Class SyncCourseWithPlRepoJob

java.lang.Object
edu.ucsb.cs.scaffold.jobs.SyncCourseWithPlRepoJob
All Implemented Interfaces:
edu.ucsb.cs156.jobs.services.JobContextConsumer

public class SyncCourseWithPlRepoJob extends Object implements edu.ucsb.cs156.jobs.services.JobContextConsumer
Syncs one course's PrairieLearn state (issue #69), replacing the repo-wide SyncPlRepoJob. Takes a course (rather than a PlRepo id) and uses the launching user's GitHub and PrairieLearn PATs.

Before doing any work, the job verifies that the user has both PATs, that the course is associated with a GitHub repo and a PrairieLearn course instance, and that the PATs can actually reach both — read/write access to the repo, and access to the course instance via the PrairieLearn API. Any failure terminates the job with a log message telling the user where to fix it (the /profile page for PATs, the PrairieLearn tab of the course settings for the associations).

Unlike the old job, the PlInstance table is not repopulated from the repo's courseInstances directory: the course's instance already exists, and its shortName/longName are just sanity-checked (and corrected) against what PrairieLearn reports. Assessments are synced only for the course's own instance. Questions are still traversed for the whole repo, exactly as before: the questions directory is walked recursively; a directory containing an info.json is a question whose questionId is its path relative to questions; __drafts__ directories are skipped; question directories are not traversed further; stale PlQuestion rows are deleted (cascading to their PlScaffoldAssessments and join rows).

Assessments: each subdirectory of courseInstances/<instance>/assessments containing an infoAssessment.json becomes a PlAssessment; the zones key is walked recursively and every "id" entry links the assessment to a PlQuestion of the repo (the PlAssessmentQuestion join table, in zone order, rewritten on change). Stale rows are deleted.

Finally the job asks the PrairieLearn API for the instance's assessments and copies the fields from issue #71 (numeric id, number, order, title, and the assessment-set abbreviation/number/heading/color) onto the matching PlAssessment rows, matched by name.

If the questions or per-instance assessments directory is missing (HTTP 404), that step is skipped entirely — including deletions — because a 404 cannot distinguish "directory removed" from "token cannot see the repo", and mass-deleting rows over a token problem would be wrong.

  • Constructor Details

    • SyncCourseWithPlRepoJob

      public SyncCourseWithPlRepoJob()
  • Method Details

    • getScopeType

      public String getScopeType()
      Specified by:
      getScopeType in interface edu.ucsb.cs156.jobs.services.JobContextConsumer
    • getScopeId

      public Long getScopeId()
      Specified by:
      getScopeId in interface edu.ucsb.cs156.jobs.services.JobContextConsumer
    • accept

      public void accept(edu.ucsb.cs156.jobs.services.JobContext ctx) throws Exception
      Specified by:
      accept in interface edu.ucsb.cs156.jobs.services.JobContextConsumer
      Throws:
      Exception