using CanvasModel.Quizzes; using LocalModels; using RestSharp; namespace Management.Services.Canvas; public class CanvasQuizService( IWebRequestor webRequestor, CanvasServiceUtils utils, CanvasAssignmentService assignments ) { private readonly IWebRequestor webRequestor = webRequestor; private readonly CanvasServiceUtils utils = utils; private readonly CanvasAssignmentService assignments = assignments; public async Task> GetAll(ulong courseId) { var url = $"courses/{courseId}/quizzes"; var request = new RestRequest(url); var quizResponse = await utils.PaginatedRequest>(request); return quizResponse.SelectMany( quizzes => quizzes.Select( a => a with { DueAt = a.DueAt?.ToLocalTime(), LockAt = a.LockAt?.ToLocalTime() } ) ); } public async Task Create( ulong canvasCourseId, LocalQuiz localQuiz, ulong? canvasAssignmentGroupId ) { Console.WriteLine($"Creating Quiz {localQuiz.Name}"); var url = $"courses/{canvasCourseId}/quizzes"; var body = new { quiz = new { title = localQuiz.Name, description = localQuiz.GetDescriptionHtml(), // assignment_group_id = "quiz", // TODO: support specific assignment groups // time_limit = localQuiz.TimeLimit, shuffle_answers = localQuiz.ShuffleAnswers, // hide_results = localQuiz.HideResults, allowed_attempts = localQuiz.AllowedAttempts, one_question_at_a_time = false, cant_go_back = false, due_at = localQuiz.DueAt, lock_at = localQuiz.LockAt, assignment_group_id = canvasAssignmentGroupId, } }; var request = new RestRequest(url); request.AddBody(body); var (canvasQuiz, response) = await webRequestor.PostAsync(request); if (canvasQuiz == null) throw new Exception("Created canvas quiz was null"); await CreateQuizQuestions(canvasCourseId, canvasQuiz.Id, localQuiz); return canvasQuiz.Id; } public async Task CreateQuizQuestions( ulong canvasCourseId, ulong canvasQuizId, LocalQuiz localQuiz ) { var tasks = localQuiz.Questions.Select(createQuestion(canvasCourseId, canvasQuizId)).ToArray(); await Task.WhenAll(tasks); await hackFixRedundantAssignments(canvasCourseId); } private async Task hackFixRedundantAssignments(ulong canvasCourseId) { var canvasAssignments = await assignments.GetAll(canvasCourseId); var assignmentsToDelete = canvasAssignments .Where( assignment => !assignment.IsQuizAssignment && assignment.SubmissionTypes.Contains(AssignmentSubmissionType.ONLINE_QUIZ) ) .ToArray(); var tasks = assignmentsToDelete.Select( async (a) => { await assignments.Delete( canvasCourseId, a.Id, a.Name ); } ); await Task.WhenAll(tasks); } private Func createQuestion( ulong canvasCourseId, ulong canvasQuizId ) { return async (question) => await createQuestionOnly(canvasCourseId, canvasQuizId, question); } private async Task createQuestionOnly( ulong canvasCourseId, ulong canvasQuizId, LocalQuizQuestion q ) { var url = $"courses/{canvasCourseId}/quizzes/{canvasQuizId}/questions"; var answers = q.Answers .Select(a => new { answer_html = a.HtmlText, answer_weight = a.Correct ? 100 : 0 }) .ToArray(); var body = new { question = new { question_text = q.HtmlText, question_type = q.QuestionType + "_question", points_possible = q.Points, // position answers } }; var request = new RestRequest(url); request.AddBody(body); var (newQuestion, response) = await webRequestor.PostAsync(request); if (newQuestion == null) throw new NullReferenceException("error creating new question, created question is null"); return newQuestion; } }