Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add rake tasks to un/archive a course #6342

Open
wants to merge 18 commits into
base: master
Choose a base branch
from

Conversation

mishaschwartz
Copy link
Contributor

@mishaschwartz mishaschwartz commented Nov 16, 2022

Motivation and Context

This PR adds several rake tasks to archive, unarchive, and delete a course and all its content. The relevant tasks are:

  • markus:archive:course
  • markus:unarchive:course
  • markus:remove:course

The following rake tasks were also moved:

  • markus:archive -> markus:archive:files
  • markus:unarchive -> markus:unarchive:files

The archive task works by copying the database content for all records associated with a course to csv files (one per table) and all files on disk associated with the course as is. These files are saved as a tar.gz archive on disk.

The remove task works by deleting the records associated with the course from the database and deleting all files on disk associated with the course.

The unarchive task works by copying the content of the csv files to a temporary database, running any pending migrations on the data and then copying the data from that database into the database used by the current MarkUs instance. Then the archived files are copied back to the expected location on disk. In order to ensure that there are no conflicts between identifiers the unarchive task does the following:

  • new ids are assigned to all records and the foreign keys are updated to match
  • for records that are not directly associated to the course being unarchived but may be referred to by a foreign key, the correct record to refer to is identified by inspecting the IDENTIFIER constant defined on the class. This is done because ids may have changed since the course was archived. For example, a role may refer to a user and the correct user is identified by inspecting the user_name column.

In order for archiving an entire course to work, there were a few adjustments that needed to be made to the source code as well. These include:

  • the order that test groups are displayed in the UI was determined by storing test group ids in the assignment_properties.autotest_settings field as a json string. This acted as a foreign key reference to the test_groups that should be displayed and in which order. Updating this field within the json string when the test group ids changed during unarchiving was going to be very error prone so I updated this so that the order is stored in the test_groups table instead. If a test group has a non-null tester_index then it is displayed on the Automated Testing page in ascending order as determined by the tester_index value.
  • File storage locations were often stored as constants which meant that they were assigned and frozen when the model classes were initialized. In order to copy archived files to their correct location on disk, we need to be able to dynamically (and temporarily) update the file location by updating the Settings.file_storage values. In order to do this, I moved the file storage locations out of constants and into methods that will be executed dynamically.
  • We rely on identifying which models are directly associated with a course based on whether they respond to :course. Two new models (LtiLineItem and LtiService) needed to have a has_one :course association added. Note that this is also required if we ever create a controller for either of these models since we use this same method to verify that the course in the url is correct.
  • In order to determine which order to load records into the database, we assume that there are no circular dependencies between tables (ie. a graph where nodes are tables and edges are foreign key references between tables contains no cycles). However, there was one cycle present where the peer_reviews table has a reference to results and results had an optional reference back to peer_reviews. In order to resolve this I removed the (I believe) unnecessary reference to peer_reviews from results. This change is not included in this PR and is in Remove unnecessary peer_review_id foreign key #6397 instead. Because of this, this PR requires Remove unnecessary peer_review_id foreign key #6397 to be pulled in first.

Your Changes

Description:

Type of change (select all that apply):

  • New feature (non-breaking change which adds functionality)
  • Refactoring (internal change to codebase, without changing functionality)

Testing

Questions and Comments (if applicable)

Checklist

  • I have performed a self-review of my own code.
  • I have verified that the pre-commit.ci checks have passed.
  • I have verified that the CI tests have passed.
  • I have reviewed the test coverage changes reported on Coveralls.
  • I have added tests for my changes.
  • I have updated the Changelog.md file.
  • I have made changes to the documentation and linked to that pull request below.

Pull request to make documentation changes (if applicable)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants