From e899001efd0dd98fe0cefded7b3a0f33a4ba82f3 Mon Sep 17 00:00:00 2001 From: Mahdi Jafari <126339078+mahdijafariii@users.noreply.github.com> Date: Sun, 8 Sep 2024 21:33:33 +0330 Subject: [PATCH] Fix bugs (#105) * fix role change in user update * fix category update dto * fix not allowed to update admin info * fix not allowed to delete admin * fix (Graph) :edge and node upload faster now * fix (Test) : fix some test --- .../AnalysisData.sln.DotSettings.user | 7 +++++-- .../GraphController/CategoriesController.cs | 2 +- .../GraphDto/CategoryDto/NewCategoryDto.cs | 1 - .../GraphDto/CategoryDto/UpdateCategoryDto.cs | 9 +++++++++ .../UserException/AdminProtectedException.cs | 8 ++++++++ .../EdgeRepository/AttributeEdgeRepository.cs | 12 +++++++++-- .../EdgeRepository/EntityEdgeRepository.cs | 14 +++++++++++-- .../EdgeRepository/ValueEdgeRepository.cs | 13 ++++++++++-- .../NodeRepository/AttributeNodeRepository.cs | 20 +++++++++++++++---- .../NodeRepository/ValueNodeRepository.cs | 11 ++++++++-- .../AnalysisData/Resources.Designer.cs | 9 +++++++++ AnalysisData/AnalysisData/Resources.resx | 3 +++ .../Business/EdgeManager/EdgeDataProcessor.cs | 14 ++++++++++--- .../Abstraction/ICategoryService.cs | 2 +- .../CategoryService/CategoryService.cs | 10 +++++----- .../UserService/AdminService/AdminService.cs | 12 +++++++++-- .../CategoryControllersTest.cs | 2 +- 17 files changed, 121 insertions(+), 28 deletions(-) create mode 100644 AnalysisData/AnalysisData/Dtos/GraphDto/CategoryDto/UpdateCategoryDto.cs create mode 100644 AnalysisData/AnalysisData/Exception/UserException/AdminProtectedException.cs diff --git a/AnalysisData/AnalysisData.sln.DotSettings.user b/AnalysisData/AnalysisData.sln.DotSettings.user index 5c0a508..5b95cdc 100644 --- a/AnalysisData/AnalysisData.sln.DotSettings.user +++ b/AnalysisData/AnalysisData.sln.DotSettings.user @@ -1,9 +1,12 @@  - <SessionState ContinuousTestingMode="0" IsActive="True" Name="UpdateCategory_ShouldReturnOk_WhenCategoryIsUpdatedSuccessfully" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> + <SessionState ContinuousTestingMode="0" Name="RoleRepositoryTests" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> <TestAncestor> - <TestId>xUnit::9AEC1F3F-B1B3-47C1-82D4-E432E2D77E0E::net8.0::TestProject.Graph.Controllers.CategoryControllersTest.UpdateCategory_ShouldReturnOk_WhenCategoryIsUpdatedSuccessfully</TestId> + <TestId>xUnit::9AEC1F3F-B1B3-47C1-82D4-E432E2D77E0E::net8.0::TestProject.User.Repository.RoleRepository.RoleRepositoryTests</TestId> </TestAncestor> </SessionState> + <SessionState ContinuousTestingMode="0" IsActive="True" Name="UpdateCategory_ShouldReturnOk_WhenCategoryIsUpdatedSuccessfully" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> + <Project Location="C:\Users\Mahdi\Desktop\code star proje\Summer1403-Project-Group03-Backend\AnalysisData\TestProject" Presentation="&lt;TestProject&gt;" /> +</SessionState> diff --git a/AnalysisData/AnalysisData/Controllers/GraphController/CategoriesController.cs b/AnalysisData/AnalysisData/Controllers/GraphController/CategoriesController.cs index 46deaaf..96cf789 100644 --- a/AnalysisData/AnalysisData/Controllers/GraphController/CategoriesController.cs +++ b/AnalysisData/AnalysisData/Controllers/GraphController/CategoriesController.cs @@ -48,7 +48,7 @@ public async Task DeleteCategory(int id) [Authorize(Policy = "silver")] [HttpPut] - public async Task UpdateCategory([FromBody] NewCategoryDto newCategory) + public async Task UpdateCategory([FromBody] UpdateCategoryDto newCategory) { await _categoryService.UpdateAsync(newCategory); return Ok(new { massage = "updated successfully" }); diff --git a/AnalysisData/AnalysisData/Dtos/GraphDto/CategoryDto/NewCategoryDto.cs b/AnalysisData/AnalysisData/Dtos/GraphDto/CategoryDto/NewCategoryDto.cs index a6c1ac4..e55647c 100644 --- a/AnalysisData/AnalysisData/Dtos/GraphDto/CategoryDto/NewCategoryDto.cs +++ b/AnalysisData/AnalysisData/Dtos/GraphDto/CategoryDto/NewCategoryDto.cs @@ -4,6 +4,5 @@ namespace AnalysisData.Dtos.GraphDto.CategoryDto; public class NewCategoryDto { - [Required] public int Id { get; set; } [Required] public string Name { get; set; } } \ No newline at end of file diff --git a/AnalysisData/AnalysisData/Dtos/GraphDto/CategoryDto/UpdateCategoryDto.cs b/AnalysisData/AnalysisData/Dtos/GraphDto/CategoryDto/UpdateCategoryDto.cs new file mode 100644 index 0000000..bf26cf3 --- /dev/null +++ b/AnalysisData/AnalysisData/Dtos/GraphDto/CategoryDto/UpdateCategoryDto.cs @@ -0,0 +1,9 @@ +using System.ComponentModel.DataAnnotations; + +namespace AnalysisData.Dtos.GraphDto.CategoryDto; + +public class UpdateCategoryDto +{ + [Required] public int Id { get; set; } + [Required] public string Name { get; set; } +} \ No newline at end of file diff --git a/AnalysisData/AnalysisData/Exception/UserException/AdminProtectedException.cs b/AnalysisData/AnalysisData/Exception/UserException/AdminProtectedException.cs new file mode 100644 index 0000000..a5cd9aa --- /dev/null +++ b/AnalysisData/AnalysisData/Exception/UserException/AdminProtectedException.cs @@ -0,0 +1,8 @@ +namespace AnalysisData.Exception.UserException; + +public class AdminProtectedException : ServiceException +{ + public AdminProtectedException() : base(Resources.AdminProtectedException, StatusCodes.Status400BadRequest) + { + } +} \ No newline at end of file diff --git a/AnalysisData/AnalysisData/Repositories/GraphRepositories/GraphRepository/EdgeRepository/AttributeEdgeRepository.cs b/AnalysisData/AnalysisData/Repositories/GraphRepositories/GraphRepository/EdgeRepository/AttributeEdgeRepository.cs index e2c09ad..63fc6f1 100644 --- a/AnalysisData/AnalysisData/Repositories/GraphRepositories/GraphRepository/EdgeRepository/AttributeEdgeRepository.cs +++ b/AnalysisData/AnalysisData/Repositories/GraphRepositories/GraphRepository/EdgeRepository/AttributeEdgeRepository.cs @@ -21,8 +21,16 @@ public async Task AddAsync(AttributeEdge entity) } public async Task AddRangeAsync(IEnumerable attributeEdges) { - await _context.AttributeEdges.AddRangeAsync(attributeEdges); - await _context.SaveChangesAsync(); + var existingIds = await _context.AttributeEdges + .Where(ae => attributeEdges.Select(e => e.Id).Contains(ae.Id)) + .Select(ae => ae.Id) + .ToListAsync(); + var newAttributeEdges = attributeEdges.Where(ae => !existingIds.Contains(ae.Id)).ToList(); + if (newAttributeEdges.Any()) + { + await _context.AttributeEdges.AddRangeAsync(newAttributeEdges); + await _context.SaveChangesAsync(); + } } public async Task> GetAllAsync() { diff --git a/AnalysisData/AnalysisData/Repositories/GraphRepositories/GraphRepository/EdgeRepository/EntityEdgeRepository.cs b/AnalysisData/AnalysisData/Repositories/GraphRepositories/GraphRepository/EdgeRepository/EntityEdgeRepository.cs index 2bcaaf3..8d94ff4 100644 --- a/AnalysisData/AnalysisData/Repositories/GraphRepositories/GraphRepository/EdgeRepository/EntityEdgeRepository.cs +++ b/AnalysisData/AnalysisData/Repositories/GraphRepositories/GraphRepository/EdgeRepository/EntityEdgeRepository.cs @@ -26,8 +26,18 @@ public async Task> GetAllAsync() } public async Task AddRangeAsync(IEnumerable entityEdges) { - await _context.EntityEdges.AddRangeAsync(entityEdges); - await _context.SaveChangesAsync(); + var existingEntityIds = await _context.EntityNodes.Select(en => en.Id).ToListAsync(); + + var validEntityEdges = entityEdges + .Where(ee => existingEntityIds.Contains(ee.EntityIDSource)) + .ToList(); + + if (validEntityEdges.Any()) + { + await _context.EntityEdges.AddRangeAsync(validEntityEdges); + await _context.SaveChangesAsync(); + } + } public async Task GetByIdAsync(Guid id) { diff --git a/AnalysisData/AnalysisData/Repositories/GraphRepositories/GraphRepository/EdgeRepository/ValueEdgeRepository.cs b/AnalysisData/AnalysisData/Repositories/GraphRepositories/GraphRepository/EdgeRepository/ValueEdgeRepository.cs index b451ed5..1549d90 100644 --- a/AnalysisData/AnalysisData/Repositories/GraphRepositories/GraphRepository/EdgeRepository/ValueEdgeRepository.cs +++ b/AnalysisData/AnalysisData/Repositories/GraphRepositories/GraphRepository/EdgeRepository/ValueEdgeRepository.cs @@ -26,8 +26,17 @@ public async Task> GetAllAsync() } public async Task AddRangeAsync(IEnumerable valueEdges) { - await _context.ValueEdges.AddRangeAsync(valueEdges); - await _context.SaveChangesAsync(); + var existingEntityIds = await _context.EntityEdges.Select(ee => ee.Id).ToListAsync(); + + var validValueEdges = valueEdges + .Where(ve => existingEntityIds.Contains(ve.EntityId)) + .ToList(); + + if (validValueEdges.Any()) + { + await _context.ValueEdges.AddRangeAsync(validValueEdges); + await _context.SaveChangesAsync(); + } } public async Task GetByIdAsync(Guid id) { diff --git a/AnalysisData/AnalysisData/Repositories/GraphRepositories/GraphRepository/NodeRepository/AttributeNodeRepository.cs b/AnalysisData/AnalysisData/Repositories/GraphRepositories/GraphRepository/NodeRepository/AttributeNodeRepository.cs index e6ecb5f..9c7e31a 100644 --- a/AnalysisData/AnalysisData/Repositories/GraphRepositories/GraphRepository/NodeRepository/AttributeNodeRepository.cs +++ b/AnalysisData/AnalysisData/Repositories/GraphRepositories/GraphRepository/NodeRepository/AttributeNodeRepository.cs @@ -34,13 +34,25 @@ public async Task GetByNameAsync(string name) { return await _context.AttributeNodes.FirstOrDefaultAsync(x => x.Name == name); } - + public async Task AddRangeAsync(IEnumerable attributeNodes) { - await _context.AttributeNodes.AddRangeAsync(attributeNodes); - await _context.SaveChangesAsync(); + { + var existingIds = await _context.AttributeNodes + .Where(an => attributeNodes.Select(n => n.Id).Contains(an.Id)) + .Select(an => an.Id) + .ToListAsync(); + + var newAttributeNodes = attributeNodes.Where(an => !existingIds.Contains(an.Id)).ToList(); + + if (newAttributeNodes.Any()) + { + await _context.AttributeNodes.AddRangeAsync(newAttributeNodes); + await _context.SaveChangesAsync(); + } + } } - + public async Task DeleteAsync(Guid id) { var entity = await _context.AttributeNodes.FindAsync(id); diff --git a/AnalysisData/AnalysisData/Repositories/GraphRepositories/GraphRepository/NodeRepository/ValueNodeRepository.cs b/AnalysisData/AnalysisData/Repositories/GraphRepositories/GraphRepository/NodeRepository/ValueNodeRepository.cs index 35f758c..75eeb0e 100644 --- a/AnalysisData/AnalysisData/Repositories/GraphRepositories/GraphRepository/NodeRepository/ValueNodeRepository.cs +++ b/AnalysisData/AnalysisData/Repositories/GraphRepositories/GraphRepository/NodeRepository/ValueNodeRepository.cs @@ -22,8 +22,15 @@ public async Task AddAsync(ValueNode entity) public async Task AddRangeAsync(IEnumerable valueNodes) { - await _context.ValueNodes.AddRangeAsync(valueNodes); - await _context.SaveChangesAsync(); + var existingAttributeNodeIds = await _context.AttributeNodes.Select(an => an.Id).ToListAsync(); + var validValueNodes = valueNodes + .Where(vn => existingAttributeNodeIds.Contains(vn.AttributeId)) + .ToList(); + if (validValueNodes.Any()) + { + await _context.ValueNodes.AddRangeAsync(validValueNodes); + await _context.SaveChangesAsync(); + } } public async Task> GetAllAsync() { diff --git a/AnalysisData/AnalysisData/Resources.Designer.cs b/AnalysisData/AnalysisData/Resources.Designer.cs index dc0377a..1f3dd7c 100644 --- a/AnalysisData/AnalysisData/Resources.Designer.cs +++ b/AnalysisData/AnalysisData/Resources.Designer.cs @@ -68,6 +68,15 @@ internal static string AdminExistenceException { } } + /// + /// Looks up a localized string similar to You can not delete or modify admin information !. + /// + internal static string AdminProtectedException { + get { + return ResourceManager.GetString("AdminProtectedException", resourceCulture); + } + } + /// /// Looks up a localized string similar to This category already exists!. /// diff --git a/AnalysisData/AnalysisData/Resources.resx b/AnalysisData/AnalysisData/Resources.resx index c516529..8a22144 100644 --- a/AnalysisData/AnalysisData/Resources.resx +++ b/AnalysisData/AnalysisData/Resources.resx @@ -96,4 +96,7 @@ Failed Operation ! + + You can not delete or modify admin information ! + \ No newline at end of file diff --git a/AnalysisData/AnalysisData/Services/GraphService/Business/EdgeManager/EdgeDataProcessor.cs b/AnalysisData/AnalysisData/Services/GraphService/Business/EdgeManager/EdgeDataProcessor.cs index 2228049..cb50756 100644 --- a/AnalysisData/AnalysisData/Services/GraphService/Business/EdgeManager/EdgeDataProcessor.cs +++ b/AnalysisData/AnalysisData/Services/GraphService/Business/EdgeManager/EdgeDataProcessor.cs @@ -36,6 +36,10 @@ public async Task ProcessEdgesAsync(ICsvReaderProcessor csv, IEnumerable CreateEntityEdgeAsync(ICsvReaderProcessor csv, st var fromNode = await _entityNodeRepository.GetByNameAsync(entityFrom); var toNode = await _entityNodeRepository.GetByNameAsync(entityTo); - ValidateNodesExistence(fromNode, toNode, entityFrom, entityTo); + if (!ValidateNodesExistence(fromNode, toNode, entityFrom, entityTo)) + { + return new EntityEdge(); + } return new EntityEdge { @@ -92,7 +99,7 @@ private async Task BatchInsertAsync(List entityEdges, List(); @@ -101,7 +108,8 @@ private static void ValidateNodesExistence(EntityNode fromNode, EntityNode toNod if (missingNodeIds.Any()) { - throw new NodeNotFoundInEntityEdgeException(missingNodeIds); + return false; } + return true; } } diff --git a/AnalysisData/AnalysisData/Services/GraphService/CategoryService/Abstraction/ICategoryService.cs b/AnalysisData/AnalysisData/Services/GraphService/CategoryService/Abstraction/ICategoryService.cs index 58ffb20..9ab827c 100644 --- a/AnalysisData/AnalysisData/Services/GraphService/CategoryService/Abstraction/ICategoryService.cs +++ b/AnalysisData/AnalysisData/Services/GraphService/CategoryService/Abstraction/ICategoryService.cs @@ -7,7 +7,7 @@ public interface ICategoryService { Task GetAllCategoriesAsync(int pageNumber, int pageSize); Task AddAsync(NewCategoryDto categoryDto); - Task UpdateAsync(NewCategoryDto newCategoryDto); + Task UpdateAsync(UpdateCategoryDto newCategoryDto); Task DeleteAsync(int id); Task GetByIdAsync(int id); } \ No newline at end of file diff --git a/AnalysisData/AnalysisData/Services/GraphService/CategoryService/CategoryService.cs b/AnalysisData/AnalysisData/Services/GraphService/CategoryService/CategoryService.cs index 9638cbc..19232b7 100644 --- a/AnalysisData/AnalysisData/Services/GraphService/CategoryService/CategoryService.cs +++ b/AnalysisData/AnalysisData/Services/GraphService/CategoryService/CategoryService.cs @@ -49,16 +49,16 @@ public async Task AddAsync(NewCategoryDto categoryDto) await _categoryRepository.AddAsync(category); } - public async Task UpdateAsync(NewCategoryDto newCategoryDto) + public async Task UpdateAsync(UpdateCategoryDto updateCategoryDto) { - var currentCategory = await _categoryRepository.GetByIdAsync(newCategoryDto.Id); - var existingCategory = await _categoryRepository.GetByNameAsync(newCategoryDto.Name); - if (existingCategory != null && newCategoryDto.Name != currentCategory.Name) + var currentCategory = await _categoryRepository.GetByIdAsync(updateCategoryDto.Id); + var existingCategory = await _categoryRepository.GetByNameAsync(updateCategoryDto.Name); + if (existingCategory != null && updateCategoryDto.Name != currentCategory.Name) { throw new CategoryAlreadyExist(); } - currentCategory.Name = newCategoryDto.Name; + currentCategory.Name = updateCategoryDto.Name; await _categoryRepository.UpdateAsync(currentCategory); } diff --git a/AnalysisData/AnalysisData/Services/UserService/AdminService/AdminService.cs b/AnalysisData/AnalysisData/Services/UserService/AdminService/AdminService.cs index 158373a..5405376 100644 --- a/AnalysisData/AnalysisData/Services/UserService/AdminService/AdminService.cs +++ b/AnalysisData/AnalysisData/Services/UserService/AdminService/AdminService.cs @@ -29,7 +29,10 @@ public AdminService(IUserRepository userRepository, IValidationService validatio public async Task UpdateUserInformationByAdminAsync(Guid id, UpdateAdminDto updateAdminDto) { var user = await _userRepository.GetUserByIdAsync(id); - + if (user !=null && user.Username == "admin") + { + throw new AdminProtectedException(); + } await ValidateUserInformation(user, updateAdminDto); _validationService.EmailCheck(updateAdminDto.Email); _validationService.PhoneNumberCheck(updateAdminDto.PhoneNumber); @@ -70,13 +73,18 @@ private async Task SetUpdatedInformation(User user, UpdateAdminDto updateAdminDt { throw new RoleNotFoundException(); } - user.Role = role; + user.RoleId = role.Id; await _userRepository.UpdateUserAsync(user.Id, user); } public async Task DeleteUserAsync(Guid id) { + var user = await _userRepository.GetUserByIdAsync(id); + if (user != null && user.Username == "admin") + { + throw new AdminProtectedException(); + } var isDelete = await _userRepository.DeleteUserAsync(id); if (!isDelete) throw new UserNotFoundException(); diff --git a/AnalysisData/TestProject/Controllers/GraphControllers/CategoryControllersTest.cs b/AnalysisData/TestProject/Controllers/GraphControllers/CategoryControllersTest.cs index 20768f6..575f8dd 100644 --- a/AnalysisData/TestProject/Controllers/GraphControllers/CategoryControllersTest.cs +++ b/AnalysisData/TestProject/Controllers/GraphControllers/CategoryControllersTest.cs @@ -105,7 +105,7 @@ public async Task UpdateCategory_ShouldReturnOk_WhenCategoryIsUpdatedSuccessfull { // Arrange int categoryId = 1; - var newCategoryDto = new NewCategoryDto { Id = 1, Name = "UpdatedCategory" }; + var newCategoryDto = new UpdateCategoryDto() { Id = 1, Name = "UpdatedCategory" }; // Act var result = await _controller.UpdateCategory(newCategoryDto);