From f02ead71784c92421e0c37813241478e58669375 Mon Sep 17 00:00:00 2001 From: Alex Mickelson Date: Fri, 18 Aug 2023 17:18:23 -0600 Subject: [PATCH] implemented hack to canvas quiz --- .../Assignments/CanvasAssignment.cs | 3 + .../Canvas/CanvasAssignmentService.cs | 2 +- .../Services/Canvas/CanvasQuizService.cs | 98 +++++++++++++------ requests/quiz.http | 4 +- 4 files changed, 76 insertions(+), 31 deletions(-) diff --git a/Management/Models/CanvasModels/Assignments/CanvasAssignment.cs b/Management/Models/CanvasModels/Assignments/CanvasAssignment.cs index 9dfa293..08ccd5d 100644 --- a/Management/Models/CanvasModels/Assignments/CanvasAssignment.cs +++ b/Management/Models/CanvasModels/Assignments/CanvasAssignment.cs @@ -70,6 +70,9 @@ public record CanvasAssignment [property: JsonPropertyName("allowed_attempts")] int AllowedAttempts, + + [property: JsonPropertyName("is_quiz_assignment")] + bool IsQuizAssignment, [property: JsonPropertyName("submission_types")] IEnumerable SubmissionTypes, diff --git a/Management/Services/Canvas/CanvasAssignmentService.cs b/Management/Services/Canvas/CanvasAssignmentService.cs index 970a4c1..46911f0 100644 --- a/Management/Services/Canvas/CanvasAssignmentService.cs +++ b/Management/Services/Canvas/CanvasAssignmentService.cs @@ -19,7 +19,7 @@ public class CanvasAssignmentService { var url = $"courses/{courseId}/assignments"; var request = new RestRequest(url); - request.AddParameter("include[]", "overrides"); + // request.AddParameter("include[]", "overrides"); var assignmentResponse = await utils.PaginatedRequest>(request); return assignmentResponse.SelectMany( assignments => diff --git a/Management/Services/Canvas/CanvasQuizService.cs b/Management/Services/Canvas/CanvasQuizService.cs index 2f0fff8..8aaad54 100644 --- a/Management/Services/Canvas/CanvasQuizService.cs +++ b/Management/Services/Canvas/CanvasQuizService.cs @@ -1,3 +1,5 @@ +using System.Runtime.InteropServices; +using System.Security.Cryptography.X509Certificates; using CanvasModel.Quizzes; using LocalModels; using RestSharp; @@ -8,11 +10,17 @@ public class CanvasQuizService { private readonly IWebRequestor webRequestor; private readonly CanvasServiceUtils utils; + private readonly CanvasAssignmentService assignments; - public CanvasQuizService(IWebRequestor webRequestor, CanvasServiceUtils utils) + public CanvasQuizService( + IWebRequestor webRequestor, + CanvasServiceUtils utils, + CanvasAssignmentService assignments + ) { this.webRequestor = webRequestor; this.utils = utils; + this.assignments = assignments; } public async Task> GetAll(ulong courseId) @@ -56,7 +64,6 @@ public class CanvasQuizService if (canvasQuiz == null) throw new Exception("Created canvas quiz was null"); - var updatedQuiz = localQuiz with { CanvasId = canvasQuiz.Id }; var quizWithQuestions = await CreateQuizQuestions(canvasCourseId, updatedQuiz); @@ -65,33 +72,67 @@ public class CanvasQuizService public async Task CreateQuizQuestions(ulong canvasCourseId, LocalQuiz localQuiz) { - var tasks = localQuiz.Questions - .Select( - async (question) => - { - var newQuestion = await createQuestionOnly(canvasCourseId, localQuiz, question); + var tasks = localQuiz.Questions.Select(createQuestion(canvasCourseId, localQuiz)).ToArray(); + var updatedQuestions = await Task.WhenAll(tasks); - var answersWithIds = question.Answers - .Select(answer => - { - var canvasAnswer = newQuestion.Answers?.FirstOrDefault(ca => ca.Html == answer.Text); - if (canvasAnswer == null) - { - Console.WriteLine(JsonSerializer.Serialize(newQuestion)); - Console.WriteLine(JsonSerializer.Serialize(question)); - throw new NullReferenceException( - "Could not find canvas answer to update local answer id" - ); - } - return answer with { CanvasId = canvasAnswer.Id }; - }) - .ToArray(); - return question with { CanvasId = newQuestion.Id, Answers = answersWithIds }; - } + await hackFixRedundantAssignments(canvasCourseId); + return localQuiz with { Questions = updatedQuestions }; + } + + private async Task hackFixRedundantAssignments(ulong canvasCourseId) + { + var canvasAssignments = await assignments.GetAll(canvasCourseId); + + var assignmentsToDelete = canvasAssignments + .Where( + assignment => + !assignment.IsQuizAssignment + && assignment.SubmissionTypes.Contains(SubmissionType.ONLINE_QUIZ) ) .ToArray(); - var updatedQuestions = await Task.WhenAll(tasks); - return localQuiz with { Questions = updatedQuestions }; + var tasks = assignmentsToDelete.Select( + async (a) => + { + await assignments.Delete( + canvasCourseId, + new LocalAssignment { Name = a.Name, CanvasId = a.Id } + ); + } + ); + await Task.WhenAll(tasks); + } + + private Func> createQuestion( + ulong canvasCourseId, + LocalQuiz localQuiz + ) + { + return async (question) => + { + var newQuestion = await createQuestionOnly(canvasCourseId, localQuiz, question); + + var answersWithIds = question.Answers + .Select(answer => + { + var canvasAnswer = newQuestion.Answers?.FirstOrDefault(ca => ca.Html == answer.Text); + if (canvasAnswer == null) + { + Console.WriteLine(JsonSerializer.Serialize(newQuestion)); + Console.WriteLine(JsonSerializer.Serialize(question)); + throw new NullReferenceException( + "Could not find canvas answer to update local answer id" + ); + } + return answer with { CanvasId = canvasAnswer.Id }; + }) + .ToArray(); + + return question with + { + CanvasId = newQuestion.Id, + Answers = answersWithIds + }; + }; } private async Task createQuestionOnly( @@ -109,8 +150,8 @@ public class CanvasQuizService question = new { question_text = q.Text, - question_type = q.QuestionType+"_question", - possible_points = q.Points, + question_type = q.QuestionType + "_question", + points_possible = q.Points, // position answers } @@ -120,6 +161,7 @@ public class CanvasQuizService var (newQuestion, response) = await webRequestor.PostAsync(request); if (newQuestion == null) throw new NullReferenceException("error creating new question, created question is null"); + return newQuestion; } } diff --git a/requests/quiz.http b/requests/quiz.http index c17e4a4..856f63e 100644 --- a/requests/quiz.http +++ b/requests/quiz.http @@ -7,13 +7,13 @@ GET https://snow.instructure.com/api/v1/courses/871954/assignments Authorization: Bearer {{$dotenv CANVAS_TOKEN}} ### -POST https://snow.instructure.com/api/v1/courses/871954/quizzes/3236013/questions +POST https://snow.instructure.com/api/v1/courses/871954/quizzes/3243305/questions Authorization: Bearer {{$dotenv CANVAS_TOKEN}} Content-Type: application/json { "question":{ - "question_text": "Other clues to how things work come from their visible structure. Specifically from _____, _____, and _____", + "question_text": "dummy question via the api", "question_type": "multiple_answers_question", "points_possible": 3, "answers": [