public static ApiGeoTask ToApiGeoTask(this GeoTask from) { if (from is null) { return(null); } var to = new ApiGeoTask { Description = from.Description, Id = from.Id, PlanFinishAt = from.PlanFinishAt, PlanStartAt = from.PlanStartAt, ProjectId = from.ProjectId, ResponsibleActor = from.ResponsibleActor.ToApiActor(), Title = from.Title, CreatedAt = from.CreatedAt, CreatedBy = from.CreatedBy.ToApiActor(), IsArchived = from.IsArchived, Status = from.Status, StatusChangedAt = from.StatusChangedAt }; to.AssistentActors.AddRange(from.AssistentActors.Select(x => x.ToApiActor())); to.GeosIds.AddRange(from.GeosIds); to.History.AddRange(from.History.Select(x => x.ToApiGeoTaskHistory())); to.ObserverActors.AddRange(from.ObserverActors.Select(x => x.ToApiActor())); return(to); }
public static Dictionary <string, object> ToDictionary (this GeoTask from) { if (from is null) { return(null); } return(new Dictionary <string, object> { { nameof(from.AssistentActors), String.Join(',', from.AssistentActors.Select(x => x.Id)) }, { nameof(from.CreatedAt), from.CreatedAt }, { nameof(from.CreatedBy), String.Join(',', from.CreatedBy .ToDictionary() .Select(x => $"{x.Key}={x.Value}")) }, { nameof(from.Description), from.Description }, { nameof(from.GeosIds), String.Join(',', from.GeosIds) }, { nameof(from.History), String.Join(',', from.History.Select(x => x.Id)) }, { nameof(from.Id), from.Id }, { nameof(from.IsArchived), from.IsArchived }, { nameof(from.ObserverActors), String.Join(',', from.ObserverActors.Select(x => x.Id)) }, { nameof(from.PlanFinishAt), from.PlanFinishAt }, { nameof(from.PlanStartAt), from.PlanStartAt }, { nameof(from.ProjectId), from.ProjectId }, { nameof(from.ResponsibleActor), from.ResponsibleActor?.Id }, { nameof(from.Status), from.Status?.Id }, { nameof(from.StatusChangedAt), from.StatusChangedAt }, { nameof(from.Title), from.Title }, }); }
public static DbGeoTask ToDbGeoTask(this GeoTask from) { if (from is null) { return(null); } var to = new DbGeoTask { CreatedAt = from.CreatedAt, Description = from.Description, CreatedById = from.CreatedBy?.Id, Id = from.Id, IsArchived = from.IsArchived, PlanFinishAt = from.PlanFinishAt, PlanStartAt = from.PlanStartAt, ProjectId = from.ProjectId, Status = from.Status, ResponsibleActorId = from.ResponsibleActor?.Id, StatusChangedAt = from.StatusChangedAt, Title = from.Title }; to.AssistentActorsIds.AddRange (from.AssistentActors.Select(x => x.Id)); to.GeosIds.AddRange(from.GeosIds); to.History.AddRange(from.History); to.ObserverActorsIds.AddRange (from.ObserverActors.Select(x => x.Id)); return(to); }
private async Task <CreateResult> CheckPermission(GeoTask task, Actor actor, Project project) { ActorRole currentActorProjectRole = null; if (project != null && actor != null) { project.ProjectActorRoles? .TryGetValue(actor.Id, out currentActorProjectRole); } var checkModel = new CheckCreatePermissionModel <GeoTask> { Entity = task, Actor = actor, ProjectActorRole = currentActorProjectRole }; var validator = new GeoTaskCreatePermissionValidator(); var validatorResult = await validator .ValidateAsync(checkModel) .ConfigureAwait(false); if (!validatorResult.IsValid) { return(ErrorResult(validatorResult.Errors .Select(x => x.ErrorMessage))); } return(new CreateResult { Success = true, Id = task.Id }); }
private async Task <GeoTask> BuildUpdatedGeoTask (GeoTaskUpdateCommand command, GeoTask oldGeoTask, Actor currentActor) { var newGeoTask = new GeoTask { CreatedAt = oldGeoTask.CreatedAt, CreatedBy = oldGeoTask.CreatedBy, Description = command.Description, Id = oldGeoTask.Id, IsArchived = command.IsArchived, PlanFinishAt = command.PlanFinishAt, PlanStartAt = command.PlanStartAt, Title = command.Title, Status = command.Status, }; var allActors = await GetActorsAsync( command.AssistentActorsIds .Concat(command.ObserverActorsIds) .Append(command.ResponsibleActorId) ).ConfigureAwait(false); newGeoTask.AssistentActors.AddRange( command.AssistentActorsIds .Select(x => allActors.FirstOrDefault(a => a.Id == x)) .Where(a => a != null)); newGeoTask.ObserverActors.AddRange( command.ObserverActorsIds .Select(x => allActors.FirstOrDefault(a => a.Id == x)) .Where(a => a != null)); newGeoTask.ResponsibleActor = allActors .FirstOrDefault(a => a.Id == command.ResponsibleActorId); // Check that Geo Ids exist in repository newGeoTask.GeosIds.AddRange(await GetGeosIdsAsync(command.GeosIds) .ConfigureAwait(false)); newGeoTask.History.AddRange(oldGeoTask.History); newGeoTask.ProjectId = NewProject?.Id; if (oldGeoTask.Status != command.Status) { newGeoTask.StatusChangedAt = DateTime.UtcNow; } else { newGeoTask.StatusChangedAt = oldGeoTask.StatusChangedAt; } newGeoTask.History.Add(BuildNewHistoryElement (newGeoTask, oldGeoTask, command, currentActor)); return(newGeoTask); }
private GeoTaskHistory BuildNewHistoryElement(GeoTask newGeoTask, GeoTask oldGeoTask, GeoTaskUpdateCommand command, Actor currentActor) { var historyRecord = new GeoTaskHistory() { ChangedAt = DateTime.UtcNow, ChangedBy = currentActor, Description = command.MessageDescription, Title = command.MessageTitle }; historyRecord.Operations .AddRange(newGeoTask.ToHistoryOperations(oldGeoTask)); return(historyRecord); }
public static EntityResponse <GeoTask> ToGeoTaskResponse (this GeoTask from) { if (from is null) { return(null); } var response = new EntityResponse <GeoTask> { Entity = from, Success = true }; return(response); }
public static GeoTask ToGeoTask(this DbGeoTask from, Dictionary <string, Actor> actors) { actors.TryGetValue(from.CreatedById, out var creator); actors.TryGetValue(from.ResponsibleActorId, out var responsible); var assistents = from.AssistentActorsIds .Select(x => { actors.TryGetValue(x, out var actor); return(actor); }) .Where(x => x != null) .ToList(); var observers = from.ObserverActorsIds .Select(x => { actors.TryGetValue(x, out var actor); return(actor); }) .Where(x => x != null) .ToList(); var to = new GeoTask { CreatedAt = from.CreatedAt, Description = from.Description, Id = from.Id, IsArchived = from.IsArchived, PlanFinishAt = from.PlanFinishAt, PlanStartAt = from.PlanStartAt, ProjectId = from.ProjectId, Status = from.Status, StatusChangedAt = from.StatusChangedAt, Title = from.Title, CreatedBy = creator, ResponsibleActor = responsible, }; to.AssistentActors.AddRange(assistents); to.ObserverActors.AddRange(observers); to.History.AddRange(from.History); to.GeosIds.AddRange(from.GeosIds); return(to); }
private async Task <ValidationResult> CheckPermissionAsync (GeoTask oldTask, GeoTask newTask, Actor currentActor, ActorRole oldProjectRole, ActorRole newProjectRole) { var checkModel = new CheckUpdatePermissionModel <GeoTask> { Actor = currentActor, OldProjectRole = oldProjectRole, NewProjectRole = newProjectRole, EntityBeforeUpdate = oldTask, EntityAfterUpdate = newTask }; var validator = new GeoTaskUpdatePermissionValidator(); var validatorResult = await validator .ValidateAsync(checkModel) .ConfigureAwait(false); return(validatorResult); }
public async Task GetIdReturnsOkResultWhenSuccessAnswerAsync() { // Arrange var entityId = "0000000000000000"; var appEntity = new GeoTask() { Id = entityId, IsArchived = false, Title = "Test GeoTask" }; var apiEntity = new ApiGeoTask() { Id = entityId, IsArchived = false, Title = "Test GeoTask" }; var mediator = new Mock <IMediator>(); mediator.Setup(x => x.Send(It.IsAny <EntityQuery <GeoTask> >(), It.IsAny <CancellationToken>())) .ReturnsAsync( new EntityResponse <GeoTask>() { Success = true, Entity = appEntity }) .Verifiable("Query was not sent."); var controller = BuildController(mediator); // Act var controllerAnswer = await controller.Get(entityId); // Assert Assert.IsType <OkObjectResult>(controllerAnswer); Assert.Equal(apiEntity.Id, (((OkObjectResult)controllerAnswer).Value as ApiGeoTask).Id); mediator.Verify(x => x.Send(It.IsAny <EntityQuery <GeoTask> >(), It.IsAny <CancellationToken>())); }
public async Task <CreateResult> Handle(GeoTaskCreateCommand command, CancellationToken cancellationToken) { if (command is null) { Logger.LogWarning(AppLogEvent.HandleArgumentError, "Handle create task got empty command"); return(ErrorResult("Empty Geo Task Create command")); } var validator = new GeoTaskCreateCommandValidator(); var validationResult = await validator .ValidateAsync(command) .ConfigureAwait(false); if (!validationResult.IsValid) { Logger.LogWarning(AppLogEvent.RequestValidationError, "Validation command error. Command = {command}. " + "Error = {Error}", command.ToDictionary(), validationResult.Errors); return(ErrorResult (validationResult.Errors.Select(x => x.ErrorMessage))); } try { var geoTask = new GeoTask() { CreatedAt = DateTime.UtcNow, Description = command.Description, StatusChangedAt = DateTime.UtcNow, IsArchived = command.IsArchived, PlanFinishAt = command.PlanFinishAt, PlanStartAt = command.PlanStartAt, Status = GeoTaskStatus.New, Title = command.Title, }; // Load from repository all mentioned actors var allActors = await GetActors( command.AssistentActorsIds .Concat(command.ObserverActorsIds) .Append(command.ResponsibleActorId) ).ConfigureAwait(false); // Add to the new entity only exist in the repository actors geoTask.AssistentActors.AddRange( command.AssistentActorsIds .Select(x => allActors .FirstOrDefault(a => a.Id == x)) .Where(a => a != null)); geoTask.ObserverActors.AddRange( command.ObserverActorsIds .Select(x => allActors .FirstOrDefault(a => a.Id == x)) .Where(a => a != null)); geoTask.ResponsibleActor = allActors .FirstOrDefault(a => a.Id == command.ResponsibleActorId); // Check that Geo Ids exist in repository geoTask.GeosIds.AddRange(await GetGeosIds(command.GeosIds) .ConfigureAwait(false)); // Get Actor for current user by user name var creatorResponse = await Mediator .Send(new DbGetActorByNameRequest (command.CurrentPrincipal?.Identity?.Name)) .ConfigureAwait(false); Actor createdBy = null; if (creatorResponse.Success) { createdBy = creatorResponse.Entity; } geoTask.CreatedBy = createdBy; Project project = await GetProject(command.ProjectId) .ConfigureAwait(false); geoTask.ProjectId = project?.Id; var historyRec = new GeoTaskHistory { ChangedAt = DateTime.UtcNow, ChangedBy = createdBy, }; historyRec.Operations.Add(new Operation { OperationType = addOperation, Path = "/", NewValue = geoTask.ToDictionary() }); geoTask.History.Add(historyRec); var validatorBeforeSave = new GeoTaskBeforeSaveValidator(); var validationBeforeSaveResult = await validatorBeforeSave .ValidateAsync(geoTask) .ConfigureAwait(false); if (!validationBeforeSaveResult.IsValid) { Logger.LogWarning(AppLogEvent.RequestNotValid, "GeoTask validation error. Entity={Entity}. " + "Error={Error}.", geoTask.ToDictionary(), validationBeforeSaveResult.Errors); return(ErrorResult(validationBeforeSaveResult.Errors .Select(x => x.ErrorMessage))); } var checkPermissionResult = await CheckPermission (geoTask, createdBy, project) .ConfigureAwait(false); if (!checkPermissionResult.Success) { Logger.LogWarning(AppLogEvent.SecurityNotPassed, "GeoTask check create permission error. " + "Entity={Entity}. CurrentActor={CurrentActor}. " + "Project={Project}. Error={Error}.", geoTask.ToDictionary(), createdBy?.ToDictionary(), project?.ToDictionary(), checkPermissionResult.Errors); return(checkPermissionResult); } return(await Mediator .Send(new DbCreateCommand <GeoTask>(geoTask)) .ConfigureAwait(false)); } catch (Exception e) { Logger.LogError(AppLogEvent.HandleErrorResponse, e, "Call repository exception"); return(ErrorResult("Not found")); } }
public async Task <UpdateResult> Handle(GeoTaskUpdateCommand command, CancellationToken cancellationToken) { try { Logger.LogInformation(AppLogEvent.HandleRequest, "Handle update task {Command}", command.ToDictionary()); if (command is null || string.IsNullOrWhiteSpace(command.Id)) { Logger.LogWarning(AppLogEvent.HandleArgumentError, "Handle update task command with empty request"); return(ErrorResult("Command empty argument")); } var validator = new GeoTaskUpdateCommandValidator(); var validationResult = await validator.ValidateAsync(command) .ConfigureAwait(false); if (!validationResult.IsValid) { var validationErrors = validationResult.Errors .Select(x => x.ErrorMessage).ToList(); Logger.LogWarning(AppLogEvent.HandleArgumentError, "Task update command validation error. " + "Command={Command}. Error={Error}", command.ToDictionary(), validationErrors); return(ErrorResult(validationErrors)); } var oldGeoTaskResponse = await Mediator .Send(new DbGetEntityByIdRequest <GeoTask>(command.Id)) .ConfigureAwait(false); if (!oldGeoTaskResponse.Success) { Logger.LogWarning(AppLogEvent.HandleErrorResponse, "Get task for update error. Id={Id}. Error={Error}.", command.Id, oldGeoTaskResponse.Errors); return(ErrorResult(oldGeoTaskResponse.Errors)); } var oldGeoTask = oldGeoTaskResponse.Entity; var currentActorResponse = await Mediator .Send(new DbGetActorByNameRequest (command.CurrentPrincipal?.Identity?.Name)) .ConfigureAwait(false); var currentActor = currentActorResponse.Entity; OldProject = await GetProjectAsync(oldGeoTask.ProjectId) .ConfigureAwait(false); // Check Project Id NewProject = null; if (command.ProjectId != OldProject?.Id) { NewProject = await GetProjectAsync(command.ProjectId) .ConfigureAwait(false); } else { NewProject = OldProject; } GeoTask newGeoTask = await BuildUpdatedGeoTask(command, oldGeoTask, currentActor).ConfigureAwait(false); var validatorBeforeSave = new GeoTaskBeforeSaveValidator(); var validationBeforeSaveResult = await validatorBeforeSave .ValidateAsync(newGeoTask) .ConfigureAwait(false); if (!validationBeforeSaveResult.IsValid) { Logger.LogWarning(AppLogEvent.RequestValidationError, "Update GeoTask validation error. " + "Entity={Entity}. Error={Error}.", newGeoTask.ToDictionary(), validationBeforeSaveResult.Errors); return(ErrorResult(validationBeforeSaveResult.Errors .Select(x => x.ErrorMessage))); } ActorRole oldProjectRole = null; OldProject?.ProjectActorRoles? .TryGetValue(currentActor.Id, out oldProjectRole); ActorRole newProjectRole = null; if (oldGeoTask.ProjectId != newGeoTask.ProjectId) { NewProject?.ProjectActorRoles? .TryGetValue(currentActor.Id, out newProjectRole); } else { newProjectRole = oldProjectRole; } var permissionValidateResult = await CheckPermissionAsync (oldGeoTask, newGeoTask, currentActor, oldProjectRole, newProjectRole) .ConfigureAwait(false); if (!permissionValidateResult.IsValid) { Logger.LogWarning(AppLogEvent.SecurityNotPassed, "Current actor has no rights to update GeoTask. " + "Actor={Actor}. Entity before update={OldEntity}." + " Entity after update={NewEntity}. Error={Error}.", currentActor.ToDictionary(), oldGeoTask.ToDictionary(), newGeoTask.ToDictionary(), permissionValidateResult.Errors .Select(x => x.ErrorMessage)); return(ErrorResult(permissionValidateResult.Errors .Select(x => x.ErrorMessage))); } var updateResult = await Mediator .Send(new DbUpdateCommand <GeoTask>(newGeoTask)) .ConfigureAwait(false); return(updateResult); } catch (Exception e) { Logger.LogError(AppLogEvent.HandleErrorResponse, e, "Geo task update exception"); return(ErrorResult("Geo task update exception")); } }
public static IEnumerable <Operation> ToHistoryOperations (this GeoTask newGeoTask, GeoTask oldGeoTask) { if (newGeoTask?.CreatedAt != oldGeoTask?.CreatedAt) { yield return(new Operation { NewValue = newGeoTask?.CreatedAt, OldValue = oldGeoTask?.CreatedAt, OperationType = _TJsonPatchOperation.Replace, Path = $"/{nameof(newGeoTask.CreatedAt)}" }); } ; if (newGeoTask?.CreatedBy != oldGeoTask?.CreatedBy) { yield return(new Operation { NewValue = newGeoTask?.CreatedBy, OldValue = oldGeoTask?.CreatedBy, OperationType = _TJsonPatchOperation.Replace, Path = $"/{nameof(newGeoTask.CreatedBy)}" }); } ; if (newGeoTask?.Description != oldGeoTask?.Description) { yield return(new Operation { NewValue = newGeoTask?.Description, OldValue = oldGeoTask?.Description, OperationType = _TJsonPatchOperation.Replace, Path = $"/{nameof(newGeoTask.Description)}" }); } ; if (newGeoTask?.Id != oldGeoTask?.Id) { yield return(new Operation { NewValue = newGeoTask?.Id, OldValue = oldGeoTask?.Id, OperationType = _TJsonPatchOperation.Replace, Path = $"/{nameof(newGeoTask.Id)}" }); } ; if (newGeoTask?.IsArchived != oldGeoTask?.IsArchived) { yield return(new Operation { NewValue = newGeoTask?.IsArchived, OldValue = oldGeoTask?.IsArchived, OperationType = _TJsonPatchOperation.Replace, Path = $"/{nameof(newGeoTask.IsArchived)}" }); } ; if (newGeoTask?.PlanFinishAt != oldGeoTask?.PlanFinishAt) { yield return(new Operation { NewValue = newGeoTask?.PlanFinishAt, OldValue = oldGeoTask?.PlanFinishAt, OperationType = _TJsonPatchOperation.Replace, Path = $"/{nameof(newGeoTask.PlanFinishAt)}" }); } ; if (newGeoTask?.PlanStartAt != oldGeoTask?.PlanStartAt) { yield return(new Operation { NewValue = newGeoTask?.PlanStartAt, OldValue = oldGeoTask?.PlanStartAt, OperationType = _TJsonPatchOperation.Replace, Path = $"/{nameof(newGeoTask.PlanStartAt)}" }); } ; if (newGeoTask?.ProjectId != oldGeoTask?.ProjectId) { yield return(new Operation { NewValue = newGeoTask?.ProjectId, OldValue = oldGeoTask?.ProjectId, OperationType = _TJsonPatchOperation.Replace, Path = $"/{nameof(newGeoTask.ProjectId)}" }); } ; if (newGeoTask?.ResponsibleActor != oldGeoTask?.ResponsibleActor) { yield return(new Operation { NewValue = newGeoTask?.ResponsibleActor, OldValue = oldGeoTask?.ResponsibleActor, OperationType = _TJsonPatchOperation.Replace, Path = $"/{nameof(newGeoTask.ResponsibleActor)}" }); } ; if (newGeoTask?.Status != oldGeoTask?.Status) { yield return(new Operation { NewValue = newGeoTask?.Status, OldValue = oldGeoTask?.Status, OperationType = _TJsonPatchOperation.Replace, Path = $"/{nameof(newGeoTask.Status)}" }); } ; if (newGeoTask?.StatusChangedAt != oldGeoTask?.StatusChangedAt) { yield return(new Operation { NewValue = newGeoTask?.StatusChangedAt, OldValue = oldGeoTask?.StatusChangedAt, OperationType = _TJsonPatchOperation.Replace, Path = $"/{nameof(newGeoTask.StatusChangedAt)}" }); } ; if (newGeoTask?.Title != oldGeoTask?.Title) { yield return(new Operation { NewValue = newGeoTask?.Title, OldValue = oldGeoTask?.Title, OperationType = _TJsonPatchOperation.Replace, Path = $"/{nameof(newGeoTask.Title)}" }); } ; var newAssistenceActorsSet = newGeoTask?.AssistentActors.ToHashSet() ?? new HashSet <Actor>(); var oldAssistenceActorsSet = oldGeoTask?.AssistentActors.ToHashSet() ?? new HashSet <Actor>(); var addedAssistenceActors = newAssistenceActorsSet .Except(oldAssistenceActorsSet); var removedAssistenceActors = oldAssistenceActorsSet .Except(newAssistenceActorsSet); foreach (var item in removedAssistenceActors) { yield return(new Operation { OldValue = item, OperationType = _TJsonPatchOperation.Remove, Path = $"/{nameof(newGeoTask.AssistentActors)}" }); } foreach (var item in addedAssistenceActors) { yield return(new Operation { NewValue = item, OperationType = _TJsonPatchOperation.Add, Path = $"/{nameof(newGeoTask.AssistentActors)}" }); } var newObserverActorsSet = newGeoTask?.ObserverActors.ToHashSet() ?? new HashSet <Actor>(); var oldObserverActorsSet = oldGeoTask?.ObserverActors.ToHashSet() ?? new HashSet <Actor>(); var addedObserverActors = newObserverActorsSet .Except(oldObserverActorsSet); var removedObserverActors = oldObserverActorsSet .Except(newObserverActorsSet); foreach (var item in removedObserverActors) { yield return(new Operation { OldValue = item, OperationType = _TJsonPatchOperation.Remove, Path = $"/{nameof(newGeoTask.ObserverActors)}" }); } foreach (var item in addedObserverActors) { yield return(new Operation { NewValue = item, OperationType = _TJsonPatchOperation.Add, Path = $"/{nameof(newGeoTask.ObserverActors)}" }); } var newGeosIdsSet = newGeoTask?.GeosIds.ToHashSet() ?? new HashSet <string>(); var oldGeosIdsSet = oldGeoTask?.GeosIds.ToHashSet() ?? new HashSet <string>(); var addedGeosIds = newGeosIdsSet.Except(oldGeosIdsSet); var removedGeosIds = oldGeosIdsSet.Except(newGeosIdsSet); foreach (var item in removedGeosIds) { yield return(new Operation { OldValue = item, OperationType = _TJsonPatchOperation.Remove, Path = $"/{nameof(newGeoTask.GeosIds)}" }); } foreach (var item in addedGeosIds) { yield return(new Operation { NewValue = item, OperationType = _TJsonPatchOperation.Add, Path = $"/{nameof(newGeoTask.GeosIds)}" }); } }