Skip to content

Commit

Permalink
🚸 Set user function in calender description
Browse files Browse the repository at this point in the history
  • Loading branch information
TDroogers committed Sep 21, 2024
1 parent d83f95b commit 9b71c25
Show file tree
Hide file tree
Showing 10 changed files with 102 additions and 31 deletions.
54 changes: 37 additions & 17 deletions src/Server/Controllers/ScheduleController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
using Microsoft.Identity.Web.Resource;
using System.Diagnostics;
using System.Security.Claims;
using System.Text;
using System.Text.Json;
using Drogecode.Knrm.Oefenrooster.Shared.Models.Function;

namespace Drogecode.Knrm.Oefenrooster.Server.Controllers;

Expand All @@ -29,6 +31,7 @@ public class ScheduleController : ControllerBase
private readonly IUserSettingService _userSettingService;
private readonly IDateTimeService _dateTimeService;
private readonly IUserService _userService;
private readonly IFunctionService _functionService;

public ScheduleController(
RefreshHub refreshHub,
Expand All @@ -39,7 +42,8 @@ public ScheduleController(
ITrainingTypesService trainingTypesService,
IUserSettingService userSettingService,
IDateTimeService dateTimeService,
IUserService userService)
IUserService userService,
IFunctionService functionService)
{
_refreshHub = refreshHub;
_logger = logger;
Expand All @@ -50,6 +54,7 @@ public ScheduleController(
_userSettingService = userSettingService;
_dateTimeService = dateTimeService;
_userService = userService;
_functionService = functionService;
}

[HttpGet]
Expand Down Expand Up @@ -204,30 +209,35 @@ private async Task PatchTrainingCalenderUsers(Guid trainingId, Guid customerId,
clt.ThrowIfCancellationRequested();

_graphService.InitializeGraph();
var text = GetTrainingCalenderText(training.Training?.TrainingTypeName, training.Training?.Name);
if (training.Training?.PlanUsers.Count > 0)
{
foreach (var user in training.Training.PlanUsers)
{
await _refreshHub.SendMessage(user.UserId, ItemUpdated.FutureTrainings);
if (!string.IsNullOrEmpty(user.CalendarEventId))
{
DrogeFunction? function = null;
if (user.PlannedFunctionId is not null && user.UserFunctionId is not null && user.UserFunctionId != user.PlannedFunctionId)
function = await _functionService.GetById(customerId, user.PlannedFunctionId.Value, clt);
var text = GetTrainingCalenderText(training.Training.TrainingTypeName, training.Training.Name, function?.Name);
await _graphService.PatchCalender(user.UserId, user.CalendarEventId, text, training.Training.DateStart, training.Training.DateEnd, !training.Training.ShowTime);
}
}
}
}

private static string GetTrainingCalenderText(string? trainingTypeName, string? trainingName)
private static string GetTrainingCalenderText(string? trainingTypeName, string? trainingName, string? functionName)
{
var text = string.Empty;
var text = new StringBuilder();
if (!string.IsNullOrEmpty(trainingTypeName))
text += trainingTypeName;
text.Append(trainingTypeName);
if (!string.IsNullOrEmpty(trainingTypeName) && !string.IsNullOrEmpty(trainingName))
text += " - ";
text.Append(" - ");
if (!string.IsNullOrEmpty(trainingName))
text += trainingName;
return text;
text.Append(trainingName);
if (!string.IsNullOrEmpty(functionName))
text.Append(" - ").Append(functionName);
return text.ToString();
}

[HttpPost]
Expand Down Expand Up @@ -301,21 +311,26 @@ public async Task<ActionResult<PatchAssignedUserResponse>> PatchAssignedUser([Fr
await _auditService.Log(userId, AuditType.PatchAssignedUser, customerId,
JsonSerializer.Serialize(new AuditAssignedUser
{
UserId = body.User?.UserId, Assigned = body.User?.Assigned, Availability = result.Availability, SetBy = result.SetBy,
UserId = body.User?.UserId, Assigned = body.User?.Assigned, Availability = result?.Availability, SetBy = result?.SetBy,
AuditReason = body.AuditReason ?? AuditReason.Assigned, // body.AuditReason was added in v0.3.81
VehicleId = body.AuditReason == AuditReason.ChangeVehicle ? body.User?.VehicleId : null,
FunctionId = body.AuditReason == AuditReason.ChangedFunction ? body.User?.PlannedFunctionId : null
}),
body.TrainingId);
await _userService.PatchLastOnline(userId, clt);
if (result.Success && body.User?.UserId is not null)
if (result?.Success == true && body.User?.UserId is not null)
{
clt = CancellationToken.None;
await ToOutlookCalendar(body.User.UserId, body.TrainingId, body.User.Assigned, body.Training, userId, customerId, result.AvailableId, result.CalendarEventId, clt);
DrogeFunction? function = null;
if (body.User.PlannedFunctionId is not null && body.User.UserFunctionId is not null && body.User.UserFunctionId != body.User.PlannedFunctionId)
function = await _functionService.GetById(customerId, body.User.PlannedFunctionId.Value, clt);
await ToOutlookCalendar(body.User.UserId, body.TrainingId, body.User.Assigned, body.Training, userId, customerId, result.AvailableId, result.CalendarEventId, function?.Name, clt);
await _refreshHub.SendMessage(body.User.UserId, ItemUpdated.FutureTrainings);
}

return result;
if (result is not null)
return result;
return BadRequest();
}
catch (OperationCanceledException)
{
Expand Down Expand Up @@ -351,7 +366,11 @@ await _auditService.Log(userId, AuditType.PatchAssignedUser, customerId,
if (result.Success && body.UserId is not null)
{
clt = CancellationToken.None;
await ToOutlookCalendar(body.UserId.Value, body.TrainingId, body.Assigned, body.Training, userId, customerId, result.AvailableId, result.CalendarEventId, clt);
var user = await _userService.GetUserById(body.UserId.Value, clt);
DrogeFunction? function = null;
if (body.Training?.PlannedFunctionId is not null && user?.UserFunctionId is not null && user.UserFunctionId != body.Training.PlannedFunctionId)
function = await _functionService.GetById(customerId, body.Training.PlannedFunctionId.Value, clt);
await ToOutlookCalendar(body.UserId.Value, body.TrainingId, body.Assigned, body.Training, userId, customerId, result.AvailableId, result.CalendarEventId, function?.Name, clt);
await _refreshHub.SendMessage(body.UserId.Value, ItemUpdated.FutureTrainings);
}

Expand Down Expand Up @@ -495,7 +514,7 @@ public async Task<ActionResult<bool>> DeleteTraining(Guid id, CancellationToken
}

private async Task ToOutlookCalendar(Guid planUserId, Guid? trainingId, bool assigned, TrainingAdvance? training, Guid currentUserId, Guid customerId, Guid? availableId, string? calendarEventId,
CancellationToken clt)
string? functionName, CancellationToken clt)
{
try
{
Expand All @@ -508,7 +527,7 @@ private async Task ToOutlookCalendar(Guid planUserId, Guid? trainingId, bool ass
if (training is null && trainingId is not null)
training = (await _scheduleService.GetTrainingById(planUserId, customerId, trainingId.Value, clt)).Training;
var type = await _trainingTypesService.GetById(training?.RoosterTrainingTypeId ?? Guid.Empty, customerId, clt);
var text = GetTrainingCalenderText(type.TrainingType?.Name, training?.Name);
var text = GetTrainingCalenderText(type.TrainingType?.Name, training?.Name, functionName);
if (training is null)
{
_logger.LogWarning("Failed to set a training for trainingId {trainingId}", trainingId);
Expand All @@ -532,8 +551,6 @@ private async Task ToOutlookCalendar(Guid planUserId, Guid? trainingId, bool ass
else
{
await _graphService.PatchCalender(planUserId, calendarEventId, text, training.DateStart, training.DateEnd, !training.ShowTime);
await _auditService.Log(currentUserId, AuditType.PatchTraining, customerId,
$"Preventing duplicate event '{type.TrainingType?.Name}' on '{training.DateStart.ToString("o")}' : '{training.DateEnd.ToString("o")}'");
}
}
else if (!string.IsNullOrEmpty(calendarEventId))
Expand All @@ -545,6 +562,9 @@ await _auditService.Log(currentUserId, AuditType.PatchTraining, customerId,
}
catch (Exception ex)
{
#if DEBUG
Debugger.Break();
#endif
_logger.LogError(ex, "Exception in ToOutlookCalendar {customerId} {planUserId} {trainingId} {assigned} {currentUserId} {availableId} {calendarEventId} and training is {trainingNullOrNot}",
customerId, planUserId, trainingId, assigned, currentUserId, availableId, calendarEventId, training is null ? "null" : "not null");
}
Expand Down
6 changes: 3 additions & 3 deletions src/Server/Controllers/UserController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public async Task<ActionResult<GetDrogeUserResponse>> GetCurrentUser(Cancellatio
var userName = User?.FindFirstValue("FullName") ?? throw new Exception("No userName found");
var userEmail = User?.FindFirstValue(ClaimTypes.Name) ?? throw new Exception("No userEmail found");
var customerId = new Guid(User?.FindFirstValue("http://schemas.microsoft.com/identity/claims/tenantid") ?? throw new DrogeCodeNullException("customerId not found"));
var result = await _userService.GetOrSetUserFromDb(userId, userName, userEmail, customerId, true);
var result = await _userService.GetOrSetUserById(userId, userName, userEmail, customerId, true);

return new GetDrogeUserResponse { DrogeUser = result };
}
Expand All @@ -88,7 +88,7 @@ public async Task<ActionResult<GetByIdResponse>> GetById(Guid id, CancellationTo
{
try
{
var result = await _userService.GetUserFromDb(id);
var result = await _userService.GetUserById(id, clt);
return new GetByIdResponse { User = result, Success = true };
}
catch (Exception ex)
Expand Down Expand Up @@ -190,7 +190,7 @@ public async Task<ActionResult<SyncAllUsersResponse>> SyncAllUsers(CancellationT
var index = existingUsers.FindIndex(x => x.Id == id);
if (index != -1)
existingUsers.RemoveAt(index);
var newUserResponse = await _userService.GetOrSetUserFromDb(id, user.DisplayName, user.Mail ?? "not set", customerId, false);
var newUserResponse = await _userService.GetOrSetUserById(id, user.DisplayName, user.Mail ?? "not set", customerId, false);
if (newUserResponse is null)
continue;
newUserResponse.SyncedFromSharePoint = true;
Expand Down
22 changes: 22 additions & 0 deletions src/Server/Mappers/FunctionMapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Drogecode.Knrm.Oefenrooster.Server.Database.Models;
using Drogecode.Knrm.Oefenrooster.Shared.Models.Function;

namespace Drogecode.Knrm.Oefenrooster.Server.Mappers;

public static class FunctionMapper
{
public static DrogeFunction ToDrogeFunction(this DbUserFunctions function)
{
return new DrogeFunction
{
Id = function.Id,
RoleId = function.RoleId,
Name = function.Name,
Order = function.Order,
TrainingTarget = function.TrainingTarget,
TrainingOnly = function.TrainingOnly,
Default = function.IsDefault,
Active = function.IsActive,
};
}
}
1 change: 1 addition & 0 deletions src/Server/Mappers/PreComMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public static DbPreComForward ToDb(this PreComForward forward, Guid customerId,
CreatedBy = forward.CreatedBy,
};
}

public static PreComForward ToPreComForward(this DbPreComForward dbForward)
{
return new PreComForward
Expand Down
27 changes: 25 additions & 2 deletions src/Server/Services/FunctionService.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,37 @@
using Drogecode.Knrm.Oefenrooster.Shared.Models.Function;
using System.Diagnostics;
using Drogecode.Knrm.Oefenrooster.Server.Mappers;
using Microsoft.Extensions.Caching.Memory;

namespace Drogecode.Knrm.Oefenrooster.Server.Services;

public class FunctionService : IFunctionService
{
private const string FUNC_BY_ID = "func_{0}";

private readonly ILogger<FunctionService> _logger;
private readonly Database.DataContext _database;
public FunctionService(ILogger<FunctionService> logger, Database.DataContext database)
private readonly IMemoryCache _memoryCache;

public FunctionService(ILogger<FunctionService> logger, Database.DataContext database, IMemoryCache memoryCache)
{
_logger = logger;
_database = database;
_memoryCache = memoryCache;
}

public async Task<DrogeFunction?> GetById(Guid customerId, Guid functionId, CancellationToken clt)
{
var memoryKey = string.Format(FUNC_BY_ID, functionId);
var function = _memoryCache.Get<DrogeFunction>(memoryKey);
if (function is not null)
return function;
function = await _database.UserFunctions.Where(x => x.CustomerId == customerId && x.Id == functionId).Select(x => x.ToDrogeFunction()).FirstOrDefaultAsync(clt);
var cacheOptions = new MemoryCacheEntryOptions();
cacheOptions.SetSlidingExpiration(TimeSpan.FromSeconds(10));
cacheOptions.SetAbsoluteExpiration(TimeSpan.FromMinutes(1));
_memoryCache.Set(memoryKey, function, cacheOptions);
return function;
}

public async Task<AddFunctionResponse> AddFunction(DrogeFunction function, Guid customerId, CancellationToken clt)
Expand All @@ -25,6 +46,7 @@ public async Task<AddFunctionResponse> AddFunction(DrogeFunction function, Guid
if (dbFunction.Order > order)
order = dbFunction.Order;
}

order += 10;
_database.UserFunctions.Add(new Database.Models.DbUserFunctions
{
Expand Down Expand Up @@ -67,9 +89,10 @@ public async Task<MultipleFunctionsResponse> GetAllFunctions(Guid customerId, Ca
Active = function.IsActive,
});
}

result.Success = true;
sw.Stop();
result.ElapsedMilliseconds = sw.ElapsedMilliseconds;
return result;
}
}
}
1 change: 1 addition & 0 deletions src/Server/Services/Interfaces/IFunctionService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ namespace Drogecode.Knrm.Oefenrooster.Server.Services.Interfaces;

public interface IFunctionService
{
Task<DrogeFunction?> GetById(Guid customerId, Guid functionId, CancellationToken clt);
Task<AddFunctionResponse> AddFunction(DrogeFunction function, Guid customerId, CancellationToken clt);
Task<MultipleFunctionsResponse> GetAllFunctions(Guid customerId, CancellationToken clt);
}
2 changes: 1 addition & 1 deletion src/Server/Services/Interfaces/IScheduleService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public interface IScheduleService
Task<GetPlannedTrainingResponse> GetPlannedTrainingById(Guid customerId, Guid trainingId, CancellationToken clt);
Task<GetPlannedTrainingResponse> GetPlannedTrainingForDefaultDate(Guid customerId, DateTime date, Guid defaultId, CancellationToken token);
Task<PatchScheduleForUserResponse> PatchScheduleForUserAsync(Guid userId, Guid customerId, Training training, CancellationToken clt);
Task<PatchAssignedUserResponse> PatchAssignedUserAsync(Guid userId, Guid customerId, PatchAssignedUserRequest body, CancellationToken clt);
Task<PatchAssignedUserResponse?> PatchAssignedUserAsync(Guid userId, Guid customerId, PatchAssignedUserRequest body, CancellationToken clt);
Task<PatchTrainingResponse> PatchTraining(Guid customerId, PlannedTraining training, bool inRoleEditPast, CancellationToken clt);
Task<AddTrainingResponse> AddTrainingAsync(Guid customerId, PlannedTraining training, Guid trainingId, CancellationToken clt);
Task<GetScheduledTrainingsForUserResponse> GetScheduledTrainingsForUser(Guid userId, Guid customerId, DateTime? fromDate, int take, int skip, OrderAscDesc order, CancellationToken clt);
Expand Down
4 changes: 2 additions & 2 deletions src/Server/Services/Interfaces/IUserService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ namespace Drogecode.Knrm.Oefenrooster.Server.Services.Interfaces;
public interface IUserService
{
Task<MultipleDrogeUsersResponse> GetAllUsers(Guid customerId, bool includeHidden, bool includeLastLogin, CancellationToken clt);
Task<DrogeUser?> GetUserFromDb(Guid userId);
Task<DrogeUser?> GetOrSetUserFromDb(Guid userId, string userName, string userEmail, Guid customerId, bool setLastOnline);
Task<DrogeUser?> GetUserById(Guid userId, CancellationToken clt);
Task<DrogeUser?> GetOrSetUserById(Guid userId, string userName, string userEmail, Guid customerId, bool setLastOnline);
Task<AddUserResponse> AddUser(DrogeUser user, Guid customerId);
Task<bool> UpdateUser(DrogeUser user, Guid userId, Guid customerId);
Task<UpdateLinkUserUserForUserResponse> UpdateLinkUserUserForUser(UpdateLinkUserUserForUserRequest body, Guid userId, Guid customerId, CancellationToken clt);
Expand Down
10 changes: 7 additions & 3 deletions src/Server/Services/ScheduleService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -777,10 +777,12 @@ private async Task<GetPlannedTrainingResponse> dDbTrainingToGetPlannedTrainingRe
return result;
}

public async Task<PatchAssignedUserResponse> PatchAssignedUserAsync(Guid userId, Guid customerId, PatchAssignedUserRequest body, CancellationToken clt)
public async Task<PatchAssignedUserResponse?> PatchAssignedUserAsync(Guid userId, Guid customerId, PatchAssignedUserRequest body, CancellationToken clt)
{
var result = new PatchAssignedUserResponse();
result.IdPatched = body.TrainingId;
var result = new PatchAssignedUserResponse
{
IdPatched = body.TrainingId
};
if (body.User == null)
{
_logger.LogWarning("user is null {UserIsNull}", body.User == null);
Expand Down Expand Up @@ -831,6 +833,8 @@ public async Task<PatchAssignedUserResponse> PatchAssignedUserAsync(Guid userId,
ava.Assigned = body.User.Assigned;
ava.UserFunctionId = body.User.PlannedFunctionId;
ava.VehicleId = body.User.VehicleId;
clt.ThrowIfCancellationRequested();
clt = CancellationToken.None;
_database.RoosterAvailables.Update(ava);
await _database.SaveChangesAsync(clt);
result.Success = true;
Expand Down
6 changes: 3 additions & 3 deletions src/Server/Services/UserService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,18 @@ public async Task<MultipleDrogeUsersResponse> GetAllUsers(Guid customerId, bool
return result;
}

public async Task<DrogeUser?> GetUserFromDb(Guid userId)
public async Task<DrogeUser?> GetUserById(Guid userId, CancellationToken clt)
{
var userObj = await _database.Users
.Include(x => x.LinkedUserAsA!.Where(y => y.DeletedOn == null))
.Include(x => x.LinkedUserAsB!.Where(y => y.DeletedOn == null))
.Where(u => u.Id == userId && u.DeletedOn == null)
.AsNoTracking()
.FirstOrDefaultAsync();
.FirstOrDefaultAsync(clt);
return userObj?.ToSharedUser(false);
}

public async Task<DrogeUser?> GetOrSetUserFromDb(Guid userId, string userName, string userEmail, Guid customerId, bool setLastOnline)
public async Task<DrogeUser?> GetOrSetUserById(Guid userId, string userName, string userEmail, Guid customerId, bool setLastOnline)
{
var userObj = _database.Users.FirstOrDefault(u => u.Id == userId);
if (userObj is null)
Expand Down

0 comments on commit 9b71c25

Please sign in to comment.