Update CreateDiscussionTopic to support checkpoints
refs VICE-4020 flag=discussion_checkpoints test plan: - Specs pass. - Create a graded discussion topic with checkpoints using this mutation: mutation MyMutation { createDiscussionTopic( input: { contextId: "1" contextType: Course title: "Checkpoints Test" assignment: { courseId: "1", name: "Test", forCheckpoints: true } checkpoints: [ { checkpointLabel: "reply_to_topic", pointsPossible: 10, dates: [{ type: everyone, dueAt: "2016-07-10T18:00:00-01:00" }] }, { checkpointLabel: "reply_to_entry", pointsPossible: 10, dates: [{ type: everyone, dueAt: "2016-07-15T18:00:00-01:00" }], repliesRequired: 3 } ] } ) { discussionTopic { _id } errors { attribute message } } } qa risk: low Change-Id: I750c26a5eda04eb98bdd1b7864415ef5d9c4dbab Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/337380 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Jason Gillett <jason.gillett@instructure.com> Reviewed-by: Spencer Olson <solson@instructure.com> QA-Review: Jason Gillett <jason.gillett@instructure.com> Product-Review: Omar Soto-Fortuño <omar.soto@instructure.com>
This commit is contained in:
parent
ea83d570fe
commit
f77772dedb
|
@ -63,6 +63,7 @@ class Mutations::AssignmentInputBase < GraphQL::Schema::InputObject
|
|||
argument :points_possible, Float, required: false
|
||||
argument :post_to_sis, Boolean, required: false
|
||||
argument :unlock_at, Types::DateTimeType, required: false
|
||||
argument :for_checkpoints, Boolean, required: false
|
||||
end
|
||||
|
||||
class Mutations::AssignmentCreate < Mutations::AssignmentInputBase
|
||||
|
|
|
@ -42,6 +42,7 @@ class Mutations::CreateDiscussionTopic < Mutations::DiscussionBase
|
|||
argument :context_id, ID, required: true, prepare: GraphQLHelpers.relay_or_legacy_id_prepare_func("Context")
|
||||
argument :context_type, Types::DiscussionTopicContextType, required: true
|
||||
argument :assignment, Mutations::AssignmentCreate, required: false
|
||||
argument :checkpoints, [Mutations::DiscussionCheckpoints], required: false
|
||||
|
||||
# most arguments inherited from DiscussionBase
|
||||
|
||||
|
@ -122,12 +123,32 @@ class Mutations::CreateDiscussionTopic < Mutations::DiscussionBase
|
|||
elsif working_assignment.present?
|
||||
discussion_topic.assignment = working_assignment&.[](:assignment)
|
||||
end
|
||||
|
||||
# Assignment must be present to set checkpoints
|
||||
if input[:checkpoints]&.count == DiscussionTopic::REQUIRED_CHECKPOINT_COUNT
|
||||
return validation_error(I18n.t("If checkpoints are defined, forCheckpoints: true must be provided to the discussion topic assignment.")) unless input.dig(:assignment, :for_checkpoints)
|
||||
|
||||
input[:checkpoints].each do |checkpoint|
|
||||
dates = checkpoint[:dates]&.map(&:to_object)
|
||||
|
||||
Checkpoints::DiscussionCheckpointCreatorService.call(
|
||||
discussion_topic:,
|
||||
checkpoint_label: checkpoint[:checkpoint_label],
|
||||
points_possible: checkpoint[:points_possible],
|
||||
dates:
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
discussion_topic.saved_by = :assignment if discussion_topic.assignment.present?
|
||||
return errors_for(discussion_topic) unless discussion_topic.save!
|
||||
|
||||
{ discussion_topic: }
|
||||
rescue Checkpoints::DiscussionCheckpointError => e
|
||||
raise GraphQL::ExecutionError, e.message
|
||||
rescue ActiveRecord::RecordInvalid
|
||||
errors_for(discussion_topic)
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
raise GraphQL::ExecutionError, "Not found"
|
||||
end
|
||||
|
|
|
@ -18,6 +18,46 @@
|
|||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
class Types::DiscussionCheckpointDateType < Types::BaseEnum
|
||||
graphql_name "DiscussionCheckpointDateType"
|
||||
description "Types of dates that can be set for discussion checkpoints"
|
||||
value "everyone"
|
||||
value "override"
|
||||
end
|
||||
|
||||
class Types::DiscussionCheckpointDateSetType < Types::BaseEnum
|
||||
graphql_name "DiscussionCheckpointDateSetType"
|
||||
description "Types of date set that can be set for discussion checkpoints"
|
||||
value "CourseSection"
|
||||
value "Group"
|
||||
value "ADHOC"
|
||||
end
|
||||
|
||||
class Mutations::DiscussionCheckpointDate < GraphQL::Schema::InputObject
|
||||
argument :type, Types::DiscussionCheckpointDateType, required: true
|
||||
argument :due_at, Types::DateTimeType, required: true
|
||||
argument :student_ids, [Integer], required: false
|
||||
argument :set_type, Types::DiscussionCheckpointDateSetType, required: false
|
||||
argument :set_id, Integer, required: false
|
||||
|
||||
def to_object
|
||||
{
|
||||
type: self[:type],
|
||||
due_at: self[:due_at],
|
||||
student_ids: self[:student_ids],
|
||||
set_type: self[:set_type],
|
||||
set_id: self[:set_id]
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
class Mutations::DiscussionCheckpoints < GraphQL::Schema::InputObject
|
||||
argument :checkpoint_label, String, required: true
|
||||
argument :dates, [Mutations::DiscussionCheckpointDate], required: true
|
||||
argument :points_possible, Integer, required: true
|
||||
argument :replies_required, Integer, required: false
|
||||
end
|
||||
|
||||
class Mutations::DiscussionBase < Mutations::BaseMutation
|
||||
argument :allow_rating, Boolean, required: false
|
||||
argument :delayed_post_at, Types::DateTimeType, required: false
|
||||
|
|
|
@ -34,6 +34,8 @@ class DiscussionTopic < ActiveRecord::Base
|
|||
include DuplicatingObjects
|
||||
include LockedFor
|
||||
|
||||
REQUIRED_CHECKPOINT_COUNT = 2
|
||||
|
||||
restrict_columns :content, [:title, :message]
|
||||
restrict_columns :settings, %i[require_initial_post
|
||||
discussion_type
|
||||
|
|
|
@ -18,10 +18,9 @@
|
|||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
class Checkpoints::AdhocOverrideCreatorService < ApplicationService
|
||||
require_relative "discussion_checkpoint_error"
|
||||
include Checkpoints::DateOverrider
|
||||
|
||||
class StudentIdsRequiredError < StandardError; end
|
||||
|
||||
def initialize(checkpoint:, override:)
|
||||
super()
|
||||
@checkpoint = checkpoint
|
||||
|
@ -29,7 +28,9 @@ class Checkpoints::AdhocOverrideCreatorService < ApplicationService
|
|||
end
|
||||
|
||||
def call
|
||||
desired_student_ids = @override.fetch(:student_ids) { raise StudentIdsRequiredError, "student_ids is required, but was not provided" }
|
||||
desired_student_ids = @override.fetch(:student_ids) { raise Checkpoints::StudentIdsRequiredError, "student_ids is required, but was not provided" }
|
||||
raise Checkpoints::StudentIdsRequiredError, "student_ids is required, but was not provided" if desired_student_ids.blank?
|
||||
|
||||
student_ids = @checkpoint.course.all_students.where(id: desired_student_ids).pluck(:id)
|
||||
override = build_override(assignment: @checkpoint, student_ids:)
|
||||
build_override_students(override:, student_ids:)
|
||||
|
|
|
@ -18,9 +18,6 @@
|
|||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
class Checkpoints::DateOverrideCreatorService < ApplicationService
|
||||
class SetTypeRequiredError < StandardError; end
|
||||
class SetTypeNotSupportedError < StandardError; end
|
||||
|
||||
def initialize(checkpoint:, overrides:)
|
||||
super()
|
||||
@checkpoint = checkpoint
|
||||
|
@ -29,8 +26,8 @@ class Checkpoints::DateOverrideCreatorService < ApplicationService
|
|||
|
||||
def call
|
||||
@overrides.each do |override|
|
||||
set_type = override.fetch(:set_type) { raise SetTypeRequiredError, "set_type is required, but was not provided" }
|
||||
service = services.fetch(set_type) { |key| raise SetTypeNotSupportedError, "set_type of '#{key}' not supported. Supported types: #{services.keys}" }
|
||||
set_type = override.fetch(:set_type) { raise Checkpoints::SetTypeRequiredError, "set_type is required, but was not provided" }
|
||||
service = services.fetch(set_type) { |key| raise Checkpoints::SetTypeNotSupportedError, "set_type of '#{key}' not supported. Supported types: #{services.keys}" }
|
||||
service.call(checkpoint: @checkpoint, override:)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -18,8 +18,7 @@
|
|||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
class Checkpoints::DiscussionCheckpointCreatorService < ApplicationService
|
||||
class FlagDisabledError < StandardError; end
|
||||
class DateTypeRequiredError < StandardError; end
|
||||
require_relative "discussion_checkpoint_error"
|
||||
|
||||
def initialize(discussion_topic:, checkpoint_label:, dates:, points_possible:, replies_required: 1)
|
||||
super()
|
||||
|
@ -32,8 +31,19 @@ class Checkpoints::DiscussionCheckpointCreatorService < ApplicationService
|
|||
end
|
||||
|
||||
def call
|
||||
unless @discussion_topic.root_account.feature_enabled?(:discussion_checkpoints)
|
||||
raise FlagDisabledError, "discussion_checkpoints feature flag must be enabled"
|
||||
unless @discussion_topic.context.root_account.feature_enabled?(:discussion_checkpoints)
|
||||
raise Checkpoints::FlagDisabledError, "discussion_checkpoints feature flag must be enabled"
|
||||
end
|
||||
|
||||
valid_date_types = %w[everyone override].freeze
|
||||
|
||||
@dates.each do |date|
|
||||
if date[:type].blank?
|
||||
raise Checkpoints::DateTypeRequiredError, "each date must have a type specified ('everyone' or 'override')"
|
||||
end
|
||||
unless valid_date_types.include?(date[:type])
|
||||
raise Checkpoints::InvalidDateTypeError, "invalid date type: #{date[:type]}"
|
||||
end
|
||||
end
|
||||
|
||||
checkpoint = create_checkpoint
|
||||
|
@ -127,7 +137,7 @@ class Checkpoints::DiscussionCheckpointCreatorService < ApplicationService
|
|||
|
||||
def dates_by_type(type)
|
||||
@dates.select do |date|
|
||||
date_type = date.fetch(:type) { raise DateTypeRequiredError, "each date must have a type specified ('everyone' or 'override')" }
|
||||
date_type = date.fetch(:type) { raise Checkpoints::DateTypeRequiredError, "each date must have a type specified ('everyone' or 'override')" }
|
||||
date_type == type
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
#
|
||||
# Copyright (C) 2024 - present Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
module Checkpoints
|
||||
class DiscussionCheckpointError < StandardError; end
|
||||
|
||||
class FlagDisabledError < DiscussionCheckpointError; end
|
||||
|
||||
class DateTypeRequiredError < DiscussionCheckpointError; end
|
||||
|
||||
class InvalidDateTypeError < DiscussionCheckpointError; end
|
||||
|
||||
class SetTypeRequiredError < DiscussionCheckpointError; end
|
||||
|
||||
class SetTypeNotSupportedError < DiscussionCheckpointError; end
|
||||
|
||||
class GroupAssignmentRequiredError < DiscussionCheckpointError; end
|
||||
|
||||
class SetIdRequiredError < DiscussionCheckpointError; end
|
||||
|
||||
class StudentIdsRequiredError < DiscussionCheckpointError; end
|
||||
end
|
|
@ -18,11 +18,9 @@
|
|||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
class Checkpoints::GroupOverrideCreatorService < ApplicationService
|
||||
require_relative "discussion_checkpoint_error"
|
||||
include Checkpoints::DateOverrider
|
||||
|
||||
class GroupAssignmentRequiredError < StandardError; end
|
||||
class SetIdRequiredError < StandardError; end
|
||||
|
||||
def initialize(checkpoint:, override:)
|
||||
super()
|
||||
@checkpoint = checkpoint
|
||||
|
@ -31,10 +29,10 @@ class Checkpoints::GroupOverrideCreatorService < ApplicationService
|
|||
|
||||
def call
|
||||
if @checkpoint.effective_group_category_id.nil?
|
||||
raise GroupAssignmentRequiredError, "must be a group assignment in order to create group overrides"
|
||||
raise Checkpoints::GroupAssignmentRequiredError, "must be a group assignment in order to create group overrides"
|
||||
end
|
||||
|
||||
group_id = @override.fetch(:set_id) { raise SetIdRequiredError, "set_id is required, but was not provided" }
|
||||
group_id = @override.fetch(:set_id) { raise Checkpoints::SetIdRequiredError, "set_id is required, but was not provided" }
|
||||
group = @checkpoint.course.active_groups.where(group_category_id: @checkpoint.effective_group_category_id).find(group_id)
|
||||
override = create_override(assignment: @checkpoint, group:)
|
||||
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
class Checkpoints::SectionOverrideCreatorService < ApplicationService
|
||||
include Checkpoints::DateOverrider
|
||||
|
||||
class SetIdRequiredError < StandardError; end
|
||||
|
||||
def initialize(checkpoint:, override:)
|
||||
super()
|
||||
@checkpoint = checkpoint
|
||||
|
@ -29,7 +27,9 @@ class Checkpoints::SectionOverrideCreatorService < ApplicationService
|
|||
end
|
||||
|
||||
def call
|
||||
section_id = @override.fetch(:set_id) { raise SetIdRequiredError, "set_id is required, but was not provided" }
|
||||
section_id = @override.fetch(:set_id) { raise Checkpoints::SetIdRequiredError, "set_id is required, but was not provided" }
|
||||
raise Checkpoints::SetIdRequiredError, "set_id is required, but was not provided" if section_id.blank?
|
||||
|
||||
section = @checkpoint.course.active_course_sections.find(section_id)
|
||||
override = create_override(assignment: @checkpoint, section:)
|
||||
|
||||
|
|
|
@ -1061,4 +1061,245 @@ describe Mutations::CreateDiscussionTopic do
|
|||
expect(result["data"]["createDiscussionTopic"]["errors"][0]["message"]).to eq "[[:base, \"unknown student ids: [\\\"#{@teacher.id - 1}\\\"]\"]]"
|
||||
end
|
||||
end
|
||||
|
||||
context "checkpoints" do
|
||||
before(:once) do
|
||||
@course.root_account.enable_feature!(:discussion_checkpoints)
|
||||
end
|
||||
|
||||
it "successfully creates a discussion topic with checkpoints" do
|
||||
context_type = "Course"
|
||||
title = "Graded Discussion w/Checkpoints"
|
||||
message = "Lorem ipsum..."
|
||||
published = true
|
||||
|
||||
query = <<~GQL
|
||||
contextId: "#{@course.id}"
|
||||
contextType: #{context_type}
|
||||
title: "#{title}"
|
||||
message: "#{message}"
|
||||
published: #{published}
|
||||
assignment: {
|
||||
courseId: "#{@course.id}",
|
||||
name: "#{title}",
|
||||
forCheckpoints: true
|
||||
}
|
||||
checkpoints: [
|
||||
{
|
||||
checkpointLabel: "reply_to_topic",
|
||||
pointsPossible: 10,
|
||||
dates: [{ type: everyone, dueAt: "#{5.days.from_now.iso8601}" }]
|
||||
},
|
||||
{
|
||||
checkpointLabel: "reply_to_entry",
|
||||
pointsPossible: 15,
|
||||
dates: [{ type: everyone, dueAt: "#{10.days.from_now.iso8601}" }],
|
||||
repliesRequired: 3
|
||||
}
|
||||
]
|
||||
GQL
|
||||
|
||||
result = execute_with_input_with_assignment(query)
|
||||
expect(result["errors"]).to be_nil
|
||||
end
|
||||
|
||||
it "successfully creates a discussion topic with checkpoints and CourseSection overrides" do
|
||||
section1 = add_section("M03")
|
||||
section2 = add_section("M06")
|
||||
|
||||
context_type = "Course"
|
||||
title = "Graded Discussion w/Checkpoints and CourseSection overrides"
|
||||
message = "Lorem ipsum..."
|
||||
published = true
|
||||
|
||||
reply_to_entry_due_at1 = 12.days.from_now
|
||||
reply_to_entry_due_at2 = 14.days.from_now
|
||||
|
||||
query = <<~GQL
|
||||
contextId: "#{@course.id}"
|
||||
contextType: #{context_type}
|
||||
title: "#{title}"
|
||||
message: "#{message}"
|
||||
published: #{published}
|
||||
assignment: {
|
||||
courseId: "#{@course.id}",
|
||||
name: "#{title}",
|
||||
forCheckpoints: true
|
||||
}
|
||||
checkpoints: [
|
||||
{
|
||||
checkpointLabel: "reply_to_topic",
|
||||
pointsPossible: 10,
|
||||
dates: [{ type: everyone, dueAt: "#{5.days.from_now.iso8601}" }]
|
||||
},
|
||||
{
|
||||
checkpointLabel: "reply_to_entry",
|
||||
pointsPossible: 15,
|
||||
dates: [
|
||||
{ type: everyone, dueAt: "#{10.days.from_now.iso8601}" },
|
||||
{ type: override, dueAt: "#{reply_to_entry_due_at1.iso8601}", setType: CourseSection, setId: #{section1.id} },
|
||||
{ type: override, dueAt: "#{reply_to_entry_due_at2.iso8601}", setType: CourseSection, setId: #{section2.id} }
|
||||
],
|
||||
repliesRequired: 3
|
||||
}
|
||||
]
|
||||
GQL
|
||||
|
||||
result = execute_with_input_with_assignment(query)
|
||||
expect(result["errors"]).to be_nil
|
||||
|
||||
assignment = Assignment.last
|
||||
|
||||
expect(assignment.has_sub_assignments?).to be true
|
||||
|
||||
sub_assignments = SubAssignment.where(parent_assignment_id: assignment.id)
|
||||
sub_assignment1 = sub_assignments.find_by(sub_assignment_tag: CheckpointLabels::REPLY_TO_TOPIC)
|
||||
sub_assignment2 = sub_assignments.find_by(sub_assignment_tag: CheckpointLabels::REPLY_TO_ENTRY)
|
||||
|
||||
expect(sub_assignment1.sub_assignment_tag).to eq "reply_to_topic"
|
||||
expect(sub_assignment1.points_possible).to eq 10
|
||||
expect(sub_assignment2.sub_assignment_tag).to eq "reply_to_entry"
|
||||
expect(sub_assignment2.points_possible).to eq 15
|
||||
|
||||
assignment_override1 = AssignmentOverride.find_by(assignment: sub_assignment2, set_type: "CourseSection", set_id: section1.id)
|
||||
assignment_override2 = AssignmentOverride.find_by(assignment: sub_assignment2, set_type: "CourseSection", set_id: section2.id)
|
||||
|
||||
expect(assignment_override1).to be_present
|
||||
expect(assignment_override2).to be_present
|
||||
expect(assignment_override1.due_at).to be_within(1.second).of reply_to_entry_due_at1
|
||||
expect(assignment_override2.due_at).to be_within(1.second).of reply_to_entry_due_at2
|
||||
end
|
||||
|
||||
it "successfully creates a discussion topic with checkpoints and Group overrides" do
|
||||
group = @course.groups.create!
|
||||
student_in_group = student_in_course(course: @course, active_all: true).user
|
||||
group.group_memberships.create!(user: student_in_group)
|
||||
|
||||
context_type = "Course"
|
||||
title = "Graded Discussion w/Checkpoints and Group overrides"
|
||||
message = "Lorem ipsum..."
|
||||
published = true
|
||||
|
||||
reply_to_entry_due_at = 12.days.from_now
|
||||
|
||||
query = <<~GQL
|
||||
contextId: "#{@course.id}"
|
||||
contextType: #{context_type}
|
||||
title: "#{title}"
|
||||
message: "#{message}"
|
||||
published: #{published}
|
||||
groupCategoryId: #{group.group_category.id}
|
||||
assignment: {
|
||||
courseId: "#{@course.id}",
|
||||
name: "#{title}",
|
||||
forCheckpoints: true
|
||||
}
|
||||
checkpoints: [
|
||||
{
|
||||
checkpointLabel: "reply_to_topic",
|
||||
pointsPossible: 10,
|
||||
dates: [{ type: everyone, dueAt: "#{5.days.from_now.iso8601}" }]
|
||||
},
|
||||
{
|
||||
checkpointLabel: "reply_to_entry",
|
||||
pointsPossible: 15,
|
||||
dates: [
|
||||
{ type: everyone, dueAt: "#{10.days.from_now.iso8601}" },
|
||||
{ type: override, dueAt: "#{reply_to_entry_due_at.iso8601}", setType: Group, setId: #{group.id} }
|
||||
],
|
||||
repliesRequired: 3
|
||||
}
|
||||
]
|
||||
GQL
|
||||
|
||||
result = execute_with_input_with_assignment(query)
|
||||
|
||||
expect(result["errors"]).to be_nil
|
||||
|
||||
assignment = Assignment.last
|
||||
|
||||
expect(assignment.has_sub_assignments?).to be true
|
||||
|
||||
sub_assignments = SubAssignment.where(parent_assignment_id: assignment.id)
|
||||
sub_assignment1 = sub_assignments.find_by(sub_assignment_tag: CheckpointLabels::REPLY_TO_TOPIC)
|
||||
sub_assignment2 = sub_assignments.find_by(sub_assignment_tag: CheckpointLabels::REPLY_TO_ENTRY)
|
||||
|
||||
expect(sub_assignment1.sub_assignment_tag).to eq "reply_to_topic"
|
||||
expect(sub_assignment1.points_possible).to eq 10
|
||||
expect(sub_assignment2.sub_assignment_tag).to eq "reply_to_entry"
|
||||
expect(sub_assignment2.points_possible).to eq 15
|
||||
|
||||
assignment_override = AssignmentOverride.find_by(assignment: sub_assignment2, set_type: "Group", set_id: group.id)
|
||||
|
||||
expect(assignment_override).to be_present
|
||||
expect(assignment_override.due_at).to be_within(1.second).of reply_to_entry_due_at
|
||||
end
|
||||
|
||||
it "successfully creates a discussion topic with checkpoints and AdHoc overrides" do
|
||||
student1 = student_in_course(course: @course, active_all: true).user
|
||||
student2 = student_in_course(course: @course, active_all: true).user
|
||||
|
||||
context_type = "Course"
|
||||
title = "Graded Discussion w/Checkpoints and AdHoc overrides"
|
||||
message = "Lorem ipsum..."
|
||||
published = true
|
||||
|
||||
reply_to_entry_due_at = 12.days.from_now
|
||||
|
||||
query = <<~GQL
|
||||
contextId: "#{@course.id}"
|
||||
contextType: #{context_type}
|
||||
title: "#{title}"
|
||||
message: "#{message}"
|
||||
published: #{published}
|
||||
assignment: {
|
||||
courseId: "#{@course.id}",
|
||||
name: "#{title}",
|
||||
forCheckpoints: true
|
||||
}
|
||||
checkpoints: [
|
||||
{
|
||||
checkpointLabel: "reply_to_topic",
|
||||
pointsPossible: 10,
|
||||
dates: [{ type: everyone, dueAt: "#{5.days.from_now.iso8601}" }]
|
||||
},
|
||||
{
|
||||
checkpointLabel: "reply_to_entry",
|
||||
pointsPossible: 15,
|
||||
dates: [
|
||||
{ type: everyone, dueAt: "#{10.days.from_now.iso8601}" },
|
||||
{ type: override, dueAt: "#{reply_to_entry_due_at.iso8601}", setType: ADHOC, studentIds: [#{student1.id}, #{student2.id}] }
|
||||
],
|
||||
repliesRequired: 3
|
||||
}
|
||||
]
|
||||
GQL
|
||||
|
||||
result = execute_with_input_with_assignment(query)
|
||||
expect(result["errors"]).to be_nil
|
||||
|
||||
assignment = Assignment.last
|
||||
|
||||
expect(assignment.has_sub_assignments?).to be true
|
||||
|
||||
sub_assignments = SubAssignment.where(parent_assignment_id: assignment.id)
|
||||
sub_assignment1 = sub_assignments.find_by(sub_assignment_tag: CheckpointLabels::REPLY_TO_TOPIC)
|
||||
sub_assignment2 = sub_assignments.find_by(sub_assignment_tag: CheckpointLabels::REPLY_TO_ENTRY)
|
||||
|
||||
expect(sub_assignment1.sub_assignment_tag).to eq "reply_to_topic"
|
||||
expect(sub_assignment1.points_possible).to eq 10
|
||||
expect(sub_assignment2.sub_assignment_tag).to eq "reply_to_entry"
|
||||
expect(sub_assignment2.points_possible).to eq 15
|
||||
|
||||
assignment_override = AssignmentOverride.find_by(assignment: sub_assignment2)
|
||||
|
||||
expect(assignment_override).to be_present
|
||||
expect(assignment_override.set_type).to eq "ADHOC"
|
||||
expect(assignment_override.due_at).to be_within(1.second).of reply_to_entry_due_at
|
||||
|
||||
student_ids = assignment_override.assignment_override_students.pluck(:user_id)
|
||||
|
||||
expect(student_ids).to match_array [student1.id, student2.id]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3004,8 +3004,8 @@ describe DiscussionTopic do
|
|||
|
||||
describe "checkpoints" do
|
||||
before do
|
||||
@course.root_account.enable_feature!(:discussion_checkpoints)
|
||||
@topic = DiscussionTopic.create_graded_topic!(course: @course, title: "Discussion Topic Title", user: @teacher)
|
||||
@topic.root_account.enable_feature!(:discussion_checkpoints)
|
||||
end
|
||||
|
||||
it "not in place in the topic" do
|
||||
|
|
|
@ -35,7 +35,7 @@ describe Checkpoints::AdhocOverrideCreatorService do
|
|||
override = { due_at: 2.days.from_now }
|
||||
expect do
|
||||
service.call(checkpoint: @checkpoint, override:)
|
||||
end.to raise_error(Checkpoints::AdhocOverrideCreatorService::StudentIdsRequiredError)
|
||||
end.to raise_error(Checkpoints::StudentIdsRequiredError)
|
||||
end
|
||||
|
||||
it "creates a parent adhoc override without dates set (but still overridden), if one doesn't already exist" do
|
||||
|
|
|
@ -33,14 +33,14 @@ describe Checkpoints::DateOverrideCreatorService do
|
|||
overrides = [{ type: "override", due_at: 2.days.from_now }]
|
||||
expect do
|
||||
service.call(checkpoint: @checkpoint, overrides:)
|
||||
end.to raise_error(Checkpoints::DateOverrideCreatorService::SetTypeRequiredError)
|
||||
end.to raise_error(Checkpoints::SetTypeRequiredError)
|
||||
end
|
||||
|
||||
it "raises a SetTypeNotSupportedError when a provided date has an unsupported set_type" do
|
||||
overrides = [{ type: "override", set_type: "Potato", due_at: 2.days.from_now }]
|
||||
expect do
|
||||
service.call(checkpoint: @checkpoint, overrides:)
|
||||
end.to raise_error(Checkpoints::DateOverrideCreatorService::SetTypeNotSupportedError)
|
||||
end.to raise_error(Checkpoints::SetTypeNotSupportedError)
|
||||
end
|
||||
|
||||
it "calls the SectionOverrideCreatorService to create a section override" do
|
||||
|
|
|
@ -28,7 +28,7 @@ describe Checkpoints::DiscussionCheckpointCreatorService do
|
|||
let(:service) { Checkpoints::DiscussionCheckpointCreatorService }
|
||||
|
||||
it "raises a FlagDisabledError when the checkpoints feature flag is disabled" do
|
||||
@topic.root_account.disable_feature!(:discussion_checkpoints)
|
||||
@topic.context.root_account.disable_feature!(:discussion_checkpoints)
|
||||
|
||||
expect do
|
||||
service.call(
|
||||
|
@ -37,7 +37,7 @@ describe Checkpoints::DiscussionCheckpointCreatorService do
|
|||
dates: [{ type: "everyone", due_at: 2.days.from_now }],
|
||||
points_possible: 6
|
||||
)
|
||||
end.to raise_error(Checkpoints::DiscussionCheckpointCreatorService::FlagDisabledError)
|
||||
end.to raise_error(Checkpoints::FlagDisabledError)
|
||||
end
|
||||
|
||||
it "raises a DateTypeRequiredError when a type is not specified on a date" do
|
||||
|
@ -48,7 +48,7 @@ describe Checkpoints::DiscussionCheckpointCreatorService do
|
|||
dates: [{ due_at: 2.days.from_now }],
|
||||
points_possible: 6
|
||||
)
|
||||
end.to raise_error(Checkpoints::DiscussionCheckpointCreatorService::DateTypeRequiredError)
|
||||
end.to raise_error(Checkpoints::DateTypeRequiredError)
|
||||
end
|
||||
|
||||
it "updates the reply_to_entry_required_count on the topic when creating a reply to entry checkpoint" do
|
||||
|
|
|
@ -36,14 +36,14 @@ describe Checkpoints::GroupOverrideCreatorService do
|
|||
override = { set_id: @group.id, due_at: 2.days.from_now }
|
||||
expect do
|
||||
service.call(checkpoint: @checkpoint, override:)
|
||||
end.to raise_error(Checkpoints::GroupOverrideCreatorService::GroupAssignmentRequiredError)
|
||||
end.to raise_error(Checkpoints::GroupAssignmentRequiredError)
|
||||
end
|
||||
|
||||
it "raises an error if set_id is not provided" do
|
||||
override = { due_at: 2.days.from_now }
|
||||
expect do
|
||||
service.call(checkpoint: @checkpoint, override:)
|
||||
end.to raise_error(Checkpoints::GroupOverrideCreatorService::SetIdRequiredError)
|
||||
end.to raise_error(Checkpoints::SetIdRequiredError)
|
||||
end
|
||||
|
||||
it "raises an error if provided a set_id for a soft-deleted group" do
|
||||
|
|
|
@ -34,7 +34,7 @@ describe Checkpoints::SectionOverrideCreatorService do
|
|||
override = { due_at: 2.days.from_now }
|
||||
expect do
|
||||
service.call(checkpoint: @checkpoint, override:)
|
||||
end.to raise_error(Checkpoints::SectionOverrideCreatorService::SetIdRequiredError)
|
||||
end.to raise_error(Checkpoints::SetIdRequiredError)
|
||||
end
|
||||
|
||||
it "raises an error if provided a set_id for a soft-deleted section" do
|
||||
|
|
Loading…
Reference in New Issue