PR7b — feat(marketplace): preview attempt (Phase 2)#8511
Conversation
562e8a5 to
d9d825a
Compare
| render partial: 'jobs/submitted', locals: { job: job } | ||
| end | ||
|
|
||
| def generate_live_feedback # rubocop:disable Metrics/AbcSize, Metrics/MethodLength |
There was a problem hiding this comment.
[Correctable] Lint/RedundantCopDisableDirective: Unnecessary disabling of Metrics/MethodLength.
| # frozen_string_literal: true | ||
| json.submission do | ||
| json.partial! 'course/assessment/submission/submissions/attempt', attempt: preview_attempt, assessment: assessment, | ||
| can_grade: can_grade, can_update: can_update |
There was a problem hiding this comment.
[Correctable] Layout/HashAlignment: Align the keys of a hash literal if they span more than one line.
| json.partial! 'course/assessment/submission/submissions/answers', submission: @submission, answers: answers | ||
| json.partial! 'course/assessment/submission/submissions/topics', submission: @submission, | ||
| submission_questions: submission_questions, | ||
| can_grade: can_grade |
There was a problem hiding this comment.
[Correctable] Layout/HashAlignment: Align the keys of a hash literal if they span more than one line.
| answers: answers | ||
| json.partial! 'course/assessment/submission/submissions/answers', submission: @submission, answers: answers | ||
| json.partial! 'course/assessment/submission/submissions/topics', submission: @submission, | ||
| submission_questions: submission_questions, |
There was a problem hiding this comment.
[Correctable] Layout/HashAlignment: Align the keys of a hash literal if they span more than one line.
| json.partial! 'course/assessment/submission/submissions/questions', assessment: @assessment, submission: @submission, | ||
| can_grade: can_grade, | ||
| submission_questions: submission_questions, | ||
| answers: answers |
There was a problem hiding this comment.
[Correctable] Layout/HashAlignment: Align the keys of a hash literal if they span more than one line.
|
|
||
| json.partial! 'course/assessment/submission/submissions/questions', assessment: @assessment, submission: @submission, | ||
| can_grade: can_grade, | ||
| submission_questions: submission_questions, |
There was a problem hiding this comment.
[Correctable] Layout/HashAlignment: Align the keys of a hash literal if they span more than one line.
| where(question: @submission.questions).includes({ discussion_topic: :posts }) | ||
|
|
||
| json.partial! 'course/assessment/submission/submissions/questions', assessment: @assessment, submission: @submission, | ||
| can_grade: can_grade, |
There was a problem hiding this comment.
[Correctable] Layout/HashAlignment: Align the keys of a hash literal if they span more than one line.
68546f0 to
b1b31c1
Compare
d9d825a to
f850512
Compare
Design-C marketplace preview groundwork, no schema change: - Attempt#preview? (true when the attempt has no Submission extension row) — the single source of truth for preview-only branching. - Attempt#reset_attempt! — destroys answers, returns to attempting, rebuilds answers (backs the preview 'Reset attempt' action). - Course::Assessment::PreviewAttemptReapingJob (TTL 7d) + daily schedule — deletes only extension-less previews past TTL; real submissions never reaped (mutation-verified). - validate_unique_submission left unchanged: the DB unique index already forbids two attempts per (assessment, creator); normal preview creation hits no prior attempt, and the unscoped rule yields the friendly collision error create-or-reuse relies on. Plan: docs/superpowers/plans/2026-07-23-marketplace-preview-increment-a-lifecycle.md
…review serving Increment B foundation: an Attempt must stand in as @submission when serving a marketplace preview, but the shared submission jbuilders call course_user/current_points_awarded/ experience_points_record/publisher on the served object — the EXP/course-coupled slice the extension owns. Delegate those to the (optional) extension with allow_nil, so a preview (no extension) returns nil and a real submission returns the extension's values. Exercised only by previews; real submissions serve via the extension directly. Interface set audited against app/views/course/assessment/submission/submissions/*.jbuilder.
…, jbuilders Increment B: PreviewAttemptsController serves marketplace preview attempts by reusing the platform submission edit/update pipeline, treating a bare Course::Assessment::Attempt (no Submission extension) as @submission. Covers create/edit/update/auto_grade/reset (core routes); live-feedback/scribing actions are authored here (single-file authoring) but wired up by a later task. PreviewUpdateService subclasses Submission::UpdateService to drop the EXP-only draft_points_awarded/points_awarded params an Attempt has no columns for, and to build SubmissionQuestion rows against the Attempt directly (the parent assumes a Submission extension with its own #attempt association). Also covers a repo-wide deferred-workflow-state-persistence gotcha in the new spec: a bare `attempt.finalise!` only transitions workflow_state in memory (lib/extensions/ deferred_workflow_state_persistence) and needs an explicit save to be visible to a subsequent reload/re-find, same as Submission#finalise! already does internally.
…nal call; scope preview loading to previews
…ubmission -> gradable.submission) The dual-typed param (Attempt in production, Submission in legacy specs) read as submission.submission when resolving the extension. Rename to `gradable` so the extension access reads gradable.submission. Behavior-preserving.
The preview reuses the submission edit UI, whose per-answer autosave and per-question submit hit dedicated answer endpoints. Add the preview equivalents so saving/submitting an answer in a preview no longer 404s on the platform /assessments/:aid/submissions/... route. - New shallow routes + #save_draft / #submit_answer actions on the preview attempts controller, reusing the platform answer write path (UpdateAnswerConcern) and the extracted SubmitAnswerConcern. - Extract the submit auto-grade helpers from AnswersController into Course::Assessment::Answer::SubmitAnswerConcern (renamed auto_grade -> auto_grade_answer to avoid colliding with the preview controller's whole-attempt #auto_grade action). - Grant :save_draft/:submit_answer on a preview-owned Attempt.
b1b31c1 to
7afa40f
Compare
f850512 to
3900460
Compare
PR7b — Marketplace preview attempt (Phase 2)
Stacked on #8510 (
pr7a-attempt-base-record). Adds the marketplace "Try it out" preview feature on the base-record foundation from PR7a.A preview is a bare
Attemptwith noSubmissionextension row (Attempt.previews == where.missing(:submission)) — nocourse_user, no EXP, throwaway. Eligible users rehearse a published assessment interactively (answer → submit → auto-grade → view-as-grader) without creating a real submission, joining a course, or earning EXP.What's in it
Attempt#preview?,#reset_attempt!, TTL reaping job (Increment A)Marketplace::PreviewAttemptsController(create-or-reuse keyed onAttempt.previews; edit / update / auto_grade / reset + live-feedback / scribing) reusing the platform submission pipeline with theAttemptstanding in as@submission;PreviewUpdateService, courselessPreviewAutoGradingService, preview jbuilders (+ shared_attemptpartial extracted from_submission)preview? && creator_id == user.idabilities; published-listing gate on create (:preview_in_marketplace);(assessment, creator)collision → clean 409Notable fixes surfaced during this work
Attempt(points_awarded=lives only on the extension) — affected real and preview autograded finalise; now extension-aware + preview-safe (Submission::AutoGradingService).Testing
All backend specs green (consolidated sweep: 92 examples, 0 failures, 11 pending). Every task independently reviewed; final whole-branch review passed after the two hardening fixes above.
Not yet included (next increment): the frontend (~10 ported files) and the launch→answer→grade feature/Capybara specs.