improve logic for cancel, save, publish, [save and publish]
flag=discussion_create fixes VICE-3811 test plan: Announcement Create - default: Cancel, Publish - check delay posting, leve date blank, (must show cancel, publish) - now set available from date to future, (must show cancel, save) - set available from date to the past, (must show cancel, publish) - uncheck delay posting, (must show cancel, publish) Discussion Create - as student, must show cancel, save (save publishes the discussion) - as a teacher, must show cancel, save and publish, save - - save must save as unpublished - - save and publish must save as published - - save with an available from date in the future must save as unpublished - - save and publish with an available from date in tge future must save as workflow_state: post_delayed Discussion Edit - you only see cancel and save buttons for published discussions - teachers see cancel, save and publish, and save for unpublished discussions - teachers only see cancel and save for published discussions Discussions/Announcements any state - cancel sends you to the place you came from Change-Id: I57945b78afd26f5024351c7bd0b303cd2027a80b Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/330478 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> QA-Review: Jason Gillett <jason.gillett@instructure.com> Reviewed-by: Drake Harper <drake.harper@instructure.com> Product-Review: Caleb Guanzon <cguanzon@instructure.com>
This commit is contained in:
parent
834df61a01
commit
77d748906e
|
@ -60,7 +60,8 @@ class Mutations::DiscussionBase < Mutations::BaseMutation
|
|||
discussion_topic.lock_at = lock_at if lock_at
|
||||
|
||||
if discussion_topic.delayed_post_at_changed? || discussion_topic.lock_at_changed?
|
||||
discussion_topic.workflow_state = discussion_topic.should_not_post_yet ? "post_delayed" : discussion_topic.workflow_state
|
||||
# only apply post_delayed if the topic is set to published
|
||||
discussion_topic.workflow_state = (discussion_topic.should_not_post_yet && discussion_topic.workflow_state == "active") ? "post_delayed" : discussion_topic.workflow_state
|
||||
if discussion_topic.should_lock_yet
|
||||
discussion_topic.lock(without_save: true)
|
||||
else
|
||||
|
|
|
@ -642,7 +642,7 @@ describe Mutations::CreateDiscussionTopic do
|
|||
end
|
||||
|
||||
context "delayed_post_at and lock_at" do
|
||||
it "successfully creates a discussion topic with delayed_post_at and lock_at" do
|
||||
it "successfully creates an unpublished discussion topic with delayed_post_at and lock_at" do
|
||||
context_type = "Course"
|
||||
title = "Delayed Topic"
|
||||
message = "Lorem ipsum..."
|
||||
|
@ -666,6 +666,37 @@ describe Mutations::CreateDiscussionTopic do
|
|||
result = execute_with_input(query)
|
||||
discussion_topic = result.dig("data", "createDiscussionTopic", "discussionTopic")
|
||||
|
||||
expect(result["errors"]).to be_nil
|
||||
expect(result.dig("data", "discussionTopic", "errors")).to be_nil
|
||||
expect(discussion_topic["delayedPostAt"]).to eq delayed_post_at
|
||||
expect(discussion_topic["lockAt"]).to eq lock_at
|
||||
expect(DiscussionTopic.last.workflow_state).to eq "unpublished"
|
||||
end
|
||||
|
||||
it "coerces a created published discussion into post_delayed if delayed_post_at is in the future" do
|
||||
context_type = "Course"
|
||||
title = "Delayed Topic"
|
||||
message = "Lorem ipsum..."
|
||||
published = true
|
||||
require_initial_post = true
|
||||
delayed_post_at = 5.days.from_now.iso8601
|
||||
lock_at = 10.days.from_now.iso8601
|
||||
|
||||
query = <<~GQL
|
||||
contextId: "#{@course.id}"
|
||||
contextType: "#{context_type}"
|
||||
title: "#{title}"
|
||||
message: "#{message}"
|
||||
published: #{published}
|
||||
requireInitialPost: #{require_initial_post}
|
||||
anonymousState: "off"
|
||||
delayedPostAt: "#{delayed_post_at}"
|
||||
lockAt: "#{lock_at}"
|
||||
GQL
|
||||
|
||||
result = execute_with_input(query)
|
||||
discussion_topic = result.dig("data", "createDiscussionTopic", "discussionTopic")
|
||||
|
||||
expect(result["errors"]).to be_nil
|
||||
expect(result.dig("data", "discussionTopic", "errors")).to be_nil
|
||||
expect(discussion_topic["delayedPostAt"]).to eq delayed_post_at
|
||||
|
|
|
@ -443,7 +443,7 @@ describe "discussions" do
|
|||
get "/courses/#{course.id}/discussion_topics/new"
|
||||
f("input[placeholder='Topic Title']").send_keys "This is fully anonymous"
|
||||
force_click("input[value='full_anonymity']")
|
||||
f("button[data-testid='save-and-publish-button']").click
|
||||
f("button[data-testid='save-button']").click
|
||||
wait_for_ajaximations
|
||||
expect(f("span[data-testid='anon-conversation']").text).to eq "This is an anonymous Discussion, Your name and profile picture will be hidden from other course members."
|
||||
expect(f("span[data-testid='author_name']").text).to include "Anonymous"
|
||||
|
@ -455,7 +455,7 @@ describe "discussions" do
|
|||
get "/courses/#{course.id}/discussion_topics/new"
|
||||
f("input[placeholder='Topic Title']").send_keys "This is partially anonymous"
|
||||
force_click("input[value='partial_anonymity']")
|
||||
f("button[data-testid='save-and-publish-button']").click
|
||||
f("button[data-testid='save-button']").click
|
||||
wait_for_ajaximations
|
||||
expect(f("span[data-testid='anon-conversation']").text).to eq "When creating a reply, you will have the option to show your name and profile picture to other course members or remain anonymous."
|
||||
expect(f("span[data-testid='author_name']").text).to include "Anonymous"
|
||||
|
@ -473,7 +473,7 @@ describe "discussions" do
|
|||
force_click("input[value='Anonymous']")
|
||||
fj("li:contains('student')").click
|
||||
|
||||
f("button[data-testid='save-and-publish-button']").click
|
||||
f("button[data-testid='save-button']").click
|
||||
wait_for_ajaximations
|
||||
expect(f("span[data-testid='anon-conversation']").text).to eq "When creating a reply, you will have the option to show your name and profile picture to other course members or remain anonymous."
|
||||
expect(f("span[data-testid='author_name']").text).to include "student"
|
||||
|
@ -494,7 +494,7 @@ describe "discussions" do
|
|||
force_click("input[value='student']")
|
||||
fj("li:contains('Anonymous')").click
|
||||
|
||||
f("button[data-testid='save-and-publish-button']").click
|
||||
f("button[data-testid='save-button']").click
|
||||
wait_for_ajaximations
|
||||
expect(f("span[data-testid='anon-conversation']").text).to eq "When creating a reply, you will have the option to show your name and profile picture to other course members or remain anonymous."
|
||||
expect(f("span[data-testid='author_name']").text).to include "Anonymous"
|
||||
|
|
|
@ -58,7 +58,7 @@ export default function DiscussionTopicForm({
|
|||
const isUnpublishedAnnouncement =
|
||||
isAnnouncement && !ENV.DISCUSSION_TOPIC?.ATTRIBUTES.course_published
|
||||
const isEditingAnnouncement = isAnnouncement && ENV.DISCUSSION_TOPIC?.ATTRIBUTES.id
|
||||
|
||||
const published = currentDiscussionTopic?.published ?? false
|
||||
const announcementAlertProps = () => {
|
||||
if (isUnpublishedAnnouncement) {
|
||||
return {
|
||||
|
@ -116,6 +116,7 @@ export default function DiscussionTopicForm({
|
|||
|
||||
const [availableFrom, setAvailableFrom] = useState(null)
|
||||
const [availableUntil, setAvailableUntil] = useState(null)
|
||||
const [willAnnouncementPostRightAway, setWillAnnouncementPostRightAway] = useState(true)
|
||||
const [availabiltyValidationMessages, setAvailabilityValidationMessages] = useState([
|
||||
{text: '', type: 'success'},
|
||||
])
|
||||
|
@ -129,7 +130,6 @@ export default function DiscussionTopicForm({
|
|||
const [peerReviewDueDate, setPeerReviewDueDate] = useState('')
|
||||
const [assignTo, setAssignTo] = useState('')
|
||||
const [dueDate, setDueDate] = useState('')
|
||||
|
||||
const [showGroupCategoryModal, setShowGroupCategoryModal] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -159,9 +159,18 @@ export default function DiscussionTopicForm({
|
|||
setAvailableUntil(currentDiscussionTopic.lockAt)
|
||||
setDelayPosting(!!currentDiscussionTopic.delayedPostAt && isAnnouncement)
|
||||
setLocked(currentDiscussionTopic.locked && isAnnouncement)
|
||||
|
||||
}, [isEditing, currentDiscussionTopic, discussionAnonymousState, isAnnouncement])
|
||||
|
||||
useEffect(() => {
|
||||
if (delayPosting) {
|
||||
const rightNow = new Date()
|
||||
const availableFromIntoDate = new Date(availableFrom)
|
||||
setWillAnnouncementPostRightAway(availableFromIntoDate <= rightNow)
|
||||
} else {
|
||||
setWillAnnouncementPostRightAway(true)
|
||||
}
|
||||
}, [availableFrom, delayPosting])
|
||||
|
||||
const validateTitle = newTitle => {
|
||||
if (newTitle.length > 255) {
|
||||
setTitleValidationMessages([
|
||||
|
@ -635,28 +644,54 @@ export default function DiscussionTopicForm({
|
|||
margin="xx-large none"
|
||||
padding="large none"
|
||||
>
|
||||
<Button type="button" color="secondary">
|
||||
<Button
|
||||
type="button"
|
||||
color="secondary"
|
||||
onClick={() => {
|
||||
window.location.assign(ENV.CANCEL_TO)
|
||||
}}
|
||||
>
|
||||
{I18n.t('Cancel')}
|
||||
</Button>
|
||||
<Button
|
||||
type="submit"
|
||||
onClick={() => submitForm(true)}
|
||||
color="secondary"
|
||||
margin="xxx-small"
|
||||
data-testid="save-and-publish-button"
|
||||
>
|
||||
{I18n.t('Save and Publish')}
|
||||
</Button>
|
||||
<Button
|
||||
type="submit"
|
||||
data-testid="save-button"
|
||||
onClick={() =>
|
||||
submitForm(currentDiscussionTopic ? currentDiscussionTopic.published : false)
|
||||
}
|
||||
color="primary"
|
||||
>
|
||||
{I18n.t('Save')}
|
||||
</Button>
|
||||
{/* discussion moderators viewing a new or still unpublished discussion */}
|
||||
{!isAnnouncement && ENV.DISCUSSION_TOPIC?.PERMISSIONS?.CAN_MODERATE && !published && (
|
||||
<Button
|
||||
type="submit"
|
||||
onClick={() => submitForm(true)}
|
||||
color="secondary"
|
||||
margin="xxx-small"
|
||||
data-testid="save-and-publish-button"
|
||||
>
|
||||
{I18n.t('Save and Publish')}
|
||||
</Button>
|
||||
)}
|
||||
{/* for announcements, show publish when the available until da */}
|
||||
{isAnnouncement ? (
|
||||
<Button
|
||||
type="submit"
|
||||
// we always process announcements as published.
|
||||
onClick={() => submitForm(true)}
|
||||
color="primary"
|
||||
margin="xxx-small"
|
||||
data-testid="announcement-submit-button"
|
||||
>
|
||||
{willAnnouncementPostRightAway ? I18n.t('Publish') : I18n.t('Save')}
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
type="submit"
|
||||
data-testid="save-button"
|
||||
// when editing, use the current published state, otherwise:
|
||||
// students will always save as published while for moderators in this case they
|
||||
// can save as unpublished
|
||||
onClick={() =>
|
||||
submitForm(isEditing ? published : !ENV.DISCUSSION_TOPIC?.PERMISSIONS?.CAN_MODERATE)
|
||||
}
|
||||
color="primary"
|
||||
>
|
||||
{I18n.t('Save')}
|
||||
</Button>
|
||||
)}
|
||||
</View>
|
||||
</FormFieldGroup>
|
||||
</>
|
||||
|
|
Loading…
Reference in New Issue