adding buttons to manage assignments from canvas

This commit is contained in:
2023-10-24 16:32:12 -06:00
parent 860c387c8d
commit b831d47d91
12 changed files with 215 additions and 107 deletions

View File

@@ -57,10 +57,10 @@
if (quizContext.Quiz == null)
{
var quiz = planner
.LocalCourse?
.Modules
.SelectMany(m => m.Quizzes)
.FirstOrDefault(q => q.Name == QuizName);
.LocalCourse?
.Modules
.SelectMany(m => m.Quizzes)
.FirstOrDefault(q => q.Name == QuizName);
quizContext.Quiz = quiz;
logger.LogInformation($"set quiz to '{quizContext.Quiz?.Name}'");
@@ -165,8 +165,12 @@
{
<div class="row justify-content-end">
<div class="col-auto">
<ConfirmationModal Label="Delete" Class="btn btn-danger" OnConfirm="deleteQuiz"
Disabled="@addingQuizToCanvas" />
<ConfirmationModal
Label="Delete"
Class="btn btn-danger"
OnConfirm="deleteQuiz"
Disabled="@addingQuizToCanvas"
/>
<button class="btn btn-outline-secondary me-1" @onclick="addToCanvas" disabled="@addingQuizToCanvas">
Add to Canvas
</button>

View File

@@ -1,6 +1,7 @@
@using Management.Web.Shared.Components
@using Management.Web.Shared.Components.AssignmentForm
@using Management.Web.Shared.Components.Forms
@using CanvasModel.Assignments
@inject CoursePlanner planner
@inject CanvasService canvas
@@ -27,7 +28,7 @@
assignmentContext.StateHasChanged -= reload;
}
private void OnHide()
private void OnHide()
{
assignmentContext.Assignment = null;
name = "";
@@ -36,6 +37,9 @@
private string name { get; set; } = String.Empty;
private bool lockAtDueDate { get; set; }
private bool addingAssignmentToCanvas = false;
private bool deletingAssignmentFromCanvas = false;
private void submitHandler()
{
if (assignmentContext.Assignment != null)
@@ -65,22 +69,24 @@
) ?? throw new Exception("handling assignment delete, could not find module");
var newModules = planner.LocalCourse.Modules.Select(m =>
m.Name == currentModule.Name
? m with
{
Assignments = m.Assignments.Where(a => a != assignment).ToArray()
}
: m
).ToArray();
m.Name == currentModule.Name
? m with
{
Assignments = m.Assignments.Where(a => a != assignment).ToArray()
}
: m
)
.ToArray();
planner.LocalCourse = planner.LocalCourse with
{
Modules = newModules
};
if (assignment.CanvasId != null && planner.LocalCourse.Settings.CanvasId != null)
if (assignmentInCanvas != null && planner.LocalCourse.Settings.CanvasId != null)
{
ulong courseId = planner.LocalCourse.Settings.CanvasId ?? throw new Exception("cannot delete if no course id");
await canvas.Assignments.Delete(courseId, assignment);
await canvas.Assignments.Delete(courseId, assignmentInCanvas.Id, assignment.Name);
}
}
}
@@ -100,35 +106,64 @@
{
var lockAtDueDate = (bool)(e.Value ?? false);
var lockAtDate = lockAtDueDate
? assignmentContext.Assignment.DueAt
: assignmentContext.Assignment.LockAt;
var newAssignment = assignmentContext.Assignment with {
LockAtDueDate = lockAtDueDate,
LockAt = lockAtDate,
};
? assignmentContext.Assignment.DueAt
: assignmentContext.Assignment.LockAt;
var newAssignment = assignmentContext.Assignment with
{
LockAtDueDate = lockAtDueDate,
LockAt = lockAtDate,
};
assignmentContext.SaveAssignment(newAssignment);
}
}
private void setAssignmentGroup(LocalAssignmentGroup? group)
{
if(assignmentContext.Assignment == null)
if (assignmentContext.Assignment == null)
return;
var newAssignment = assignmentContext.Assignment with
{
LocalAssignmentGroupId = group?.Id
};
var newAssignment = assignmentContext.Assignment with
{
LocalAssignmentGroupId = group?.Id
};
assignmentContext.SaveAssignment(newAssignment);
}
private LocalAssignmentGroup? selectedAssignmentGroup =>
planner
.LocalCourse?
.Settings
.AssignmentGroups
.FirstOrDefault(g => g.Id == assignmentContext.Assignment?.LocalAssignmentGroupId);
.LocalCourse?
.Settings
.AssignmentGroups
.FirstOrDefault(g => g.Id == assignmentContext.Assignment?.LocalAssignmentGroupId);
private async Task addToCanvas()
{
addingAssignmentToCanvas = true;
await assignmentContext.AddAssignmentToCanvas();
await planner.LoadCanvasData();
addingAssignmentToCanvas = false;
}
private CanvasAssignment? assignmentInCanvas =>
planner.CanvasAssignments?.FirstOrDefault(a => a.Name == assignmentContext.Assignment?.Name);
private string canvasAssignmentUrl =>
$"https://snow.instructure.com/courses/{planner.LocalCourse?.Settings.CanvasId}/assignments/{assignmentInCanvas?.Id}";
private async Task deleteFromCanvas()
{
if (assignmentInCanvas == null || planner.LocalCourse.Settings.CanvasId == null || assignmentContext.Assignment == null)
return;
deletingAssignmentFromCanvas = true;
await canvas.Assignments.Delete(
(ulong)planner.LocalCourse.Settings.CanvasId,
assignmentInCanvas.Id,
assignmentContext.Assignment.Name);
await planner.LoadCanvasData();
StateHasChanged();
deletingAssignmentFromCanvas = false;
}
}
@assignmentContext.Assignment?.Name
@@ -136,38 +171,26 @@
@if (assignmentContext.Assignment != null)
{
<div class="m-1">
<label class="form-label">
Name
</label>
<input
class="form-control"
@bind="name"
@oninput="handleNameChange"
/>
</div>
<ButtonSelect
Label="Assignment Group"
Options="planner.LocalCourse?.Settings.AssignmentGroups"
<label class="form-label">
Name
</label>
<input class="form-control" @bind="name" @oninput="handleNameChange" />
</div>
<ButtonSelect
Label="Assignment Group"
Options="planner.LocalCourse?.Settings.AssignmentGroups"
GetName="(g) => g?.Name"
OnSelect="(g) => setAssignmentGroup(g)"
SelectedOption="selectedAssignmentGroup"
OnSelect="(g) => setAssignmentGroup(g)"
SelectedOption="selectedAssignmentGroup"
/>
<div class="m-1">
<AssignmentDescriptionEditor />
</div>
<div class="form-check m-1">
<input
class="form-check-input"
id="lockAtDueDate"
type="checkbox"
@bind="lockAtDueDate"
@oninput="handleLockAtDueDateChange"
/>
<label
class="form-check-label"
for="lockAtDueDate"
>
<input class="form-check-input" id="lockAtDueDate" type="checkbox" @bind="lockAtDueDate"
@oninput="handleLockAtDueDateChange" />
<label class="form-check-label" for="lockAtDueDate">
Lock At Due Date
</label>
</div>
@@ -185,16 +208,41 @@
<ConfirmationModal Label="Delete" Class="btn btn-danger" OnConfirmAsync="HandleDelete" />
<button
class="btn btn-primary mx-2"
@onclick="@(() => {
class="btn btn-outline-secondary mx-3"
disabled="@(addingAssignmentToCanvas || deletingAssignmentFromCanvas)"
@onclick="addToCanvas"
>
Add To Canvas
</button>
@if (assignmentInCanvas != null)
{
<a
class="btn btn-outline-secondary me-1"
href="@canvasAssignmentUrl"
target="_blank"
disabled="@(addingAssignmentToCanvas || deletingAssignmentFromCanvas)"
>
View in Canvas
</a>
<ConfirmationModal
Disabled="@(addingAssignmentToCanvas || deletingAssignmentFromCanvas)"
Label="Delete from Canvas"
Class="btn btn-outline-danger mx-3"
OnConfirmAsync="deleteFromCanvas"
/>
}
<button class="btn btn-primary mx-2" @onclick="@(() => {
assignmentContext.Assignment = null;
Navigation.NavigateTo("/course/" + planner.LocalCourse?.Settings.Name);
})"
>
})">
Done
</button>
</div>
@if (addingAssignmentToCanvas || deletingAssignmentFromCanvas)
{
<Spinner />
}
<br>
<br>
<br>

View File

@@ -29,14 +29,9 @@
{
if (assignmentContext.Assignment != null)
{
var totalRubricPoints = rubric
.Where(r => !r.Label.Contains(RubricItem.extraCredit))
.Select(s => s.Points)
.Sum();
var newAssignment = assignmentContext.Assignment with
{
Rubric = rubric,
PointsPossible = totalRubricPoints,
};
assignmentContext.SaveAssignment(newAssignment);
StateHasChanged();

View File

@@ -49,7 +49,7 @@
}
<button
class="btn btn-danger"
class="@(Class != "" ? Class : "btn btn-danger ")"
@onclick="() => modal?.Show()"
disabled="@Disabled"
>

View File

@@ -27,7 +27,6 @@
Rubric = new RubricItem[] { },
LockAt = null,
DueAt = DateTime.Now,
PointsPossible = 10,
SubmissionTypes = new string[] { SubmissionType.ONLINE_TEXT_ENTRY },
LocalAssignmentGroupId = selectedAssignmentGroup?.Id,
};

View File

@@ -1,17 +1,29 @@
using LocalModels;
using Management.Planner;
using Management.Services;
using Management.Services.Canvas;
public class AssignmentEditorContext
{
public event Action? StateHasChanged;
public CanvasService canvas { get; }
private CoursePlanner planner { get; }
public AssignmentEditorContext(CoursePlanner planner)
public AssignmentEditorContext(
MyLogger<AssignmentEditorContext> logger,
CanvasService canvas,
CoursePlanner planner
)
{
this.logger = logger;
this.canvas = canvas;
this.planner = planner;
}
private LocalAssignment? _assignment;
private readonly MyLogger<AssignmentEditorContext> logger;
public LocalAssignment? Assignment
{
get => _assignment;
@@ -50,4 +62,72 @@ public class AssignmentEditorContext
planner.LocalCourse = planner.LocalCourse with { Modules = updatedModules };
}
}
public async Task AddAssignmentToCanvas()
{
logger.Log("started to add assignment to canvas");
if (Assignment == null)
{
logger.Log("cannot add null assignment to canvas");
return;
}
await planner.LoadCanvasData();
if (planner.CanvasAssignments == null)
{
logger.Log("cannot add assignment to canvas, failed to retrieve current assignments");
return;
}
if (planner.LocalCourse == null)
{
logger.Log("cannot add assignment to canvas, no course stored in planner");
return;
}
var courseCanvasId = planner.LocalCourse.Settings.CanvasId;
if (courseCanvasId == null)
{
logger.Log("cannot add assignment to canvas if there is no course canvas id");
return;
}
var createdAssignment = await planner.LocalCourse.SyncAssignmentToCanvas(
canvasCourseId: (ulong)courseCanvasId,
localAssignment: Assignment,
canvasAssignments: planner.CanvasAssignments,
canvas: canvas
);
var currentModule = getCurrentModule(Assignment, planner.LocalCourse);
if (currentModule.CanvasId == null)
{
logger.Log("was able to add assignment to canvas, but errored while making module item. module canvasId is null");
return;
}
await canvas.CreateModuleItem(
(ulong)courseCanvasId,
(ulong)currentModule.CanvasId,
Assignment.Name,
"Assignment",
(ulong)createdAssignment.CanvasId
);
await planner.LocalCourse.Modules.First().SortModuleItems(
(ulong)courseCanvasId,
(ulong)currentModule.CanvasId,
canvas
);
logger.Log($"finished adding assignment {Assignment.Name} to canvas");
}
private static LocalModule getCurrentModule(LocalAssignment assignment, LocalCourse course)
{
return course.Modules.FirstOrDefault(
m => m.Assignments.Contains(assignment)
)
?? throw new Exception("could not find current module in assignment editor context");
}
}

View File

@@ -6,7 +6,9 @@ using Management.Services.Canvas;
public class QuizEditorContext
{
public QuizEditorContext(CoursePlanner planner, CanvasService canvas,
public QuizEditorContext(
CoursePlanner planner,
CanvasService canvas,
MyLogger<CanvasAssignmentService> logger)
{
this.planner = planner;
@@ -28,7 +30,7 @@ public class QuizEditorContext
get => _quiz;
set
{
if(_quiz == null && value != null)
if (_quiz == null && value != null)
{
_module = getCurrentModule(value, planner.LocalCourse);
}
@@ -70,7 +72,8 @@ public class QuizEditorContext
var updatedModules = planner.LocalCourse.Modules
.Select(m => m.Name != _module.Name
? m
: m with {
: m with
{
Quizzes = m.Quizzes.Where(q => q.Name + q.Description != Quiz.Name + Quiz.Description).ToArray()
}
)
@@ -85,18 +88,18 @@ public class QuizEditorContext
public async Task AddQuizToCanvas()
{
logger.Log("started to add quiz to canvas");
if(Quiz == null)
if (Quiz == null)
{
logger.Log("cannot add null quiz to canvas");
return;
}
await planner.LoadCanvasData();
if(planner.CanvasQuizzes == null)
if (planner.CanvasQuizzes == null)
{
logger.Log("cannot add quiz to canvas, failed to retrieve current quizzes");
return;
}
if(planner.LocalCourse == null)
if (planner.LocalCourse == null)
{
logger.Log("cannot add quiz to canvas, no course stored in planner");
return;
@@ -108,14 +111,14 @@ public class QuizEditorContext
var courseCanvasId = planner.LocalCourse.Settings.CanvasId;
if (courseCanvasId == null)
{
logger.Log("was able to add course to canvas, but errored while making module item. CourseCanvasId is null");
logger.Log("was able to add quiz to canvas, but errored while making module item. CourseCanvasId is null");
return;
}
var currentModule = getCurrentModule(Quiz, planner.LocalCourse);
if (currentModule.CanvasId == null)
{
logger.Log("was able to add course to canvas, but errored while making module item. module canvasId is null");
logger.Log("was able to add quiz to canvas, but errored while making module item. module canvasId is null");
return;
}

View File

@@ -1,3 +1,4 @@
using System.Reflection;
using System.Text.RegularExpressions;
using CanvasModel.Assignments;
using CanvasModel.Modules;
@@ -9,6 +10,8 @@ namespace Management.Planner;
public static partial class AssignmentSyncronizationExtensions
{
internal static async Task<LocalAssignment> SyncAssignmentToCanvas(
this LocalCourse localCourse,
ulong canvasCourseId,

View File

@@ -47,13 +47,7 @@ public record LocalAssignment
public DateTime? LockAt { get; init; }
public DateTime DueAt { get; init; }
public string? LocalAssignmentGroupId { get; init; }
public int PointsPossible
{
get
{
return Rubric.Sum(r => r.IsExtraCredit ? 0 : r.Points);
}
}
public int PointsPossible => Rubric.Sum(r => r.IsExtraCredit ? 0 : r.Points);
public IEnumerable<string> SubmissionTypes { get; init; } = Array.Empty<string>();
public string GetRubricHtml()

View File

@@ -96,10 +96,10 @@ public class CanvasAssignmentService
await CreateRubric(courseId, localAssignment);
}
public async Task Delete(ulong courseId, LocalAssignment assignment)
public async Task Delete(ulong courseId, ulong assignmentCanvasId, string assignmentName)
{
log.Log($"deleting assignment from canvas {assignment.Name}");
var url = $"courses/{courseId}/assignments/{assignment.CanvasId}";
log.Log($"deleting assignment from canvas {assignmentName}");
var url = $"courses/{courseId}/assignments/{assignmentCanvasId}";
var request = new RestRequest(url);
var response = await webRequestor.DeleteAsync(request);
if (!response.IsSuccessful)

View File

@@ -100,7 +100,8 @@ public class CanvasQuizService
{
await assignments.Delete(
canvasCourseId,
new LocalAssignment { Name = a.Name, CanvasId = a.Id }
a.Id,
a.Name
);
}
);

View File

@@ -17,22 +17,3 @@ Apparently the VSCode razor extension was compiled with a preview of dotnet 6...
The issue can be tracked [here](https://github.com/dotnet/razor/issues/6241)
pOpenID Connect is sometimes abbreviated to OIDC. It is not a synonym to Oauth2.0/p
pRead and watch the video in this article a href=https://developer.okta.com/blog/2019/10/21/illustrated-guide-to-oauth-and-oidchttps://developer.okta.com/blog/2019/10/21/illustrated-guide-to-oauth-and-oidc/abr
Read this article: a href=https://curity.io/resources/learn/openid-connect-overview/https://curity.io/resources/learn/openid-connect-overview//abr
Watch this video: a href=https://www.youtube.com/watch?v=rTzlF-U9Y6Yhttps://www.youtube.com/watch?v=rTzlF-U9Y6Y/a/p
pSubmit your answers to these questions:/p
ol
liWhat problem is Oauth 2.0 trying to solve?/li
liWhat is the difference between oauth and openid connect?/li
liWhat problem is OIDC trying to solve?/li
liWhat resources does the client get from the authentication server after a OIDC flow?/li
/ol
hrh1Rubric/h1precode class=language-json[
{label: Answered 4 questions, points: 8}
]/code/pre