after removing canvas id from module

This commit is contained in:
2023-11-06 07:54:17 -07:00
parent 3252e3ca9f
commit bda13f7bec
13 changed files with 357 additions and 96 deletions

View File

@@ -14,4 +14,190 @@ dotnet_diagnostic.CA2254.severity = none
[*.razor] [*.razor]
indent_style = ignore indent_style = ignore
indent_size = ignore indent_size = ignore
# Default settings:
# A newline ending every file
# Use 4 spaces as indentation
[*]
insert_final_newline = true
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
[project.json]
indent_size = 2
# Generated code
[*{_AssemblyInfo.cs,.notsupported.cs}]
generated_code = true
# C# files
[*.cs]
# New line preferences
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_between_query_expression_clauses = true
# Indentation preferences
csharp_indent_block_contents = true
csharp_indent_braces = false
csharp_indent_case_contents = true
csharp_indent_case_contents_when_block = true
csharp_indent_switch_labels = true
csharp_indent_labels = one_less_than_current
# Modifier preferences
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion
# avoid this. unless absolutely necessary
dotnet_style_qualification_for_field = false:suggestion
dotnet_style_qualification_for_property = false:suggestion
dotnet_style_qualification_for_method = false:suggestion
dotnet_style_qualification_for_event = false:suggestion
# Types: use keywords instead of BCL types, and permit var only when the type is clear
# csharp_style_var_for_built_in_types = false:suggestion
csharp_style_var_when_type_is_apparent = false:none
# csharp_style_var_elsewhere = false:suggestion
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
dotnet_style_predefined_type_for_member_access = true:suggestion
# name all constant fields using PascalCase
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
dotnet_naming_symbols.constant_fields.applicable_kinds = field
dotnet_naming_symbols.constant_fields.required_modifiers = const
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
# static fields should have s_ prefix
# dotnet_naming_rule.static_fields_should_have_prefix.severity = suggestion
# dotnet_naming_rule.static_fields_should_have_prefix.symbols = static_fields
# dotnet_naming_rule.static_fields_should_have_prefix.style = static_prefix_style
# dotnet_naming_symbols.static_fields.applicable_kinds = field
# dotnet_naming_symbols.static_fields.required_modifiers = static
# dotnet_naming_symbols.static_fields.applicable_accessibilities = private, internal, private_protected
# dotnet_naming_style.static_prefix_style.required_prefix = s_
# dotnet_naming_style.static_prefix_style.capitalization = camel_case
# internal and private fields should be _camelCase
dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion
dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields
dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style
dotnet_naming_symbols.private_internal_fields.applicable_kinds = field
dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal
dotnet_naming_style.camel_case_underscore_style.required_prefix = _
dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case
# Code style defaults
csharp_using_directive_placement = outside_namespace:suggestion
dotnet_sort_system_directives_first = true
csharp_prefer_braces = true:silent
csharp_preserve_single_line_blocks = true:none
csharp_preserve_single_line_statements = false:none
csharp_prefer_static_local_function = true:suggestion
csharp_prefer_simple_using_statement = false:none
csharp_style_prefer_switch_expression = true:suggestion
dotnet_style_readonly_field = true:suggestion
# Expression-level preferences
dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
dotnet_style_prefer_inferred_tuple_names = true:suggestion
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
dotnet_style_prefer_auto_properties = true:suggestion
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
dotnet_style_prefer_conditional_expression_over_return = true:silent
csharp_prefer_simple_default_expression = true:suggestion
# Expression-bodied members
csharp_style_expression_bodied_methods = true:silent
csharp_style_expression_bodied_constructors = true:silent
csharp_style_expression_bodied_operators = true:silent
csharp_style_expression_bodied_properties = true:silent
csharp_style_expression_bodied_indexers = true:silent
csharp_style_expression_bodied_accessors = true:silent
csharp_style_expression_bodied_lambdas = true:silent
csharp_style_expression_bodied_local_functions = true:silent
# Pattern matching
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
csharp_style_inlined_variable_declaration = true:suggestion
# Null checking preferences
csharp_style_throw_expression = true:suggestion
csharp_style_conditional_delegate_call = true:suggestion
# Other features
csharp_style_prefer_index_operator = false:none
csharp_style_prefer_range_operator = false:none
csharp_style_pattern_local_over_anonymous_function = false:none
# Space preferences
csharp_space_after_cast = false
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_after_comma = true
csharp_space_after_dot = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_after_semicolon_in_for_statement = true
csharp_space_around_binary_operators = before_and_after
csharp_space_around_declaration_statements = do_not_ignore
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_before_comma = false
csharp_space_before_dot = false
csharp_space_before_open_square_brackets = false
csharp_space_before_semicolon_in_for_statement = false
csharp_space_between_empty_square_brackets = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_declaration_name_and_open_parenthesis = false
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false
csharp_space_between_square_brackets = false
# C++ Files
[*.{cpp,h,in}]
curly_bracket_next_line = true
indent_brace_style = Allman
# Xml project files
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,nativeproj,locproj}]
indent_size = 2
[*.{csproj,vbproj,proj,nativeproj,locproj}]
charset = utf-8
# Xml build files
[*.builds]
indent_size = 2
# Xml files
[*.{xml,stylecop,resx,ruleset}]
indent_size = 2
# Xml config files
[*.{props,targets,config,nuspec}]
indent_size = 2
# YAML config files
[*.{yml,yaml}]
indent_size = 2
# Shell scripts
[*.sh]
end_of_line = lf
[*.{cmd,bat}]
end_of_line = crlf

View File

@@ -57,9 +57,9 @@
<CourseSettings /> <CourseSettings />
<AssignmentTemplateManagement /> <AssignmentTemplateManagement />
<button class="btn btn-outline-primary" @onclick="planner.SyncWithCanvas"> @* <button class="btn btn-outline-primary" @onclick="planner.SyncWithCanvas">
Sync With Canvas Sync With Canvas
</button> </button> *@
<a class="btn btn-outline-secondary" target="_blank" <a class="btn btn-outline-secondary" target="_blank"
href="@($"{Environment.GetEnvironmentVariable("CANVAS_URL")}/courses/{planner.LocalCourse.Settings.CanvasId}")"> href="@($"{Environment.GetEnvironmentVariable("CANVAS_URL")}/courses/{planner.LocalCourse.Settings.CanvasId}")">
View In Canvas View In Canvas

View File

@@ -83,7 +83,7 @@
private bool isSyncedWithCanvas => planner private bool isSyncedWithCanvas => planner
.CanvasModules? .CanvasModules?
.FirstOrDefault( .FirstOrDefault(
cm => cm.Id == Module.CanvasId cm => cm.Name == Module.Name
) != null; ) != null;
} }

View File

@@ -1,3 +1,4 @@
using CanvasModel.Modules;
using LocalModels; using LocalModels;
using Management.Planner; using Management.Planner;
using Management.Services; using Management.Services;
@@ -39,7 +40,7 @@ public class AssignmentEditorContext
if (planner.LocalCourse != null) if (planner.LocalCourse != null)
{ {
// run discovery on Assignment, it was the last stored version of the assignment // run discovery on Assignment, it was the last stored version of the assignment
var currentModule = getCurrentModule(Assignment, planner.LocalCourse); var currentModule = getCurrentLocalModule(Assignment, planner.LocalCourse);
var updatedModules = planner.LocalCourse.Modules var updatedModules = planner.LocalCourse.Modules
.Select( .Select(
@@ -146,16 +147,11 @@ public class AssignmentEditorContext
canvas: canvas canvas: canvas
); );
var currentModule = getCurrentModule(Assignment, planner.LocalCourse); var canvasModule = getCurrentCanvasModule(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( await canvas.CreateModuleItem(
(ulong)courseCanvasId, (ulong)courseCanvasId,
(ulong)currentModule.CanvasId, canvasModule.Id,
Assignment.Name, Assignment.Name,
"Assignment", "Assignment",
createdAssignmentCanvasId createdAssignmentCanvasId
@@ -163,17 +159,25 @@ public class AssignmentEditorContext
await planner.LocalCourse.Modules.First().SortModuleItems( await planner.LocalCourse.Modules.First().SortModuleItems(
(ulong)courseCanvasId, (ulong)courseCanvasId,
(ulong)currentModule.CanvasId, canvasModule.Id,
canvas canvas
); );
logger.Log($"finished adding assignment {Assignment.Name} to canvas"); logger.Log($"finished adding assignment {Assignment.Name} to canvas");
} }
private static LocalModule getCurrentModule(LocalAssignment assignment, LocalCourse course) private static LocalModule getCurrentLocalModule(LocalAssignment assignment, LocalCourse course)
{ {
return course.Modules.FirstOrDefault( return course.Modules.FirstOrDefault(
m => m.Assignments.Select(a => a.Name).Contains(assignment.Name) m => m.Assignments.Select(a => a.Name).Contains(assignment.Name)
) )
?? throw new Exception("could not find current module in assignment editor context"); ?? throw new Exception("could not find current module in assignment editor context");
} }
private CanvasModule getCurrentCanvasModule(LocalAssignment assignment, LocalCourse course)
{
var localModule = getCurrentLocalModule(assignment, course);
var canvasModule = planner.CanvasModules?.FirstOrDefault(m => m.Name == localModule.Name)
?? throw new Exception($"error in assignment context, canvas module with name {localModule.Name} not found in planner");
return canvasModule;
}
} }

View File

@@ -76,12 +76,12 @@ public class CoursePlanner
public IEnumerable<CanvasAssignmentGroup>? CanvasAssignmentGroups { get; internal set; } public IEnumerable<CanvasAssignmentGroup>? CanvasAssignmentGroups { get; internal set; }
public IEnumerable<CanvasQuiz>? CanvasQuizzes { get; internal set; } public IEnumerable<CanvasQuiz>? CanvasQuizzes { get; internal set; }
public IEnumerable<CanvasModule>? CanvasModules { get; internal set; } public IEnumerable<CanvasModule>? CanvasModules { get; internal set; }
public Dictionary<ulong, IEnumerable<CanvasModuleItem>>? CanvasModulesItems { get; internal set; } public Dictionary<CanvasModule, IEnumerable<CanvasModuleItem>>? CanvasModulesItems { get; internal set; }
public async Task<( public async Task<(
IEnumerable<CanvasAssignment> CanvasAssignments, IEnumerable<CanvasAssignment> CanvasAssignments,
IEnumerable<CanvasModule> CanvasModules, IEnumerable<CanvasModule> CanvasModules,
Dictionary<ulong, IEnumerable<CanvasModuleItem>> CanvasModulesItems, Dictionary<CanvasModule, IEnumerable<CanvasModuleItem>> CanvasModulesItems,
IEnumerable<CanvasQuiz> canvasQuizzes, IEnumerable<CanvasQuiz> canvasQuizzes,
IEnumerable<CanvasAssignmentGroup> canvasAssignmentGroups IEnumerable<CanvasAssignmentGroup> canvasAssignmentGroups
)> LoadCanvasData() )> LoadCanvasData()
@@ -155,12 +155,11 @@ public class CoursePlanner
}; };
var newModules = await LocalCourse.CreateAllModules( await LocalCourse.CreateAllModules(
canvasId, canvasId,
CanvasModules, CanvasModules,
canvas canvas
); );
LocalCourse = LocalCourse with { Modules = newModules };
CanvasModules = await canvas.Modules.GetModules(canvasId); CanvasModules = await canvas.Modules.GetModules(canvasId);
await LocalCourse.SortCanvasModulesByLocalOrder(canvasId, CanvasModules, canvas); await LocalCourse.SortCanvasModulesByLocalOrder(canvasId, CanvasModules, canvas);

View File

@@ -87,7 +87,7 @@ public static class CoursePlannerExtensions
IEnumerable<CanvasQuiz> canvasQuizzes IEnumerable<CanvasQuiz> canvasQuizzes
) )
{ {
var moduleIdInCanvas = canvasModules.FirstOrDefault(m => m.Id == module.CanvasId) != null; var moduleIdInCanvas = canvasModules.FirstOrDefault(m => m.Name == module.Name) != null;
var moduleWithAssignments = module with var moduleWithAssignments = module with
{ {
Assignments = module.Assignments Assignments = module.Assignments
@@ -100,7 +100,7 @@ public static class CoursePlannerExtensions
Console.WriteLine( Console.WriteLine(
$"no id in canvas for module, removing old canvas id: {moduleWithAssignments.Name}" $"no id in canvas for module, removing old canvas id: {moduleWithAssignments.Name}"
); );
return moduleWithAssignments with { CanvasId = null }; return moduleWithAssignments;
} }
return moduleWithAssignments; return moduleWithAssignments;
} }

View File

@@ -1,4 +1,5 @@
using System.Reflection.Metadata.Ecma335; using System.Reflection.Metadata.Ecma335;
using CanvasModel.Modules;
using LocalModels; using LocalModels;
using Management.Planner; using Management.Planner;
using Management.Services; using Management.Services;
@@ -32,7 +33,7 @@ public class QuizEditorContext
{ {
if (_quiz == null && value != null) if (_quiz == null && value != null)
{ {
_module = getCurrentModule(value, planner.LocalCourse); _module = getCurrentLocalModule(value, planner.LocalCourse);
} }
_quiz = value; _quiz = value;
StateHasChanged?.Invoke(); StateHasChanged?.Invoke();
@@ -115,16 +116,11 @@ public class QuizEditorContext
return; return;
} }
var currentModule = getCurrentModule(Quiz, planner.LocalCourse); var canvasModule = getCurrentCanvasModule(Quiz, planner.LocalCourse);
if (currentModule.CanvasId == null)
{
logger.Log("was able to add quiz to canvas, but errored while making module item. module canvasId is null");
return;
}
await canvas.CreateModuleItem( await canvas.CreateModuleItem(
(ulong)courseCanvasId, (ulong)courseCanvasId,
(ulong)currentModule.CanvasId, canvasModule.Id,
Quiz.Name, Quiz.Name,
"Quiz", "Quiz",
(ulong)canvasQuizId (ulong)canvasQuizId
@@ -132,17 +128,25 @@ public class QuizEditorContext
await planner.LocalCourse.Modules.First().SortModuleItems( await planner.LocalCourse.Modules.First().SortModuleItems(
(ulong)courseCanvasId, (ulong)courseCanvasId,
(ulong)currentModule.CanvasId, canvasModule.Id,
canvas canvas
); );
logger.Log($"finished adding quiz {Quiz.Name} to canvas"); logger.Log($"finished adding quiz {Quiz.Name} to canvas");
} }
private static LocalModule getCurrentModule(LocalQuiz quiz, LocalCourse course) private static LocalModule getCurrentLocalModule(LocalQuiz quiz, LocalCourse course)
{ {
return course.Modules.FirstOrDefault( return course.Modules.FirstOrDefault(
m => m.Quizzes.Select(q => q.Name + q.Description).Contains(quiz.Name + quiz.Description) m => m.Quizzes.Select(q => q.Name + q.Description).Contains(quiz.Name + quiz.Description)
) )
?? throw new Exception("could not find current module in quiz editor context"); ?? throw new Exception("could not find current module in quiz editor context");
} }
private CanvasModule getCurrentCanvasModule(LocalQuiz quiz, LocalCourse course)
{
var localModule = getCurrentLocalModule(quiz, course);
var canvasModule = planner.CanvasModules?.FirstOrDefault(m => m.Name == localModule.Name)
?? throw new Exception($"error in quiz context, canvas module with name {localModule.Name} not found in planner");
return canvasModule;
}
} }

View File

@@ -6,7 +6,7 @@ namespace Management.Planner;
public static partial class ModuleSyncronizationExtensions public static partial class ModuleSyncronizationExtensions
{ {
internal static async Task<IEnumerable<LocalModule>> CreateAllModules( internal static async Task CreateAllModules(
this LocalCourse localCourse, this LocalCourse localCourse,
ulong canvasCourseId, ulong canvasCourseId,
IEnumerable<CanvasModule> canvasModules, IEnumerable<CanvasModule> canvasModules,
@@ -15,21 +15,18 @@ public static partial class ModuleSyncronizationExtensions
{ {
var moduleTasks = localCourse.Modules.Select(async module => var moduleTasks = localCourse.Modules.Select(async module =>
{ {
var canvasModule = canvasModules.FirstOrDefault(cm => cm.Id == module.CanvasId); var canvasModule = canvasModules.FirstOrDefault(cm => cm.Name == module.Name);
if (canvasModule == null) if (canvasModule == null)
{ {
var newModule = await canvas.Modules.CreateModule(canvasCourseId, module.Name); var newModule = await canvas.Modules.CreateModule(canvasCourseId, module.Name);
return module with { CanvasId = newModule.Id };
} }
if (canvasModule.Name != module.Name) if (canvasModule?.Name != module.Name) // TODO: maybe check to see if we have name change here
{ {
await canvas.Modules.UpdateModule(canvasCourseId, canvasModule.Id, module.Name, canvasModule.Position); await canvas.Modules.UpdateModule(canvasCourseId, canvasModule.Id, module.Name, canvasModule.Position);
} }
return module;
}); });
var newModules = await Task.WhenAll(moduleTasks); await Task.WhenAll(moduleTasks);
return newModules ?? throw new Exception("Error ensuring all modules exist in canvas");
} }
internal static async Task SortCanvasModulesByLocalOrder( internal static async Task SortCanvasModulesByLocalOrder(
@@ -42,13 +39,14 @@ public static partial class ModuleSyncronizationExtensions
var currentCanvasPositions = canvasModules.ToDictionary(m => m.Id, m => m.Position); var currentCanvasPositions = canvasModules.ToDictionary(m => m.Id, m => m.Position);
foreach (var (localModule, i) in localCourse.Modules.Select((m, i) => (m, i))) foreach (var (localModule, i) in localCourse.Modules.Select((m, i) => (m, i)))
{ {
uint correctPosition = (uint)(i + 1); uint correctPosition = (uint)(i + 1);
var moduleCanvasId = var canvasModule = canvasModules.FirstOrDefault(c => c.Name == localModule.Name) ?? throw new Exception($"error sorting canvas module, could not find canvas module with name {localModule.Name}"); ;
localModule.CanvasId ?? throw new Exception("cannot sort module if no module canvas id");
var currentCanvasPosition = currentCanvasPositions[moduleCanvasId]; var currentCanvasPosition = currentCanvasPositions[canvasModule.Id];
if (currentCanvasPosition != correctPosition) if (currentCanvasPosition != correctPosition)
{ {
await canvas.Modules.UpdateModule(canvasId, moduleCanvasId, localModule.Name, correctPosition); await canvas.Modules.UpdateModule(canvasId, canvasModule.Id, localModule.Name, correctPosition);
} }
} }
} }
@@ -59,15 +57,15 @@ public static partial class ModuleSyncronizationExtensions
CanvasService canvas CanvasService canvas
) )
{ {
var canvasModules = await canvas.Modules.GetModules(canvasId); // var canvasModules = await canvas.Modules.GetModules(canvasId);
return localCourse with return localCourse;
{ // {
Modules = localCourse.Modules.Select(m => // Modules = localCourse.Modules.Select(m =>
{ // {
var canvasModule = canvasModules.FirstOrDefault(cm => cm.Name == m.Name); // var canvasModule = canvasModules.FirstOrDefault(cm => cm.Name == m.Name);
return canvasModule == null ? m : m with { CanvasId = canvasModule.Id }; // return canvasModule == null ? m : m with { CanvasId = canvasModule.Id };
}) // })
}; // };
} }
public static async Task SortModuleItems( public static async Task SortModuleItems(
@@ -112,15 +110,15 @@ public static partial class ModuleSyncronizationExtensions
internal static async Task<bool> EnsureAllModulesItemsCreated( internal static async Task<bool> EnsureAllModulesItemsCreated(
this LocalModule localModule, this LocalModule localModule,
ulong canvasId, ulong canvasId,
ulong moduleCanvasId, CanvasModule canvasModule,
Dictionary<ulong, IEnumerable<CanvasModuleItem>> canvasModulesItems, Dictionary<CanvasModule, IEnumerable<CanvasModuleItem>> canvasModulesItems,
CanvasService canvas CanvasService canvas
) )
{ {
var anyUpdated = false; var anyUpdated = false;
foreach (var localAssignment in localModule.Assignments.Where(a => a.DueAt > DateTime.Now)) foreach (var localAssignment in localModule.Assignments.Where(a => a.DueAt > DateTime.Now))
{ {
var canvasModuleItemContentIds = canvasModulesItems[moduleCanvasId].Select(i => i.ContentId); var canvasModuleItemContentIds = canvasModulesItems[canvasModule].Select(i => i.ContentId);
if (!canvasModuleItemContentIds.Contains(localAssignment.CanvasId)) if (!canvasModuleItemContentIds.Contains(localAssignment.CanvasId))
{ {
var canvasAssignmentId = var canvasAssignmentId =
@@ -128,7 +126,7 @@ public static partial class ModuleSyncronizationExtensions
?? throw new Exception("cannot create module item if assignment does not have canvas id"); ?? throw new Exception("cannot create module item if assignment does not have canvas id");
await canvas.CreateModuleItem( await canvas.CreateModuleItem(
canvasId, canvasId,
moduleCanvasId, canvasModule.Id,
localAssignment.Name, localAssignment.Name,
"Assignment", "Assignment",
canvasAssignmentId canvasAssignmentId
@@ -142,29 +140,34 @@ public static partial class ModuleSyncronizationExtensions
internal static async Task SyncModuleItemsWithCanvas( internal static async Task SyncModuleItemsWithCanvas(
this LocalCourse localCourse, this LocalCourse localCourse,
ulong canvasId, ulong courseCanvasId,
Dictionary<ulong, IEnumerable<CanvasModuleItem>> canvasModulesItems, Dictionary<CanvasModule, IEnumerable<CanvasModuleItem>> canvasModulesItems,
CanvasService canvas CanvasService canvas
) )
{ {
foreach (var localModule in localCourse.Modules) foreach (var localModule in localCourse.Modules)
{ {
var moduleCanvasId = // var moduleCanvasId =
localModule.CanvasId // localModule.CanvasId
?? throw new Exception("cannot sync canvas modules items if module not synced with canvas"); // ?? throw new Exception("cannot sync canvas modules items if module not synced with canvas");
var canvasModule = canvasModulesItems.Keys.FirstOrDefault(k => k.Name == localModule.Name);
if(canvasModule == null)
{
throw new Exception($"cannot sync module items in canvas, could not find module with name ${localModule.Name}");
}
bool anyUpdated = await localModule.EnsureAllModulesItemsCreated( bool anyUpdated = await localModule.EnsureAllModulesItemsCreated(
canvasId, courseCanvasId,
moduleCanvasId, canvasModule,
canvasModulesItems, canvasModulesItems,
canvas canvas
); );
var canvasModuleItems = anyUpdated var canvasModuleItems = anyUpdated
? await canvas.Modules.GetModuleItems(canvasId, moduleCanvasId) ? await canvas.Modules.GetModuleItems(courseCanvasId, canvasModule.Id)
: canvasModulesItems[moduleCanvasId]; : canvasModulesItems[canvasModule];
await localModule.SortModuleItems(canvasId, moduleCanvasId, canvas); await localModule.SortModuleItems(courseCanvasId, canvasModule.Id, canvas);
} }
} }
} }

View File

@@ -27,6 +27,16 @@ public record LocalCourseSettings
var yaml = serializer.Serialize(this); var yaml = serializer.Serialize(this);
return yaml; return yaml;
} }
public static LocalCourseSettings ParseYaml(string rawText)
{
var deserializer = new DeserializerBuilder()
.IgnoreUnmatchedProperties()
.Build();
var settings = deserializer.Deserialize<LocalCourseSettings>(rawText);
return settings;
}
} }
public record SimpleTimeOnly public record SimpleTimeOnly

View File

@@ -4,7 +4,7 @@ public record LocalModule
{ {
public string Name { get; init; } = string.Empty; public string Name { get; init; } = string.Empty;
public string Id { get; init; } = DateTime.UtcNow.Ticks.ToString(); public string Id { get; init; } = DateTime.UtcNow.Ticks.ToString();
public ulong? CanvasId { get; set; } = null; // public ulong? CanvasId { get; set; } = null;
public string Notes { get; set; } = string.Empty; public string Notes { get; set; } = string.Empty;
public IEnumerable<LocalAssignment> Assignments { get; init; } = public IEnumerable<LocalAssignment> Assignments { get; init; } =
Enumerable.Empty<LocalAssignment>(); Enumerable.Empty<LocalAssignment>();

View File

@@ -65,7 +65,7 @@ public class CanvasModuleService
return items; return items;
} }
public async Task<Dictionary<ulong, IEnumerable<CanvasModuleItem>>> GetAllModulesItems( public async Task<Dictionary<CanvasModule, IEnumerable<CanvasModuleItem>>> GetAllModulesItems(
ulong courseId, ulong courseId,
IEnumerable<CanvasModule> modules IEnumerable<CanvasModule> modules
) )
@@ -78,7 +78,7 @@ public class CanvasModuleService
} }
); );
var output = new Dictionary<ulong, IEnumerable<CanvasModuleItem>>(); var output = new Dictionary<CanvasModule, IEnumerable<CanvasModuleItem>>();
var itemTasksResult = await Task.WhenAll(itemsTasks); var itemTasksResult = await Task.WhenAll(itemsTasks);
foreach (var (module, items) in itemTasksResult) foreach (var (module, items) in itemTasksResult)
{ {
@@ -86,7 +86,7 @@ public class CanvasModuleService
throw new Exception( throw new Exception(
"i'm not sure how we got here, but module and items are null after looking up module items" "i'm not sure how we got here, but module and items are null after looking up module items"
); );
output[module.Id] = items; output[module] = items;
} }
return output; return output;
} }

View File

@@ -1,27 +1,18 @@
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
using CanvasModel.Quizzes; using CanvasModel.Quizzes;
using LocalModels; using LocalModels;
using RestSharp; using RestSharp;
namespace Management.Services.Canvas; namespace Management.Services.Canvas;
public class CanvasQuizService public class CanvasQuizService(
IWebRequestor webRequestor,
CanvasServiceUtils utils,
CanvasAssignmentService assignments
)
{ {
private readonly IWebRequestor webRequestor; private readonly IWebRequestor webRequestor = webRequestor;
private readonly CanvasServiceUtils utils; private readonly CanvasServiceUtils utils = utils;
private readonly CanvasAssignmentService assignments; private readonly CanvasAssignmentService assignments = assignments;
public CanvasQuizService(
IWebRequestor webRequestor,
CanvasServiceUtils utils,
CanvasAssignmentService assignments
)
{
this.webRequestor = webRequestor;
this.utils = utils;
this.assignments = assignments;
}
public async Task<IEnumerable<CanvasQuiz>> GetAll(ulong courseId) public async Task<IEnumerable<CanvasQuiz>> GetAll(ulong courseId)
{ {

View File

@@ -6,9 +6,12 @@ using YamlDotNet.Serialization.NamingConventions;
public class FileStorageManager public class FileStorageManager
{ {
private readonly MyLogger<FileStorageManager> logger; private readonly MyLogger<FileStorageManager> logger;
private static readonly string _basePath = "../storage";
public FileStorageManager(MyLogger<FileStorageManager> logger) public FileStorageManager(MyLogger<FileStorageManager> logger)
{ {
if (!Directory.Exists(_basePath))
throw new Exception("storage folder not found");
this.logger = logger; this.logger = logger;
} }
public string CourseToYaml(LocalCourse course) public string CourseToYaml(LocalCourse course)
@@ -32,18 +35,18 @@ public class FileStorageManager
{ {
var courseString = CourseToYaml(course); var courseString = CourseToYaml(course);
var courseDirectory = $"../storage/{course.Settings.Name}"; var courseDirectory = $"{_basePath}/{course.Settings.Name}";
if (!Directory.Exists(courseDirectory)) if (!Directory.Exists(courseDirectory))
Directory.CreateDirectory(courseDirectory); Directory.CreateDirectory(courseDirectory);
await saveModules(course); await saveModules(course);
await File.WriteAllTextAsync($"../storage/{course.Settings.Name}.yml", courseString); await File.WriteAllTextAsync($"{_basePath}/{course.Settings.Name}.yml", courseString);
} }
private async Task saveModules(LocalCourse course) private async Task saveModules(LocalCourse course)
{ {
var courseDirectory = $"../storage/{course.Settings.Name}"; var courseDirectory = $"{_basePath}/{course.Settings.Name}";
await saveSettings(course, courseDirectory); await saveSettings(course, courseDirectory);
foreach (var module in course.Modules) foreach (var module in course.Modules)
@@ -67,7 +70,7 @@ public class FileStorageManager
private async Task saveQuizzes(LocalCourse course, LocalModule module) private async Task saveQuizzes(LocalCourse course, LocalModule module)
{ {
var quizzesDirectory = $"../storage/{course.Settings.Name}/{module.Name}/quizzes"; var quizzesDirectory = $"{_basePath}/{course.Settings.Name}/{module.Name}/quizzes";
if (!Directory.Exists(quizzesDirectory)) if (!Directory.Exists(quizzesDirectory))
Directory.CreateDirectory(quizzesDirectory); Directory.CreateDirectory(quizzesDirectory);
@@ -106,7 +109,7 @@ public class FileStorageManager
private async Task saveAssignments(LocalCourse course, LocalModule module) private async Task saveAssignments(LocalCourse course, LocalModule module)
{ {
var assignmentsDirectory = $"../storage/{course.Settings.Name}/{module.Name}/assignments"; var assignmentsDirectory = $"{_basePath}/{course.Settings.Name}/{module.Name}/assignments";
if (!Directory.Exists(assignmentsDirectory)) if (!Directory.Exists(assignmentsDirectory))
Directory.CreateDirectory(assignmentsDirectory); Directory.CreateDirectory(assignmentsDirectory);
@@ -139,22 +142,83 @@ public class FileStorageManager
logger.Log($"removing old assignment, it has probably been renamed {file}"); logger.Log($"removing old assignment, it has probably been renamed {file}");
File.Delete(file); File.Delete(file);
} }
} }
public async Task<IEnumerable<LocalCourse>> LoadSavedCourses() public async Task<IEnumerable<LocalCourse>> LoadSavedCourses()
{ {
string path = "../storage/";
if (!Directory.Exists(path))
throw new Exception("storage folder not found");
var fileNames = Directory.GetFiles(path); var fileNames = Directory.GetFiles(_basePath);
var courses = await Task.WhenAll( var courses = await Task.WhenAll(
fileNames fileNames
.Where(name => name.EndsWith(".yml")) .Where(name => name.EndsWith(".yml"))
.Select(async n => ParseCourse(await File.ReadAllTextAsync($"../storage/{n}"))) .Select(async n => ParseCourse(await File.ReadAllTextAsync($"{_basePath}/{n}")))
); );
return courses; return courses;
} }
// public async Task<LocalCourse> LoadCourseByName(string courseName)
// {
// var courseDirectory = $"{_basePath}/{courseName}";
// if (!Directory.Exists(courseDirectory))
// {
// var errorMessage = $"error loading course by name, could not find folder {courseDirectory}";
// logger.Log(errorMessage);
// throw new LoadCourseFromFileException(errorMessage);
// }
// var settingsPath = $"{courseDirectory}/settings.yml";
// if (!Directory.Exists(settingsPath))
// {
// var errorMessage = $"error loading course by name, settings file {settingsPath}";
// logger.Log(errorMessage);
// throw new LoadCourseFromFileException(errorMessage);
// }
// var settingsString = await File.ReadAllTextAsync(settingsPath);
// var settings = LocalCourseSettings.ParseYaml(settingsString);
// var modulePaths = Directory.GetDirectories(courseDirectory);
// var modules = modulePaths
// .Select(LoadModuleFromPath)
// .ToArray();
// }
// public async Task<LocalModule> LoadModuleFromPath(string modulePath)
// {
// var assignmentsPath = $"{modulePath}/assignments";
// if (!Directory.Exists(assignmentsPath))
// {
// var errorMessage = $"error loading course by name, assignments folder does not exist in {modulePath}";
// logger.Log(errorMessage);
// throw new LoadCourseFromFileException(errorMessage);
// }
// var quizzesPath = $"{modulePath}/quizzes";
// if (!Directory.Exists(quizzesPath))
// {
// var errorMessage = $"error loading course by name, quizzes folder does not exist in {modulePath}";
// logger.Log(errorMessage);
// throw new LoadCourseFromFileException(errorMessage);
// }
// var assignments = LoadAssignmentsFromPath(assignmentsPath);
// var quizzes = LoadQuizzesFromPath(quizzesPath);
// }
// public async Task<IEnumerable<LocalAssignment>> LoadAssignmentsFromPath(string assignmentsFolder)
// {
// }
// public async Task<IEnumerable<LocalAssignment>> LoadQuizzesFromPath(string quizzesFolder)
// {
// }
} }
public class LoadCourseFromFileException(string message) : Exception(message)
{
}