• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

source-academy / backend / 18dc689a4df4836fc6967bf0f74dc252964bd175-PR-1180

08 Sep 2024 06:14PM UTC coverage: 79.088% (-15.3%) from 94.372%
18dc689a4df4836fc6967bf0f74dc252964bd175-PR-1180

Pull #1180

github

josh1248
Change appropriate routes into admin scope
Pull Request #1180: Transfer groundControl (and admin panel) from staff to admin route

7 of 12 new or added lines in 1 file covered. (58.33%)

499 existing lines in 25 files now uncovered.

2602 of 3290 relevant lines covered (79.09%)

1023.2 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

53.75
/lib/cadet_web/admin_controllers/admin_grading_controller.ex
1
defmodule CadetWeb.AdminGradingController do
2
  use CadetWeb, :controller
3
  use PhoenixSwagger
4

5
  alias Cadet.Assessments
6

7
  def index(conn, %{"group" => group} = params)
8
      when group in ["true", "false"] do
UNCOV
9
    course_reg = conn.assigns[:course_reg]
×
10

UNCOV
11
    case Assessments.submissions_by_grader_for_index(course_reg, params) do
×
12
      {:ok, view_model} ->
13
        conn
14
        |> put_status(:ok)
15
        |> put_resp_content_type("application/json")
UNCOV
16
        |> render("gradingsummaries.json", view_model)
×
17
    end
18
  end
19

20
  def index(conn, _) do
UNCOV
21
    index(conn, %{"group" => "false"})
×
22
  end
23

24
  def show(conn, %{"submissionid" => submission_id}) when is_ecto_id(submission_id) do
UNCOV
25
    case Assessments.get_answers_in_submission(submission_id) do
×
26
      {:ok, {answers, assessment}} ->
UNCOV
27
        render(conn, "show.json", answers: answers, assessment: assessment)
×
28

29
      {:error, {status, message}} ->
30
        conn
31
        |> put_status(status)
UNCOV
32
        |> text(message)
×
33
    end
34
  end
35

36
  def update(
37
        conn,
38
        %{
39
          "submissionid" => submission_id,
40
          "questionid" => question_id,
41
          "grading" => raw_grading
42
        }
43
      )
44
      when is_ecto_id(submission_id) and is_ecto_id(question_id) do
UNCOV
45
    course_reg = conn.assigns[:course_reg]
×
46

UNCOV
47
    grading = raw_grading |> snake_casify_string_keys()
×
48

UNCOV
49
    case Assessments.update_grading_info(
×
50
           %{submission_id: submission_id, question_id: question_id},
51
           grading,
52
           course_reg
53
         ) do
54
      {:ok, _} ->
UNCOV
55
        text(conn, "OK")
×
56

57
      {:error, {status, message}} ->
58
        conn
59
        |> put_status(status)
UNCOV
60
        |> text(message)
×
61
    end
62
  end
63

64
  def update(conn, _params) do
65
    conn
66
    |> put_status(:bad_request)
UNCOV
67
    |> text("Missing parameter")
×
68
  end
69

70
  def unsubmit(conn, %{"submissionid" => submission_id}) when is_ecto_id(submission_id) do
UNCOV
71
    course_reg = conn.assigns[:course_reg]
×
72

UNCOV
73
    case Assessments.unsubmit_submission(submission_id, course_reg) do
×
74
      {:ok, nil} ->
UNCOV
75
        text(conn, "OK")
×
76

77
      {:error, {status, message}} ->
78
        conn
79
        |> put_status(status)
UNCOV
80
        |> text(message)
×
81
    end
82
  end
83

84
  def unpublish_grades(conn, %{"submissionid" => submission_id}) when is_ecto_id(submission_id) do
UNCOV
85
    course_reg = conn.assigns[:course_reg]
×
86

UNCOV
87
    case Assessments.unpublish_grading(submission_id, course_reg) do
×
88
      {:ok, nil} ->
UNCOV
89
        text(conn, "OK")
×
90

91
      {:error, {status, message}} ->
92
        conn
93
        |> put_status(status)
UNCOV
94
        |> text(message)
×
95
    end
96
  end
97

98
  def publish_grades(conn, %{"submissionid" => submission_id}) when is_ecto_id(submission_id) do
UNCOV
99
    course_reg = conn.assigns[:course_reg]
×
100

UNCOV
101
    case Assessments.publish_grading(submission_id, course_reg) do
×
102
      {:ok, nil} ->
UNCOV
103
        text(conn, "OK")
×
104

105
      {:error, {status, message}} ->
106
        conn
107
        |> put_status(status)
UNCOV
108
        |> text(message)
×
109
    end
110
  end
111

112
  def publish_all_grades(conn, %{"assessmentid" => assessment_id})
113
      when is_ecto_id(assessment_id) do
114
    course_reg = conn.assigns[:course_reg]
1✔
115

116
    case Assessments.publish_all_graded(course_reg, assessment_id) do
1✔
117
      {:ok, nil} ->
118
        text(conn, "OK")
1✔
119

120
      {:error, {status, message}} ->
121
        conn
122
        |> put_status(status)
UNCOV
123
        |> text(message)
×
124
    end
125
  end
126

127
  def unpublish_all_grades(conn, %{"assessmentid" => assessment_id})
128
      when is_ecto_id(assessment_id) do
129
    course_reg = conn.assigns[:course_reg]
1✔
130

131
    case Assessments.unpublish_all(course_reg, assessment_id) do
1✔
132
      {:ok, nil} ->
133
        text(conn, "OK")
1✔
134

135
      {:error, {status, message}} ->
136
        conn
137
        |> put_status(status)
UNCOV
138
        |> text(message)
×
139
    end
140
  end
141

142
  def autograde_submission(conn, %{"submissionid" => submission_id}) do
UNCOV
143
    course_reg = conn.assigns[:course_reg]
×
144

UNCOV
145
    case Assessments.force_regrade_submission(submission_id, course_reg) do
×
146
      {:ok, nil} ->
UNCOV
147
        send_resp(conn, :no_content, "")
×
148

149
      {:error, {status, message}} ->
150
        conn
151
        |> put_status(status)
UNCOV
152
        |> text(message)
×
153
    end
154
  end
155

156
  def autograde_answer(conn, %{"submissionid" => submission_id, "questionid" => question_id}) do
UNCOV
157
    course_reg = conn.assigns[:course_reg]
×
158

UNCOV
159
    case Assessments.force_regrade_answer(submission_id, question_id, course_reg) do
×
160
      {:ok, nil} ->
UNCOV
161
        send_resp(conn, :no_content, "")
×
162

163
      {:error, {status, message}} ->
164
        conn
165
        |> put_status(status)
UNCOV
166
        |> text(message)
×
167
    end
168
  end
169

170
  def grading_summary(conn, %{"course_id" => course_id}) do
UNCOV
171
    case Assessments.get_group_grading_summary(course_id) do
×
172
      {:ok, cols, summary} ->
UNCOV
173
        render(conn, "grading_summary.json", cols: cols, summary: summary)
×
174
    end
175
  end
176

177
  swagger_path :index do
1✔
178
    get("/courses/{course_id}/admin/grading")
179

180
    summary("Get a list of all submissions with current user as the grader")
181

182
    security([%{JWT: []}])
183

184
    produces("application/json")
185

186
    parameters do
187
      group(
188
        :query,
189
        :boolean,
190
        "Show only students in the grader's group when true",
191
        required: false
192
      )
193
    end
194

195
    response(200, "OK", Schema.ref(:Submissions))
196
    response(401, "Unauthorised")
197
    response(403, "Forbidden")
198
  end
199

200
  swagger_path :unsubmit do
1✔
201
    post("/courses/{course_id}/admin/grading/{submissionId}/unsubmit")
202
    summary("Unsubmit submission. Can only be done by the Avenger of a student")
203
    security([%{JWT: []}])
204

205
    parameters do
206
      submissionId(:path, :integer, "submission id", required: true)
207
    end
208

209
    response(200, "OK")
210
    response(400, "Invalid parameters")
211
    response(403, "Forbidden")
212
    response(404, "Submission not found")
213
  end
214

215
  swagger_path :autograde_submission do
1✔
216
    post("/courses/{course_id}/admin/grading/{submissionId}/autograde")
217
    summary("Force re-autograding of an entire submission")
218
    security([%{JWT: []}])
219

220
    parameters do
221
      submissionId(:path, :integer, "submission id", required: true)
222
    end
223

224
    response(204, "Successful request")
225
    response(400, "Invalid parameters or submission not submitted")
226
    response(403, "Forbidden")
227
    response(404, "Submission not found")
228
  end
229

230
  swagger_path :autograde_answer do
1✔
231
    post("/courses/{course_id}/admin/grading/{submissionId}/{questionId}/autograde")
232
    summary("Force re-autograding of a question in a submission")
233
    security([%{JWT: []}])
234

235
    parameters do
236
      submissionId(:path, :integer, "submission id", required: true)
237
      questionId(:path, :integer, "question id", required: true)
238
    end
239

240
    response(204, "Successful request")
241
    response(400, "Invalid parameters or submission not submitted")
242
    response(403, "Forbidden")
243
    response(404, "Answer not found")
244
  end
245

246
  swagger_path :show do
1✔
247
    get("/courses/{course_id}/admin/grading/{submissionId}")
248

249
    summary("Get information about a specific submission to be graded")
250

251
    security([%{JWT: []}])
252

253
    produces("application/json")
254

255
    parameters do
256
      submissionId(:path, :integer, "submission id", required: true)
257
    end
258

259
    response(200, "OK", Schema.ref(:GradingInfo))
260
    response(400, "Invalid or missing parameter(s) or submission and/or question not found")
261
    response(401, "Unauthorised")
262
    response(403, "Forbidden")
263
  end
264

265
  swagger_path :update do
1✔
266
    post("/courses/{course_id}/admin/grading/{submissionId}/{questionId}")
267

268
    summary("Update marks given to the answer of a particular question in a submission")
269

270
    security([%{JWT: []}])
271

272
    consumes("application/json")
273
    produces("application/json")
274

275
    parameters do
276
      submissionId(:path, :integer, "submission id", required: true)
277
      questionId(:path, :integer, "question id", required: true)
278
      grading(:body, Schema.ref(:Grading), "adjustments for a question", required: true)
279
    end
280

281
    response(200, "OK")
282
    response(400, "Invalid or missing parameter(s) or submission and/or question not found")
283
    response(401, "Unauthorised")
284
    response(403, "Forbidden")
285
  end
286

287
  swagger_path :grading_summary do
1✔
288
    get("/courses/{course_id}/admin/grading/summary")
289

290
    summary("Receives a summary of grading items done by this grader")
291

292
    security([%{JWT: []}])
293

294
    produces("application/json")
295

296
    response(200, "OK", Schema.array(:GradingSummary))
297
    response(400, "Invalid or missing parameter(s) or submission and/or question not found")
298
    response(401, "Unauthorised")
299
    response(403, "Forbidden")
300
  end
301

302
  def swagger_definitions do
303
    %{
1✔
304
      Submissions:
305
        swagger_schema do
1✔
306
          type(:array)
307
          items(Schema.ref(:Submission))
308
        end,
309
      Submission:
310
        swagger_schema do
1✔
311
          properties do
1✔
312
            id(:integer, "Submission id", required: true)
313
            grade(:integer, "Grade given", required: true)
314
            xp(:integer, "XP earned", required: true)
315
            xpBonus(:integer, "Bonus XP for a given submission", required: true)
316
            xpAdjustment(:integer, "XP adjustment given", required: true)
317
            adjustment(:integer, "Grade adjustment given", required: true)
318

319
            status(
320
              Schema.ref(:AssessmentStatus),
321
              "One of 'not_attempted/attempting/attempted/submitted' indicating whether the assessment has been attempted by the current user",
322
              required: true
323
            )
324

325
            gradedCount(:integer, "Number of questions in this submission that have been graded",
326
              required: true
327
            )
328

329
            assessment(Schema.ref(:AssessmentInfo), "Assessment for which the submission is for",
330
              required: true
331
            )
332

333
            student(Schema.ref(:StudentInfo), "Student who created the submission", required: true)
334

335
            unsubmittedBy(Schema.ref(:GraderInfo))
336
            unsubmittedAt(:string, "Last unsubmitted at", format: "date-time", required: false)
337

338
            isGradingPublished(:boolean, "Whether the grading is published", required: true)
1✔
339
          end
340
        end,
341
      AssessmentInfo:
342
        swagger_schema do
1✔
343
          properties do
1✔
344
            id(:integer, "assessment id", required: true)
345

346
            config(Schema.ref(:AssessmentConfig), "Either mission/sidequest/path/contest",
347
              required: true
348
            )
349

350
            title(:string, "Mission title", required: true)
351

352
            maxGrade(
353
              :integer,
354
              "The max grade for this assessment",
355
              required: true
356
            )
357

358
            maxXp(
359
              :integer,
360
              "The max xp for this assessment",
361
              required: true
362
            )
363

364
            questionCount(:integer, "number of questions in this assessment", required: true)
1✔
365
          end
366
        end,
367
      StudentInfo:
368
        swagger_schema do
1✔
369
          properties do
1✔
370
            id(:integer, "student id", required: true)
371
            name(:string, "student name", required: true)
372
            username(:string, "student username", required: true)
373
            groupName(:string, "name of student's group")
374
            groupLeaderId(:integer, "user id of group leader")
1✔
375
          end
376
        end,
377
      GraderInfo:
378
        swagger_schema do
1✔
379
          properties do
1✔
380
            id(:integer, "grader id", required: true)
381
            name(:string, "grader name", required: true)
1✔
382
          end
383
        end,
384
      GradingInfo:
385
        swagger_schema do
1✔
386
          description(
387
            "A list of questions with submitted answers, solution and previous grading info " <>
388
              "if available"
389
          )
390

391
          type(:array)
392

393
          items(
394
            Schema.new do
1✔
395
              properties do
1✔
396
                question(Schema.ref(:Question), "Question", required: true)
397
                grade(Schema.ref(:Grade), "Grading information", required: true)
398
                student(Schema.ref(:StudentInfo), "Student", required: true)
399

400
                solution(
401
                  :string,
402
                  "the marking scheme and model solution to this question. Only available for programming questions",
403
                  required: true
404
                )
405

406
                maxGrade(
407
                  :integer,
408
                  "the max grade that can be given to this question",
409
                  required: true
410
                )
411

412
                maxXp(
1✔
413
                  :integer,
414
                  "the max xp that can be given to this question",
415
                  required: true
416
                )
417
              end
418
            end
419
          )
420
        end,
421
      GradingSummary:
422
        swagger_schema do
1✔
423
          description("Summary of grading items for current user as the grader")
424

425
          properties do
1✔
426
            groupName(:string, "Name of group this grader is in", required: true)
427
            leaderName(:string, "Name of group leader", required: true)
428
            submittedMissions(:integer, "Number of submitted missions", required: true)
429
            submittedSidequests(:integer, "Number of submitted sidequests", required: true)
430
            ungradedMissions(:integer, "Number of ungraded missions", required: true)
431
            ungradedSidequests(:integer, "Number of ungraded sidequests", required: true)
1✔
432
          end
433
        end,
434
      Grade:
435
        swagger_schema do
1✔
436
          properties do
1✔
437
            grade(:integer, "Grade awarded by autograder")
438
            xp(:integer, "XP awarded by autograder")
439
            adjustment(:integer, "Grade adjustment given")
440
            xpAdjustment(:integer, "XP adjustment given", required: true)
441
            grader(Schema.ref(:GraderInfo))
442
            gradedAt(:string, "Last graded at", format: "date-time", required: false)
443
            comments(:string, "Comments given by grader")
1✔
444
          end
445
        end,
446
      Grading:
447
        swagger_schema do
1✔
448
          properties do
1✔
449
            grading(
1✔
450
              Schema.new do
1✔
451
                properties do
1✔
452
                  adjustment(:integer, "Grade adjustment given")
453
                  xpAdjustment(:integer, "XP adjustment given")
454
                  comments(:string, "Comments given by grader")
1✔
455
                end
456
              end
457
            )
458
          end
459
        end
460
    }
461
  end
462
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc