Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions app/controllers/content_migrations_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ def index
OLD_START_DATE: datetime_string(@context.start_at, :verbose),
OLD_END_DATE: datetime_string(@context.conclude_at, :verbose),
SHOW_SELECT: should_show_course_copy_dropdown,
COPY_COURSE_INTEGRATION_INFO: Account.site_admin.feature_enabled?(:course_copy_allow_copying_integration_info),
MISSING_POLICY_ENABLED: @context.late_policy&.missing_submission_deduction_enabled || false
})
set_tutorial_js_env
Expand Down Expand Up @@ -212,6 +213,7 @@ def index
BLUEPRINT_ELIGIBLE_IMPORT: MasterCourses::MasterTemplate.blueprint_eligible?(@context),
SHOW_BP_SETTINGS_IMPORT_OPTION: MasterCourses::MasterTemplate.blueprint_eligible?(@context) &&
@context.account.grants_all_rights?(@current_user, session, :manage_courses_admin, :manage_master_courses),
COPY_COURSE_INTEGRATION_INFO: Account.site_admin.feature_enabled?(:course_copy_allow_copying_integration_info),
MISSING_POLICY_ENABLED: @context.late_policy&.missing_submission_deduction_enabled || false
})
set_tutorial_js_env
Expand Down Expand Up @@ -341,6 +343,10 @@ def migration_plugin_supported?(plugin)
# from the source course or package. The destination course must not be associated
# with an existing blueprint course and cannot have any student or observer enrollments.
#
# @argument settings[copy_integration_info] [Boolean]
# Whether to copy integration_id and integration_data values from
# source assignments to destination assignments during a course copy.
#
# @argument date_shift_options[shift_dates] [Boolean]
# Whether to shift dates in the copied course
#
Expand Down
4 changes: 3 additions & 1 deletion app/controllers/courses_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2984,7 +2984,8 @@ def copy
NEW_QUIZZES_MIGRATION: new_quizzes_migration_enabled?,
NEW_QUIZZES_MIGRATION_DEFAULT: new_quizzes_migration_default,
NEW_QUIZZES_MIGRATION_REQUIRED: new_quizzes_require_migration?,
NEW_QUIZZES_UNATTACHED_BANK_MIGRATIONS: new_quizzes_unattached_bank_migrations_enabled?
NEW_QUIZZES_UNATTACHED_BANK_MIGRATIONS: new_quizzes_unattached_bank_migrations_enabled?,
COPY_COURSE_INTEGRATION_INFO: Account.site_admin.feature_enabled?(:course_copy_allow_copying_integration_info)
})
end

Expand Down Expand Up @@ -3045,6 +3046,7 @@ def copy_course
@content_migration.migration_settings[:source_course_id] = @context.id
@content_migration.migration_settings[:import_quizzes_next] = true if params.dig(:settings, :import_quizzes_next)
@content_migration.migration_settings[:import_blueprint_settings] = true if params.dig(:settings, :import_blueprint_settings)
@content_migration.migration_settings[:copy_integration_info] = true if params.dig(:settings, :copy_integration_info)
@content_migration.workflow_state = "created"
if (adjust_dates = params[:adjust_dates]) && Canvas::Plugin.value_to_boolean(adjust_dates[:enabled])
params[:date_shift_options][adjust_dates[:operation]] = "1"
Expand Down
4 changes: 4 additions & 0 deletions app/models/content_migration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -713,6 +713,10 @@ def import_quizzes_next?
Canvas::Plugin.value_to_boolean(migration_settings[:import_quizzes_next])
end

def copy_integration_info?
Canvas::Plugin.value_to_boolean(migration_settings[:copy_integration_info])
end

def quizzes_next_migration?
context.instance_of?(Course) &&
context.feature_enabled?(:quizzes_next) &&
Expand Down
5 changes: 5 additions & 0 deletions app/models/importers/assignment_importer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,11 @@ def self.import_from_migration(hash, context, migration, item = nil, quiz = nil)
end
end

if migration.copy_integration_info?
item.integration_id = hash[:integration_id]
item.integration_data = hash[:integration_data]
end

[:turnitin_enabled, :vericite_enabled].each do |prop|
if !hash[prop].nil? && context.send(:"#{prop}?")
item.send(:"#{prop}=", hash[prop])
Expand Down
11 changes: 11 additions & 0 deletions config/feature_flags/00_standard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@ autodetect_field_separators_for_gradebook_exports:
exports based on the number format for your language.
applies_to: User
custom_transition_proc: autodetect_field_separators_for_gradebook_exports_custom_transition_hook
course_copy_allow_copying_integration_info:
applies_to: SiteAdmin
state: hidden
display_name: "Course Copy: allow copying integration_id and integration_data"
description: Adds opt-in settings to copy integration_id and integration_data
on assignments during course copy.
environments:
ci:
state: allowed_on
development:
state: allowed_on
common_cartridge_page_conversion:
type: setting
state: hidden
Expand Down
4 changes: 3 additions & 1 deletion lib/cc/assignment_resources.rb
Original file line number Diff line number Diff line change
Expand Up @@ -272,10 +272,12 @@ def self.create_canvas_assignment(node, assignment, manifest = nil)
graders_anonymous_to_graders
grader_names_visible_to_final_grader
anonymous_instructor_annotations
allowed_attempts]
allowed_attempts
integration_id]
atts.each do |att|
node.tag!(att, assignment.send(att)) if assignment.send(att) == false || assignment.send(att).present?
end
node.tag!(:integration_data, assignment.integration_data.to_json) if assignment.integration_data.present?
if assignment.external_tool_tag
if (content = assignment.external_tool_tag.content) && content.is_a?(ContextExternalTool)
if content.context == assignment.context
Expand Down
7 changes: 6 additions & 1 deletion lib/cc/importer/standard/assignment_converter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -147,10 +147,15 @@ def parse_canvas_assignment_data(meta_doc, html_doc = nil, assignment = {})
external_tool_data_json
external_tool_link_settings_json
turnitin_settings
time_zone_edited].each do |string_type|
time_zone_edited
integration_id].each do |string_type|
val = get_node_val(meta_doc, string_type)
assignment[string_type] = val unless val.nil?
end
integration_data_val = get_node_val(meta_doc, "integration_data")
if integration_data_val.present?
assignment["integration_data"] = JSON.parse(integration_data_val)
end
%w[turnitin_enabled
vericite_enabled
peer_reviews
Expand Down
45 changes: 45 additions & 0 deletions spec/models/content_migration/course_copy_assignments_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1199,5 +1199,50 @@
expect(a_to).to be_valid
end
end

context "integration info copying" do
it "copies integration_id and integration_data when copy_integration_info is enabled" do
assignment_model(course: @copy_from, points_possible: 10, submission_types: "online_text_entry")
@assignment.update!(integration_id: "ext-system-42", integration_data: { "sis_source" => "ABC", "vendor_id" => 99 })

@cm.migration_settings[:copy_integration_info] = true
@cm.save!

run_course_copy

a_to = @copy_to.assignments.find_by(migration_id: mig_id(@assignment))
expect(a_to.integration_id).to eq "ext-system-42"
expect(a_to.integration_data).to eq({ "sis_source" => "ABC", "vendor_id" => 99 })
end

it "does not copy integration_id or integration_data when copy_integration_info is not enabled" do
assignment_model(course: @copy_from, points_possible: 10, submission_types: "online_text_entry")
@assignment.update!(integration_id: "ext-system-42", integration_data: { "sis_source" => "ABC", "vendor_id" => 99 })

run_course_copy

a_to = @copy_to.assignments.find_by(migration_id: mig_id(@assignment))
expect(a_to.integration_id).to be_nil
expect(a_to.integration_data).to be_nil

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this assertion is failing with:

Failure/Error: expect(a_to.integration_data).to be_nil

 expected: nil
      got: {}

end

it "copies only populated fields when copy_integration_info is enabled" do
a1 = @copy_from.assignments.create!(title: "Only ID", submission_types: "online_text_entry", integration_id: "id-only")
a2 = @copy_from.assignments.create!(title: "Only Data", submission_types: "online_text_entry", integration_data: { "data" => "only" })

@cm.migration_settings[:copy_integration_info] = true
@cm.save!

run_course_copy

a1_to = @copy_to.assignments.find_by(migration_id: mig_id(a1))
expect(a1_to.integration_id).to eq "id-only"
expect(a1_to.integration_data).to be_nil

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this assertion is failing with:

Failure/Error: expect(a1_to.integration_data).to be_nil

 expected: nil
      got: {}


a2_to = @copy_to.assignments.find_by(migration_id: mig_id(a2))
expect(a2_to.integration_id).to be_nil
expect(a2_to.integration_data).to eq({ "data" => "only" })
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,7 @@ export const CourseCopyImporter = ({onSubmit, onCancel, isSubmitting}: CourseCop
canImportBPSettings={
selectedCourse && showBpSettingImport ? selectedCourse.blueprint : false
}
canCopyIntegrationInfo={!!ENV.COPY_COURSE_INTEGRATION_INFO}
oldStartDate={parseDateToISOString(oldStartDate)}
oldEndDate={parseDateToISOString(oldEndDate)}
newStartDate={parseDateToISOString(newStartDate)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ export const CopyCourseForm = ({
canAdjustDates={true}
canSelectContent={true}
canImportBPSettings={canImportBpSettings}
canCopyIntegrationInfo={!!ENV.COPY_COURSE_INTEGRATION_INFO}
canImportAsNewQuizzes={canImportAsNewQuizzes}
newStartDate={isoNewCourseStartDate}
newEndDate={isoNewCourseEndDate}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ type CommonMigratorControlsProps = {
canOverwriteAssessmentContent?: boolean
canAdjustDates?: boolean
canImportBPSettings?: boolean
canCopyIntegrationInfo?: boolean
onSubmit: onSubmitMigrationFormCallback
onCancel: () => void
fileUploadProgress: number | null
Expand Down Expand Up @@ -129,6 +130,7 @@ export const CommonMigratorControls = ({
canOverwriteAssessmentContent = false,
canAdjustDates = false,
canImportBPSettings = false,
canCopyIntegrationInfo = false,
onSubmit,
onCancel,
isSubmitting,
Expand All @@ -149,6 +151,7 @@ export const CommonMigratorControls = ({
!!ENV.NEW_QUIZZES_MIGRATION_DEFAULT,
)
const [overwriteAssessmentContent, setOverwriteAssessmentContent] = useState<boolean>(false)
const [copyIntegrationInfo, setCopyIntegrationInfo] = useState<boolean>(false)
const [showAdjustDates, setShowAdjustDates] = useState<boolean>(false)
const [dateAdjustmentConfig, setDateAdjustmentConfig] = useState<DateAdjustmentConfig>({
adjust_dates: {
Expand Down Expand Up @@ -199,6 +202,7 @@ export const CommonMigratorControls = ({
}
canImportAsNewQuizzes && (data.settings.import_quizzes_next = importAsNewQuizzes)
canOverwriteAssessmentContent && (data.settings.overwrite_quizzes = overwriteAssessmentContent)
canCopyIntegrationInfo && (data.settings.copy_integration_info = copyIntegrationInfo)
onSubmit(data)
}, [
selectiveImport,
Expand All @@ -211,6 +215,8 @@ export const CommonMigratorControls = ({
importAsNewQuizzes,
canOverwriteAssessmentContent,
overwriteAssessmentContent,
canCopyIntegrationInfo,
copyIntegrationInfo,
onSubmit,
])

Expand Down Expand Up @@ -265,6 +271,20 @@ export const CommonMigratorControls = ({
/>,
]
: []),
...(canCopyIntegrationInfo
? [
<Checkbox
key="copy_integration_info"
name="copy_integration_info"
value="copy_integration_info"
disabled={isSubmitting}
label={I18n.t('Copy assignment integration IDs and data')}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setCopyIntegrationInfo(e.target.checked)
}
/>,
]
: []),
]

const allContentText = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,20 @@ describe('CommonMigratorControls', () => {
)
})

it('calls onSubmit with copy_integration_info', async () => {
renderComponent({canCopyIntegrationInfo: true})
await userEvent.click(
screen.getByRole('checkbox', {name: 'Copy assignment integration IDs and data'}),
)
await userEvent.click(screen.getByRole('button', {name: 'Add to Import Queue'}))

expect(onSubmit).toHaveBeenCalledWith(
expect.objectContaining({
settings: expect.objectContaining({copy_integration_info: true}),
}),
)
})

it('calls onSubmit with all data', async () => {
renderComponent({
canSelectContent: true,
Expand Down
1 change: 1 addition & 0 deletions ui/shared/global/env/ContentMigrations.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export interface EnvContentMigrations {
NEW_QUIZZES_UNATTACHED_BANK_MIGRATIONS?: boolean
EXPORT_WARNINGS?: string[]
SHOW_BP_SETTINGS_IMPORT_OPTION?: boolean
COPY_COURSE_INTEGRATION_INFO?: boolean
SHOW_SELECT?: boolean
OLD_START_DATE?: string
OLD_END_DATE?: string
Expand Down