diff --git a/OrganizationService/OrganizationService.Api/Controllers/ClassController.cs b/OrganizationService/OrganizationService.Api/Controllers/ClassController.cs new file mode 100644 index 00000000..dc554021 --- /dev/null +++ b/OrganizationService/OrganizationService.Api/Controllers/ClassController.cs @@ -0,0 +1,65 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using OrganizationService.Core.ApiModels; +using OrganizationService.Service.ApiModels.Class; +using OrganizationService.Service.Dtos.Class; +using OrganizationService.Service.Implementation; +using OrganizationService.Service.Interfaces; + +namespace OrganizationService.Api.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class ClassController : BaseApiController + { + public IClassService _classService { get; set; } + private readonly IConfiguration _configuration; + + public ClassController(IServiceProvider serviceProvider, IClassService classService, IConfiguration configuration) : base(serviceProvider) + { + _configuration = configuration; + _classService = classService; + } + + [HttpPost("public")] + public async Task GetViewModelsAsync([FromBody] ClassModel classModel) + { + var result = await _classService.GetViewModelsAsync(classModel); + var listResult = new PaginatedList(result.ToList(), result.Count(), classModel.PageIndex, classModel.PageSize); + return Success(listResult); + } + + //get project by id + [HttpGet("{id}")] + public async Task GetClassById(Guid id) + { + var result = await _classService.GetByIdAsync(id); + return Success(result); + } + + //add project + [HttpPost("add")] + public async Task AddClass([FromBody] CreateClassRequest addProjectModel) + { + await _classService.CreateAsync(addProjectModel); + return Success(); + } + + //edit project + [HttpPut("edit/{classId}")] + public async Task EditDetailClass(Guid classId, [FromBody] UpdateClassRequest editClassModel) + { + var result = await _classService.UpdateAsync(classId, editClassModel); + return Success(result); + } + + //delete project + [HttpDelete("{id}")] + public async Task DeleteClass(Guid id) + { + await _classService.DeleteAsync(id); + return Success(); + } + } +} diff --git a/OrganizationService/OrganizationService.Api/Controllers/GradeController.cs b/OrganizationService/OrganizationService.Api/Controllers/GradeController.cs new file mode 100644 index 00000000..0f459d4c --- /dev/null +++ b/OrganizationService/OrganizationService.Api/Controllers/GradeController.cs @@ -0,0 +1,65 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using OrganizationService.Core.ApiModels; +using OrganizationService.Service.ApiModels.Class; +using OrganizationService.Service.ApiModels.Grade; +using OrganizationService.Service.Dtos.Class; +using OrganizationService.Service.Dtos.Grade; +using OrganizationService.Service.Interfaces; + +namespace OrganizationService.Api.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class GradeController : BaseApiController + { + public IGradeService _gradeService { get; set; } + private readonly IConfiguration _configuration; + + public GradeController(IServiceProvider serviceProvider, IGradeService gradeService, IConfiguration configuration) : base(serviceProvider) + { + _configuration = configuration; + _gradeService = gradeService; + } + + [HttpPost("public")] + public async Task GetViewModelsAsync([FromBody] GradeModel gradeModel) + { + var result = await _gradeService.GetViewModelsAsync(gradeModel); + var listResult = new PaginatedList(result.ToList(), result.Count(), gradeModel.PageIndex, gradeModel.PageSize); + return Success(listResult); + } + + //get project by id + [HttpGet("{id}")] + public async Task GetGradeById(Guid id) + { + var result = await _gradeService.GetByIdAsync(id); + return Success(result); + } + + //add project + [HttpPost("add")] + public async Task AddGrade([FromBody] CreateGradeRequest addGradeModel) + { + await _gradeService.CreateAsync(addGradeModel); + return Success(); + } + + //edit project + [HttpPut("edit/{gradeId}")] + public async Task EditDetailGrade(Guid gradeId, [FromBody] UpdateGradeRequest editGradeModel) + { + var result = await _gradeService.UpdateAsync(gradeId, editGradeModel); + return Success(result); + } + + //delete project + [HttpDelete("{id}")] + public async Task DeleteGrade(Guid id) + { + var result = await _gradeService.DeleteAsync(id); + return Success(result); + } + } +} diff --git a/OrganizationService/OrganizationService.Api/Controllers/OrganizationController.cs b/OrganizationService/OrganizationService.Api/Controllers/OrganizationController.cs new file mode 100644 index 00000000..915f07dc --- /dev/null +++ b/OrganizationService/OrganizationService.Api/Controllers/OrganizationController.cs @@ -0,0 +1,66 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using OrganizationService.Core.ApiModels; +using OrganizationService.Service.ApiModels.Grade; +using OrganizationService.Service.ApiModels.Organization; +using OrganizationService.Service.Dtos.Grade; +using OrganizationService.Service.Dtos.Organization; +using OrganizationService.Service.Implementation; +using OrganizationService.Service.Interfaces; + +namespace OrganizationService.Api.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class OrganizationController : BaseApiController + { + public IOrganizationService _organizationService { get; set; } + private readonly IConfiguration _configuration; + + public OrganizationController(IServiceProvider serviceProvider, IOrganizationService organizationService, IConfiguration configuration) : base(serviceProvider) + { + _configuration = configuration; + _organizationService = organizationService; + } + + [HttpPost("public")] + public async Task GetViewModelsAsync([FromBody] OrganizationModel orgModel) + { + var result = await _organizationService.GetViewModelsAsync(orgModel); + var listResult = new PaginatedList(result.ToList(), result.Count(), orgModel.PageIndex, orgModel.PageSize); + return Success(listResult); + } + + //get project by id + [HttpGet("{id}")] + public async Task GetOrganizationById(Guid id) + { + var result = await _organizationService.GetByIdAsync(id); + return Success(result); + } + + //add project + [HttpPost("add")] + public async Task AddOrganization([FromBody] CreateOrganizationRequest addOrgModel) + { + await _organizationService.CreateAsync(addOrgModel); + return Success(); + } + + //edit project + [HttpPut("edit/{orgId}")] + public async Task EditDetailOrganization(Guid orgId, [FromBody] UpdateOrganizationRequest editOrgModel) + { + var result = await _organizationService.UpdateAsync(orgId, editOrgModel); + return Success(result); + } + + //delete project + [HttpDelete("{id}")] + public async Task DeleteOrganization(Guid id) + { + var result = await _organizationService.DeleteAsync(id); + return Success(result); + } + } +} diff --git a/OrganizationService/OrganizationService.Api/Controllers/OrganizationMemberController.cs b/OrganizationService/OrganizationService.Api/Controllers/OrganizationMemberController.cs new file mode 100644 index 00000000..3dac7ecf --- /dev/null +++ b/OrganizationService/OrganizationService.Api/Controllers/OrganizationMemberController.cs @@ -0,0 +1,65 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using OrganizationService.Core.ApiModels; +using OrganizationService.Service.ApiModels.Class; +using OrganizationService.Service.ApiModels.OrganizationMember; +using OrganizationService.Service.Dtos.Class; +using OrganizationService.Service.Dtos.OrganizationMember; +using OrganizationService.Service.Interfaces; + +namespace OrganizationService.Api.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class OrganizationMemberController : BaseApiController + { + public IOrganizationMemberService _orgMemberService { get; set; } + private readonly IConfiguration _configuration; + + public OrganizationMemberController(IServiceProvider serviceProvider, IOrganizationMemberService orgMemberService, IConfiguration configuration) : base(serviceProvider) + { + _configuration = configuration; + _orgMemberService = orgMemberService; + } + + [HttpPost("public")] + public async Task GetViewModelsAsync([FromBody] OrganizationMemberModel orgMemberModel) + { + var result = await _orgMemberService.GetViewModelsAsync(orgMemberModel); + var listResult = new PaginatedList(result.ToList(), result.Count(), orgMemberModel.PageIndex, orgMemberModel.PageSize); + return Success(listResult); + } + + //get project by id + [HttpGet("{id}")] + public async Task GetOrganizationMemberById(Guid id) + { + var result = await _orgMemberService.GetByIdAsync(id); + return Success(result); + } + + //add project + [HttpPost("add")] + public async Task AddClass([FromBody] CreateOrganizationMemberRequest addOrgMemberModel) + { + await _orgMemberService.CreateAsync(addOrgMemberModel); + return Success(); + } + + //edit project + [HttpPut("edit/{classId}")] + public async Task EditDetailClass(Guid classId, [FromBody] UpdateOrganizationMemberRequest editOrgMemberModel) + { + var result = await _orgMemberService.UpdateAsync(classId, editOrgMemberModel); + return Success(result); + } + + //delete project + [HttpDelete("{id}")] + public async Task DeleteOrganizationMember(Guid id) + { + await _orgMemberService.DeleteAsync(id); + return Success(); + } + } +} diff --git a/OrganizationService/OrganizationService.Api/Middlewares/ExceptionMiddleware.cs b/OrganizationService/OrganizationService.Api/Middlewares/ExceptionMiddleware.cs index 55ef4ab5..ac5499c1 100644 --- a/OrganizationService/OrganizationService.Api/Middlewares/ExceptionMiddleware.cs +++ b/OrganizationService/OrganizationService.Api/Middlewares/ExceptionMiddleware.cs @@ -128,7 +128,6 @@ private async Task HandleExceptionAsync(HttpContext context, Exception exception var requestBody = Encoding.UTF8.GetString(buffer); builder.AppendLine($"Body: {requestBody}"); - // context.Request.Body.Position = 0; } builder.AppendLine("Outgoing Response:"); builder.AppendLine($"Message: {exception.Message}"); @@ -141,9 +140,23 @@ private async Task HandleExceptionAsync(HttpContext context, Exception exception context.Response.ContentType = "application/json"; context.Response.StatusCode = (int)HttpStatusCode.InternalServerError; + var apiResponse = new ApiResponseModel + { + Code = (int)HttpStatusCode.InternalServerError, + Message = "Lỗi hệ thống. Vui lòng thử lại sau.", + Status = "fail", + Result = null + }; - await context.Response.WriteAsync("An error occurred. Please contact AmericanBank support."); - await context.Response.WriteAsync(exception.Message + exception.StackTrace); + var jsonResponse = JsonConvert.SerializeObject(apiResponse, new JsonSerializerSettings + { + ContractResolver = new CamelCasePropertyNamesContractResolver() + }); + + // await context.Response.WriteAsync("An error occurred. Please contact CodeCampus support."); + // await context.Response.WriteAsync(exception.Message + exception.StackTrace); + + await context.Response.WriteAsync(jsonResponse); } private async Task LogRequest(HttpContext context) diff --git a/OrganizationService/OrganizationService.Api/OrganizationService.Api.csproj b/OrganizationService/OrganizationService.Api/OrganizationService.Api.csproj index d69c5e3b..f2d0b640 100644 --- a/OrganizationService/OrganizationService.Api/OrganizationService.Api.csproj +++ b/OrganizationService/OrganizationService.Api/OrganizationService.Api.csproj @@ -7,6 +7,7 @@ + diff --git a/OrganizationService/OrganizationService.Api/Program.cs b/OrganizationService/OrganizationService.Api/Program.cs index 62e4fdfd..10b4a04a 100644 --- a/OrganizationService/OrganizationService.Api/Program.cs +++ b/OrganizationService/OrganizationService.Api/Program.cs @@ -10,6 +10,8 @@ using OrganizationService.DataAccess.DbContexts; using OrganizationService.DataAccess.Implementation; using OrganizationService.DataAccess.Interfaces; +using OrganizationService.Service.Implementation; +using OrganizationService.Service.Interfaces; using System.Data; using System.Text; using System.Text.Json.Serialization; @@ -36,7 +38,11 @@ builder.Services.AddScoped(typeof(IRepository<>), typeof(Repository<>)); builder.Services.AddScoped(); builder.Services.AddScoped(); - +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.Configure(options => diff --git a/OrganizationService/OrganizationService.Core/ApiModels/PagingBaseModel.cs b/OrganizationService/OrganizationService.Core/ApiModels/PagingBaseModel.cs index 2bfcb356..17115d28 100644 --- a/OrganizationService/OrganizationService.Core/ApiModels/PagingBaseModel.cs +++ b/OrganizationService/OrganizationService.Core/ApiModels/PagingBaseModel.cs @@ -11,7 +11,7 @@ public class PagingBaseModel { [DefaultValue(1)] public int PageIndex { get; set; } - [DefaultValue(20)] + [DefaultValue(30)] public int PageSize { get; set; } } } diff --git a/OrganizationService/OrganizationService.Core/OrganizationService.Core.csproj b/OrganizationService/OrganizationService.Core/OrganizationService.Core.csproj index 1bc4e9b3..ebff33e8 100644 --- a/OrganizationService/OrganizationService.Core/OrganizationService.Core.csproj +++ b/OrganizationService/OrganizationService.Core/OrganizationService.Core.csproj @@ -7,6 +7,7 @@ + diff --git a/OrganizationService/OrganizationService.DataAccess/Implementation/Repository.cs b/OrganizationService/OrganizationService.DataAccess/Implementation/Repository.cs index e996d19c..b5d368a8 100644 --- a/OrganizationService/OrganizationService.DataAccess/Implementation/Repository.cs +++ b/OrganizationService/OrganizationService.DataAccess/Implementation/Repository.cs @@ -112,9 +112,6 @@ public async Task> GetDistinctColumnAsync(string columnName) }; return result.Distinct(); } - - - public async Task> GetListAsync() { return await ActiveRecords.ToListAsync(); @@ -133,6 +130,7 @@ public async Task FindAsync(Expression> predicate) public async Task InsertAsync(T obj) { obj.CreatedBy = _userContext.UserId; + obj.CreatedAt = DateTime.UtcNow; await _dbContext.Set().AddAsync(obj); } @@ -158,13 +156,28 @@ public void UpdateMany(IEnumerable objs) public void Delete(T obj) { - obj.UpdatedAt = DateTime.UtcNow; - obj.UpdatedBy = _userContext.UserId; + obj.DeletedAt = DateTime.UtcNow; + obj.DeletedBy = _userContext.UserId; obj.IsDeleted = true; _dbContext.Set().Update(obj); } + public async Task DeleteAsync(Guid id) + { + var entity = await _dbContext.Set() + .FirstOrDefaultAsync(x => x.Id == id && !x.IsDeleted); + + if (entity == null) + throw new KeyNotFoundException("Không tìm thấy bản ghi hoặc đã bị xóa."); + + entity.DeletedAt = DateTime.UtcNow; + entity.DeletedBy = _userContext.UserId; + entity.IsDeleted = true; + + await _dbContext.SaveChangesAsync(); + } + public async Task DeleteByIdAsync(Guid id) { var obj = await FindByIdAsync(id); diff --git a/OrganizationService/OrganizationService.DataAccess/Implementation/UnitOfWork.cs b/OrganizationService/OrganizationService.DataAccess/Implementation/UnitOfWork.cs index 772f460a..d0183192 100644 --- a/OrganizationService/OrganizationService.DataAccess/Implementation/UnitOfWork.cs +++ b/OrganizationService/OrganizationService.DataAccess/Implementation/UnitOfWork.cs @@ -11,10 +11,7 @@ namespace OrganizationService.DataAccess.Implementation { public class UnitOfWork : IUnitOfWork { - public UnitOfWork( - OrganizationServiceDbContext dbContext - - ) + public UnitOfWork(OrganizationServiceDbContext dbContext) { _dbContext = dbContext; } diff --git a/OrganizationService/OrganizationService.DataAccess/Interfaces/IRepository.cs b/OrganizationService/OrganizationService.DataAccess/Interfaces/IRepository.cs index 94bbe093..3199b135 100644 --- a/OrganizationService/OrganizationService.DataAccess/Interfaces/IRepository.cs +++ b/OrganizationService/OrganizationService.DataAccess/Interfaces/IRepository.cs @@ -23,12 +23,13 @@ public interface IRepository where T : BaseTable void UpdateMany(IEnumerable objs); Task InsertAsync(T obj); void Delete(T obj); + Task DeleteAsync(Guid id); Task DeleteByIdAsync(Guid id); Task CreateAsync(T obj); Task> GetPagedListAsync( Expression> predicate = null, int pageIndex = 0, - int pageSize = 20 + int pageSize = 30 ); Task DeleteManyAsync(Expression> predicate); Task> FindElementAsync(Expression> predicate); diff --git a/OrganizationService/OrganizationService.DataAccess/Models/Grade.cs b/OrganizationService/OrganizationService.DataAccess/Models/Grade.cs index 6ba58799..b0c80ed4 100644 --- a/OrganizationService/OrganizationService.DataAccess/Models/Grade.cs +++ b/OrganizationService/OrganizationService.DataAccess/Models/Grade.cs @@ -16,6 +16,5 @@ public class Grade : BaseTable public Guid OrganizationId { get; set; } public Organization Organization { get; set; } public ICollection Classes { get; set; } - //public ICollection OrganizationMembers { get; set; } } } diff --git a/OrganizationService/OrganizationService.DataAccess/Models/Organization.cs b/OrganizationService/OrganizationService.DataAccess/Models/Organization.cs index e7e35df8..b44fccbf 100644 --- a/OrganizationService/OrganizationService.DataAccess/Models/Organization.cs +++ b/OrganizationService/OrganizationService.DataAccess/Models/Organization.cs @@ -12,15 +12,26 @@ namespace OrganizationService.DataAccess.Models public class Organization : BaseTable { [Required] + [StringLength(200)] public string Name { get; set; } = string.Empty; + + [StringLength(500)] public string? Description { get; set; } + + + [StringLength(300)] public string? Address { get; set; } + + [EmailAddress] public string? Email { get; set; } [MaxLength(10)] + [Phone] [RegularExpression("^[0-9]*$")] public string? Phone { get; set; } public Guid? Logo { get; set; } + + [Url] public string? LogoUrl { get; set; } public OrganizationStatus Status { get; set; } public ICollection Grades { get; set; } diff --git a/OrganizationService/OrganizationService.DataAccess/OrganizationService.DataAccess.csproj b/OrganizationService/OrganizationService.DataAccess/OrganizationService.DataAccess.csproj index 45142969..88041592 100644 --- a/OrganizationService/OrganizationService.DataAccess/OrganizationService.DataAccess.csproj +++ b/OrganizationService/OrganizationService.DataAccess/OrganizationService.DataAccess.csproj @@ -7,6 +7,7 @@ + diff --git a/OrganizationService/OrganizationService.Service/ApiModels/Class/ClassModel.cs b/OrganizationService/OrganizationService.Service/ApiModels/Class/ClassModel.cs new file mode 100644 index 00000000..c43f5c58 --- /dev/null +++ b/OrganizationService/OrganizationService.Service/ApiModels/Class/ClassModel.cs @@ -0,0 +1,13 @@ +using OrganizationService.Core.ApiModels; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OrganizationService.Service.ApiModels.Class +{ + public class ClassModel : PagingBaseModel + { + } +} diff --git a/OrganizationService/OrganizationService.Service/ApiModels/Class/CreateClassRequest.cs b/OrganizationService/OrganizationService.Service/ApiModels/Class/CreateClassRequest.cs new file mode 100644 index 00000000..4150c65d --- /dev/null +++ b/OrganizationService/OrganizationService.Service/ApiModels/Class/CreateClassRequest.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OrganizationService.Service.ApiModels.Class +{ + public class CreateClassRequest + { + [Required] + public string ClassName { get; set; } = string.Empty; + public string? Description { get; set; } + + [Required] + public Guid GradeId { get; set; } + public string GradeName { get; set; } = string.Empty; + } +} diff --git a/OrganizationService/OrganizationService.Service/ApiModels/Class/UpdateClassRequest.cs b/OrganizationService/OrganizationService.Service/ApiModels/Class/UpdateClassRequest.cs new file mode 100644 index 00000000..412aebe6 --- /dev/null +++ b/OrganizationService/OrganizationService.Service/ApiModels/Class/UpdateClassRequest.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OrganizationService.Service.ApiModels.Class +{ + public class UpdateClassRequest + { + public string? Name { get; set; } + public string? Description { get; set; } + public Guid? GradeId { get; set; } + } +} diff --git a/OrganizationService/OrganizationService.Service/ApiModels/Grade/CreateGradeRequest.cs b/OrganizationService/OrganizationService.Service/ApiModels/Grade/CreateGradeRequest.cs new file mode 100644 index 00000000..4a238662 --- /dev/null +++ b/OrganizationService/OrganizationService.Service/ApiModels/Grade/CreateGradeRequest.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OrganizationService.Service.ApiModels.Grade +{ + public class CreateGradeRequest + { + public string Name { get; set; } = string.Empty; + public string? Description { get; set; } + public Guid OrganizationId { get; set; } + } +} diff --git a/OrganizationService/OrganizationService.Service/ApiModels/Grade/GradeModel.cs b/OrganizationService/OrganizationService.Service/ApiModels/Grade/GradeModel.cs new file mode 100644 index 00000000..0ab9a80a --- /dev/null +++ b/OrganizationService/OrganizationService.Service/ApiModels/Grade/GradeModel.cs @@ -0,0 +1,13 @@ +using OrganizationService.Core.ApiModels; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OrganizationService.Service.ApiModels.Grade +{ + public class GradeModel : PagingBaseModel + { + } +} diff --git a/OrganizationService/OrganizationService.Service/ApiModels/Grade/UpdateGradeRequest.cs b/OrganizationService/OrganizationService.Service/ApiModels/Grade/UpdateGradeRequest.cs new file mode 100644 index 00000000..4785e269 --- /dev/null +++ b/OrganizationService/OrganizationService.Service/ApiModels/Grade/UpdateGradeRequest.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OrganizationService.Service.ApiModels.Grade +{ + public class UpdateGradeRequest + { + public string? GradeName { get; set; } + public string? Description { get; set; } + } +} diff --git a/OrganizationService/OrganizationService.Service/ApiModels/Organization/CreateOrganizationRequest.cs b/OrganizationService/OrganizationService.Service/ApiModels/Organization/CreateOrganizationRequest.cs new file mode 100644 index 00000000..d4dd3784 --- /dev/null +++ b/OrganizationService/OrganizationService.Service/ApiModels/Organization/CreateOrganizationRequest.cs @@ -0,0 +1,21 @@ +using OrganizationService.Core.Constants; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OrganizationService.Service.ApiModels.Organization +{ + public class CreateOrganizationRequest + { + public string Name { get; set; } = string.Empty; + public string? Description { get; set; } + public string? Address { get; set; } + public string? Email { get; set; } + public string? Phone { get; set; } + public Guid? Logo { get; set; } + public string? LogoUrl { get; set; } + public OrganizationStatus Status { get; set; } + } +} diff --git a/OrganizationService/OrganizationService.Service/ApiModels/Organization/OrganizationModel.cs b/OrganizationService/OrganizationService.Service/ApiModels/Organization/OrganizationModel.cs new file mode 100644 index 00000000..f53934e1 --- /dev/null +++ b/OrganizationService/OrganizationService.Service/ApiModels/Organization/OrganizationModel.cs @@ -0,0 +1,13 @@ +using OrganizationService.Core.ApiModels; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OrganizationService.Service.ApiModels.Organization +{ + public class OrganizationModel : PagingBaseModel + { + } +} diff --git a/OrganizationService/OrganizationService.Service/ApiModels/Organization/UpdateOrganizationRequest.cs b/OrganizationService/OrganizationService.Service/ApiModels/Organization/UpdateOrganizationRequest.cs new file mode 100644 index 00000000..b3cfeddc --- /dev/null +++ b/OrganizationService/OrganizationService.Service/ApiModels/Organization/UpdateOrganizationRequest.cs @@ -0,0 +1,21 @@ +using OrganizationService.Core.Constants; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OrganizationService.Service.ApiModels.Organization +{ + public class UpdateOrganizationRequest + { + public string Name { get; set; } = string.Empty; + public string? Description { get; set; } + public string? Address { get; set; } + public string? Email { get; set; } + public string? Phone { get; set; } + public Guid? Logo { get; set; } + public string? LogoUrl { get; set; } + public OrganizationStatus Status { get; set; } + } +} diff --git a/OrganizationService/OrganizationService.Service/ApiModels/OrganizationMember/CreateOrganizationMemberRequest.cs b/OrganizationService/OrganizationService.Service/ApiModels/OrganizationMember/CreateOrganizationMemberRequest.cs new file mode 100644 index 00000000..dfde11dc --- /dev/null +++ b/OrganizationService/OrganizationService.Service/ApiModels/OrganizationMember/CreateOrganizationMemberRequest.cs @@ -0,0 +1,18 @@ +using OrganizationService.Core.Constants; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OrganizationService.Service.ApiModels.OrganizationMember +{ + public class CreateOrganizationMemberRequest + { + public Guid UserId { get; set; } + public ScopeType ScopeType { get; set; } + public Guid ScopeId { get; set; } + public MemberRole Role { get; set; } + public bool IsActive { get; set; } + } +} diff --git a/OrganizationService/OrganizationService.Service/ApiModels/OrganizationMember/OrganizationMemberModel.cs b/OrganizationService/OrganizationService.Service/ApiModels/OrganizationMember/OrganizationMemberModel.cs new file mode 100644 index 00000000..859fb4d3 --- /dev/null +++ b/OrganizationService/OrganizationService.Service/ApiModels/OrganizationMember/OrganizationMemberModel.cs @@ -0,0 +1,13 @@ +using OrganizationService.Core.ApiModels; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OrganizationService.Service.ApiModels.OrganizationMember +{ + public class OrganizationMemberModel : PagingBaseModel + { + } +} diff --git a/OrganizationService/OrganizationService.Service/ApiModels/OrganizationMember/UpdateOrganizationMemberRequest.cs b/OrganizationService/OrganizationService.Service/ApiModels/OrganizationMember/UpdateOrganizationMemberRequest.cs new file mode 100644 index 00000000..1400fc1c --- /dev/null +++ b/OrganizationService/OrganizationService.Service/ApiModels/OrganizationMember/UpdateOrganizationMemberRequest.cs @@ -0,0 +1,15 @@ +using OrganizationService.Core.Constants; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OrganizationService.Service.ApiModels.OrganizationMember +{ + public class UpdateOrganizationMemberRequest + { + public MemberRole Role { get; set; } + public bool IsActive { get; set; } + } +} diff --git a/OrganizationService/OrganizationService.Service/ApiModels/StudentCredential/StudentCredentialModel.cs b/OrganizationService/OrganizationService.Service/ApiModels/StudentCredential/StudentCredentialModel.cs index f4778c4e..24daa46e 100644 --- a/OrganizationService/OrganizationService.Service/ApiModels/StudentCredential/StudentCredentialModel.cs +++ b/OrganizationService/OrganizationService.Service/ApiModels/StudentCredential/StudentCredentialModel.cs @@ -9,5 +9,9 @@ namespace OrganizationService.Service.ApiModels.StudentCredential { public class StudentCredentialModel : PagingBaseModel { + public Guid? OrganizationId { get; set; } + public Guid? GradeId { get; set; } + public Guid? ClassId { get; set; } + public bool? IsUsed { get; set; } } } diff --git a/OrganizationService/OrganizationService.Service/Dtos/Class/ClassDto.cs b/OrganizationService/OrganizationService.Service/Dtos/Class/ClassDto.cs new file mode 100644 index 00000000..10a24ccb --- /dev/null +++ b/OrganizationService/OrganizationService.Service/Dtos/Class/ClassDto.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OrganizationService.Service.Dtos.Class +{ + public class ClassDto + { + public Guid Id { get; set; } + public string Name { get; set; } = string.Empty; + public string? Description { get; set; } + public Guid GradeId { get; set; } + public string GradeName { get; set; } = string.Empty; + } +} diff --git a/OrganizationService/OrganizationService.Service/Dtos/Grade/GradeDto.cs b/OrganizationService/OrganizationService.Service/Dtos/Grade/GradeDto.cs new file mode 100644 index 00000000..3879c336 --- /dev/null +++ b/OrganizationService/OrganizationService.Service/Dtos/Grade/GradeDto.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OrganizationService.Service.Dtos.Grade +{ + public class GradeDto + { + public Guid Id { get; set; } + public string Name { get; set; } = string.Empty; + public string? Description { get; set; } + public Guid OrganizationId { get; set; } + public string OrganizationName { get; set; } = string.Empty; + } +} diff --git a/OrganizationService/OrganizationService.Service/Dtos/Organization/OrganizationDto.cs b/OrganizationService/OrganizationService.Service/Dtos/Organization/OrganizationDto.cs new file mode 100644 index 00000000..a7d4ee2c --- /dev/null +++ b/OrganizationService/OrganizationService.Service/Dtos/Organization/OrganizationDto.cs @@ -0,0 +1,22 @@ +using OrganizationService.Core.Constants; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OrganizationService.Service.Dtos.Organization +{ + public class OrganizationDto + { + public Guid Id { get; set; } + public string Name { get; set; } = string.Empty; + public string? Description { get; set; } + public string? Address { get; set; } + public string? Email { get; set; } + public string? Phone { get; set; } + public Guid? Logo { get; set; } + public string? LogoUrl { get; set; } + public OrganizationStatus Status { get; set; } + } +} diff --git a/OrganizationService/OrganizationService.Service/Dtos/OrganizationMember/OrganizationMemberDto.cs b/OrganizationService/OrganizationService.Service/Dtos/OrganizationMember/OrganizationMemberDto.cs new file mode 100644 index 00000000..61896c3b --- /dev/null +++ b/OrganizationService/OrganizationService.Service/Dtos/OrganizationMember/OrganizationMemberDto.cs @@ -0,0 +1,20 @@ +using OrganizationService.Core.Constants; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OrganizationService.Service.Dtos.OrganizationMember +{ + public class OrganizationMemberDto + { + public Guid Id { get; set; } + public Guid UserId { get; set; } + public ScopeType ScopeType { get; set; } + public string ScopeName { get; set; } = string.Empty; + public Guid ScopeId { get; set; } + public MemberRole Role { get; set; } + public bool IsActive { get; set; } + } +} diff --git a/OrganizationService/OrganizationService.Service/Dtos/StudentCredential/StudentCredentialDto.cs b/OrganizationService/OrganizationService.Service/Dtos/StudentCredential/StudentCredentialDto.cs index c79c0852..d3486f56 100644 --- a/OrganizationService/OrganizationService.Service/Dtos/StudentCredential/StudentCredentialDto.cs +++ b/OrganizationService/OrganizationService.Service/Dtos/StudentCredential/StudentCredentialDto.cs @@ -10,7 +10,9 @@ public class StudentCredentialDto { public Guid Id { get; set; } public Guid OrganizationId { get; set; } + public string OrganizationName { get; set; } = string.Empty; public Guid ClassId { get; set; } + public string ClassName { get; set; } = string.Empty; public string Username { get; set; } = string.Empty; public bool IsUsed { get; set; } } diff --git a/OrganizationService/OrganizationService.Service/Implementation/ClassService.cs b/OrganizationService/OrganizationService.Service/Implementation/ClassService.cs new file mode 100644 index 00000000..d6027e61 --- /dev/null +++ b/OrganizationService/OrganizationService.Service/Implementation/ClassService.cs @@ -0,0 +1,135 @@ +using Microsoft.EntityFrameworkCore; +using OrganizationService.Core.ApiModels; +using OrganizationService.Core.Enums; +using OrganizationService.Core.Exceptions; +using OrganizationService.DataAccess.Interfaces; +using OrganizationService.DataAccess.Models; +using OrganizationService.Service.ApiModels.Class; +using OrganizationService.Service.Dtos.Class; +using OrganizationService.Service.Interfaces; + +namespace OrganizationService.Service.Implementation +{ + public class ClassService : BaseService, IClassService + { + private readonly IRepository _classRepository; + private readonly IRepository _gradeRepository; + + public ClassService( + AppSettings appSettings, + IUnitOfWork unitOfWork, + UserContext userContext, + IRepository classRepository, + IRepository gradeRepository) + : base(appSettings, unitOfWork, userContext) + { + _classRepository = classRepository; + _gradeRepository = gradeRepository; + } + + private void ValidatePagingModel(ClassModel classModel) + { + if (classModel.PageIndex < 1) + throw new ErrorException(Core.Enums.StatusCodeEnum.PageIndexInvalid); + if (classModel.PageSize < 1) + throw new ErrorException(Core.Enums.StatusCodeEnum.PageSizeInvalid); + } + + public async Task> GetViewModelsAsync(ClassModel classModel) + { + // Validate PageIndex and PageSize + ValidatePagingModel(classModel); + + var query = _classRepository.AsNoTracking.Include(c => c.Grade).Where(c => !c.IsDeleted); + + return await query.Select(c => new ClassDto + { + Id = c.Id, + Name = c.Name, + Description = c.Description, + GradeId = c.GradeId, + GradeName = c.Grade.Name + }).ToListAsync(); + } + + public async Task GetByIdAsync(Guid id) + { + var data = await _classRepository.AsNoTracking + .Include(c => c.Grade) + .FirstOrDefaultAsync(c => c.Id == id && !c.IsDeleted); + + if (data == null) + { + throw new ErrorException(StatusCodeEnum.A02, "Class not found"); + } + + return new ClassDto + { + Id = data.Id, + Name = data.Name, + Description = data.Description, + GradeId = data.GradeId, + GradeName = data.Grade.Name + }; + } + + public async Task CreateAsync(CreateClassRequest request) + { + var grade = await _gradeRepository.FindByIdAsync(request.GradeId) + ?? throw new ErrorException(StatusCodeEnum.A02, "Grade not found"); + + var entity = new Class + { + Id = Guid.NewGuid(), + Name = request.ClassName, + Description = request.Description, + GradeId = request.GradeId, + CreatedAt = DateTime.UtcNow + }; + + await _classRepository.CreateAsync(entity); + await _unitOfWork.SaveChangesAsync(); + + return new ClassDto + { + Id = entity.Id, + Name = entity.Name, + Description = entity.Description, + GradeId = entity.GradeId, + GradeName = grade.Name + }; + } + + public async Task UpdateAsync(Guid id, UpdateClassRequest request) + { + var entity = await _classRepository.FindByIdAsync(id); + if (entity == null) + { + throw new ErrorException(StatusCodeEnum.A02, "Class not found"); + } + + if (!string.IsNullOrWhiteSpace(request.Name)) entity.Name = request.Name; + if (request.GradeId.HasValue) entity.GradeId = request.GradeId.Value; + + entity.UpdatedAt = DateTime.UtcNow; + + await _unitOfWork.SaveChangesAsync(); + return true; + } + + public async Task DeleteAsync(Guid id) + { + var entity = await _classRepository.FindByIdAsync(id); + if (entity == null) + { + throw new ErrorException(StatusCodeEnum.A02, "Class not found"); + } + + entity.IsDeleted = true; + + _classRepository.Delete(entity); + await _unitOfWork.SaveChangesAsync(); + return true; + } + } +} diff --git a/OrganizationService/OrganizationService.Service/Implementation/GradeService.cs b/OrganizationService/OrganizationService.Service/Implementation/GradeService.cs new file mode 100644 index 00000000..71783b04 --- /dev/null +++ b/OrganizationService/OrganizationService.Service/Implementation/GradeService.cs @@ -0,0 +1,156 @@ +using Microsoft.EntityFrameworkCore; +using OrganizationService.Core.ApiModels; +using OrganizationService.Core.Exceptions; +using OrganizationService.DataAccess.Interfaces; +using OrganizationService.DataAccess.Models; +using OrganizationService.Service.ApiModels.Grade; +using OrganizationService.Service.Dtos.Grade; +using OrganizationService.Service.Interfaces; + +namespace OrganizationService.Service.Implementation +{ + public class GradeService : BaseService, IGradeService + { + private readonly IRepository _gradeRepository; + private readonly IRepository _organizationRepository; + + public GradeService( + AppSettings appSettings, + IUnitOfWork unitOfWork, + UserContext userContext, + IRepository organizationRepository, + IRepository gradeRepository + ) + : base(appSettings, unitOfWork, userContext) + { + _organizationRepository = organizationRepository; + _gradeRepository = gradeRepository; + } + + private void ValidatePagingModel(GradeModel gradeModel) + { + if (gradeModel.PageIndex < 1) + throw new ErrorException(Core.Enums.StatusCodeEnum.PageIndexInvalid); + if (gradeModel.PageSize < 1) + throw new ErrorException(Core.Enums.StatusCodeEnum.PageSizeInvalid); + } + public async Task> GetViewModelsAsync(GradeModel gradeModel) + { + // Validate PageIndex and PageSize + ValidatePagingModel(gradeModel); + + var data = _gradeRepository.AsNoTracking + .Where(c => !c.IsDeleted) + .OrderByDescending(c => c.CreatedAt) + .Select(c => new GradeDto + { + Id = c.Id, + Name = c.Name, + OrganizationId = c.OrganizationId, + OrganizationName = _organizationRepository.AsNoTracking + .Where(o => o.Id == c.OrganizationId) + .Select(o => o.Name) + .FirstOrDefault() ?? string.Empty, + }); + return await data.ToListAsync(); + } + + public async Task GetByIdAsync(Guid id) + { + var grade = await _gradeRepository.AsNoTracking + .FirstOrDefaultAsync(c => c.Id == id); + if (grade == null) + { + throw new ErrorException(Core.Enums.StatusCodeEnum.A02, "Grade not found"); + } + + var orgName = await _organizationRepository.AsNoTracking + .Where(o => o.Id == grade.OrganizationId) + .Select(o => o.Name) + .FirstOrDefaultAsync() ?? string.Empty; + + return new GradeDto + { + Id = grade.Id, + Name = grade.Name, + Description = grade.Description, + OrganizationId = grade.OrganizationId, + OrganizationName = orgName + }; + } + + public async Task CreateAsync(CreateGradeRequest request) + { + var grade = new Grade + { + Id = Guid.NewGuid(), + Name = request.Name, + Description = request.Description, + OrganizationId = request.OrganizationId + }; + + await _gradeRepository.CreateAsync(grade); + await _unitOfWork.SaveChangesAsync(); + + var orgName = await _organizationRepository.AsNoTracking + .Where(o => o.Id == grade.OrganizationId) + .Select(o => o.Name) + .FirstOrDefaultAsync() ?? string.Empty; + + return new GradeDto + { + Id = grade.Id, + Name = grade.Name, + Description = grade.Description, + OrganizationId = grade.OrganizationId, + OrganizationName = orgName + }; + } + + public async Task UpdateAsync(Guid id, UpdateGradeRequest request) + { + var grade = await _gradeRepository.FindByIdAsync(id); + if (grade == null) + { + throw new ErrorException(Core.Enums.StatusCodeEnum.A02, "Grade not found"); + } + + grade.Name = request.GradeName; + grade.Description = request.Description; + _gradeRepository.Update(grade); + + await _unitOfWork.SaveChangesAsync(); + + var orgName = await _organizationRepository.AsNoTracking + .Where(o => o.Id == grade.OrganizationId) + .Select(o => o.Name) + .FirstOrDefaultAsync() ?? string.Empty; + + return new GradeDto + { + Id = grade.Id, + Name = grade.Name, + Description = grade.Description, + OrganizationId = grade.OrganizationId, + OrganizationName = orgName + }; + } + + public async Task DeleteAsync(Guid id) + { + var grade = await _gradeRepository.FindByIdAsync(id); + + if (grade == null) + throw new ErrorException(Core.Enums.StatusCodeEnum.A02, "Grade not found"); + + grade.DeletedAt = DateTime.UtcNow; + grade.DeletedBy = _userContext.UserId; + grade.IsDeleted = true; + + _gradeRepository.Update(grade); + await _unitOfWork.SaveChangesAsync(); + + return true; + } + } +} diff --git a/OrganizationService/OrganizationService.Service/Implementation/OrganizationMemberService.cs b/OrganizationService/OrganizationService.Service/Implementation/OrganizationMemberService.cs new file mode 100644 index 00000000..6997fdcb --- /dev/null +++ b/OrganizationService/OrganizationService.Service/Implementation/OrganizationMemberService.cs @@ -0,0 +1,165 @@ +using Microsoft.EntityFrameworkCore; +using OrganizationService.Core.ApiModels; +using OrganizationService.Core.Exceptions; +using OrganizationService.DataAccess.Interfaces; +using OrganizationService.DataAccess.Models; +using OrganizationService.Service.ApiModels.OrganizationMember; +using OrganizationService.Service.Dtos.OrganizationMember; +using OrganizationService.Service.Interfaces; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OrganizationService.Service.Implementation +{ + public class OrganizationMemberService : BaseService, IOrganizationMemberService + { + private readonly IRepository _organizationMemberRepository; + private readonly IRepository _organizationRepository; + + + public OrganizationMemberService( + AppSettings appSettings, + IUnitOfWork unitOfWork, + UserContext userContext, + IRepository organizationMemberRepository, + IRepository organizationRepository + ) : base(appSettings, unitOfWork, userContext) + { + _organizationMemberRepository = organizationMemberRepository; + _organizationRepository = organizationRepository; + } + + private void ValidatePagingModel(OrganizationMemberModel orgMemberModel) + { + if (orgMemberModel.PageIndex < 1) + throw new ErrorException(Core.Enums.StatusCodeEnum.PageIndexInvalid); + if (orgMemberModel.PageSize < 1) + throw new ErrorException(Core.Enums.StatusCodeEnum.PageSizeInvalid); + } + + public async Task> GetViewModelsAsync(OrganizationMemberModel orgMemberModel) + { + + // Validate PageIndex and PageSize + ValidatePagingModel(orgMemberModel); + + var query = _organizationMemberRepository.AsNoTracking + .Where(x => !x.IsDeleted) + .OrderByDescending(x => x.CreatedAt); + + var list = await query.ToListAsync(); + + var result = new List(); + foreach (var m in list) + { + var orgName = (await _organizationRepository.FindByIdAsync(m.ScopeId))?.Name ?? string.Empty; + + result.Add(new OrganizationMemberDto + { + Id = m.Id, + UserId = m.UserId, + ScopeType = m.ScopeType, + ScopeId = m.ScopeId, + Role = m.Role, + IsActive = m.IsActive, + ScopeName = orgName + }); + } + + return result; + } + + public async Task GetByIdAsync(Guid id) + { + var m = await _organizationMemberRepository.AsNoTracking + .FirstOrDefaultAsync(x => x.Id == id && !x.IsDeleted); + + if (m == null) + throw new ErrorException(Core.Enums.StatusCodeEnum.A02, "Organization member not found"); + + var orgName = (await _organizationRepository.FindByIdAsync(m.ScopeId))?.Name ?? string.Empty; + + return new OrganizationMemberDto + { + Id = m.Id, + UserId = m.UserId, + ScopeType = m.ScopeType, + ScopeId = m.ScopeId, + Role = m.Role, + IsActive = m.IsActive, + ScopeName = orgName + }; + } + + public async Task CreateAsync(CreateOrganizationMemberRequest request) + { + var entity = new OrganizationMember + { + Id = Guid.NewGuid(), + UserId = request.UserId, + ScopeType = request.ScopeType, + ScopeId = request.ScopeId, + Role = request.Role, + IsActive = request.IsActive + }; + + await _organizationMemberRepository.CreateAsync(entity); + await _unitOfWork.SaveChangesAsync(); + + var orgName = (await _organizationRepository.FindByIdAsync(entity.ScopeId))?.Name ?? string.Empty; + + return new OrganizationMemberDto + { + Id = entity.Id, + UserId = entity.UserId, + ScopeType = entity.ScopeType, + ScopeId = entity.ScopeId, + Role = entity.Role, + IsActive = entity.IsActive, + ScopeName = orgName + }; + } + + public async Task UpdateAsync(Guid id, UpdateOrganizationMemberRequest request) + { + var entity = await _organizationMemberRepository.FindByIdAsync(id); + + if (entity == null) + throw new ErrorException(Core.Enums.StatusCodeEnum.A02, "Organization member not found"); + + entity.Role = request.Role; + entity.IsActive = request.IsActive; + + _organizationMemberRepository.Update(entity); + await _unitOfWork.SaveChangesAsync(); + + var orgName = (await _organizationRepository.FindByIdAsync(entity.ScopeId))?.Name ?? string.Empty; + + return new OrganizationMemberDto + { + Id = entity.Id, + UserId = entity.UserId, + ScopeType = entity.ScopeType, + ScopeId = entity.ScopeId, + Role = entity.Role, + IsActive = entity.IsActive, + ScopeName = orgName + }; + } + + public async Task DeleteAsync(Guid id) + { + var entity = await _organizationMemberRepository.FindByIdAsync(id); + + if (entity == null) + throw new ErrorException(Core.Enums.StatusCodeEnum.A02, "Organization member not found"); + + _organizationMemberRepository.Delete(entity); + await _unitOfWork.SaveChangesAsync(); + return true; + } + } +} diff --git a/OrganizationService/OrganizationService.Service/Implementation/OrganizationService.cs b/OrganizationService/OrganizationService.Service/Implementation/OrganizationService.cs new file mode 100644 index 00000000..439b16c0 --- /dev/null +++ b/OrganizationService/OrganizationService.Service/Implementation/OrganizationService.cs @@ -0,0 +1,177 @@ +using Microsoft.EntityFrameworkCore; +using OrganizationService.Core.ApiModels; +using OrganizationService.Core.Exceptions; +using OrganizationService.DataAccess.Interfaces; +using OrganizationService.DataAccess.Models; +using OrganizationService.Service.ApiModels.Grade; +using OrganizationService.Service.ApiModels.Organization; +using OrganizationService.Service.Dtos.Organization; +using OrganizationService.Service.Interfaces; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OrganizationService.Service.Implementation +{ + public class OrganizationService : BaseService, IOrganizationService + { + private readonly IRepository _organizationRepository; + + public OrganizationService( + AppSettings appSettings, + IUnitOfWork unitOfWork, + UserContext userContext, + IRepository organizationRepository + ) : base(appSettings, unitOfWork, userContext) + { + _organizationRepository = organizationRepository; + } + + private void ValidatePagingModel(OrganizationModel orgModel) + { + if (orgModel.PageIndex < 1) + throw new ErrorException(Core.Enums.StatusCodeEnum.PageIndexInvalid); + if (orgModel.PageSize < 1) + throw new ErrorException(Core.Enums.StatusCodeEnum.PageSizeInvalid); + } + + public async Task> GetViewModelsAsync(OrganizationModel orgModel) + { + + // Validate PageIndex and PageSize + ValidatePagingModel(orgModel); + + var orgs = _organizationRepository.AsNoTracking + .Where(o => !o.IsDeleted) + .OrderByDescending(o => o.CreatedAt) + .Select(o => new OrganizationDto + { + Id = o.Id, + Name = o.Name, + Description = o.Description, + Address = o.Address, + Email = o.Email, + Phone = o.Phone, + Logo = o.Logo, + LogoUrl = o.LogoUrl, + Status = o.Status + }); + + + return await orgs.ToListAsync(); + } + + public async Task GetByIdAsync(Guid id) + { + var org = await _organizationRepository.AsNoTracking + .FirstOrDefaultAsync(o => o.Id == id && !o.IsDeleted); + + if (org == null) + throw new ErrorException(Core.Enums.StatusCodeEnum.A02, "Organization not found"); + + return new OrganizationDto + { + Id = org.Id, + Name = org.Name, + Description = org.Description, + Address = org.Address, + Email = org.Email, + Phone = org.Phone, + Logo = org.Logo, + LogoUrl = org.LogoUrl, + Status = org.Status + }; + } + + public async Task CreateAsync(CreateOrganizationRequest request) + { + var existingOrg = await _organizationRepository.FindAsync(o => o.Name.ToLower() == request.Name.ToLower()); + if (existingOrg != null) + throw new ErrorException(Core.Enums.StatusCodeEnum.A03, "Organization with this name already exists"); + + + var entity = new Organization + { + Id = Guid.NewGuid(), + Name = request.Name, + Description = request.Description, + Address = request.Address, + Email = request.Email, + Phone = request.Phone, + Logo = request?.Logo, + LogoUrl = request?.LogoUrl, + Status = request.Status, + CreatedAt = DateTime.UtcNow, + CreatedBy = _userContext.UserId + }; + + await _organizationRepository.CreateAsync(entity); + await _unitOfWork.SaveChangesAsync(); + + return new OrganizationDto + { + Id = entity.Id, + Name = entity.Name, + Description = entity.Description, + Address = entity.Address, + Email = entity.Email, + Phone = entity.Phone, + Logo = entity.Logo, + LogoUrl = entity.LogoUrl, + Status = entity.Status + }; + } + + public async Task UpdateAsync(Guid id, UpdateOrganizationRequest request) + { + var entity = await _organizationRepository.FindByIdAsync(id); + if (entity == null) + throw new ErrorException(Core.Enums.StatusCodeEnum.A02, "Organization not found"); + + entity.Name = request.Name; + entity.Description = request.Description; + entity.Address = request.Address; + entity.Email = request.Email; + entity.Phone = request.Phone; + entity.Logo = request.Logo; + entity.LogoUrl = request.LogoUrl; + entity.Status = request.Status; + entity.UpdatedAt = DateTime.UtcNow; + entity.UpdatedBy = _userContext.UserId; + + _organizationRepository.Update(entity); + await _unitOfWork.SaveChangesAsync(); + + return new OrganizationDto + { + Id = entity.Id, + Name = entity.Name, + Description = entity.Description, + Address = entity.Address, + Email = entity.Email, + Phone = entity.Phone, + Logo = entity.Logo, + LogoUrl = entity.LogoUrl, + Status = entity.Status + }; + } + + public async Task DeleteAsync(Guid id) + { + var entity = await _organizationRepository.FindByIdAsync(id); + if (entity == null) + throw new ErrorException(Core.Enums.StatusCodeEnum.A02, "Organization not found"); + + entity.IsDeleted = true; + entity.DeletedAt = DateTime.UtcNow; + entity.DeletedBy = _userContext.UserId; + + _organizationRepository.Update(entity); + await _unitOfWork.SaveChangesAsync(); + return true; + } + } + +} diff --git a/OrganizationService/OrganizationService.Service/Implementation/StudentCredentialService.cs b/OrganizationService/OrganizationService.Service/Implementation/StudentCredentialService.cs index b95a1396..5647fc6a 100644 --- a/OrganizationService/OrganizationService.Service/Implementation/StudentCredentialService.cs +++ b/OrganizationService/OrganizationService.Service/Implementation/StudentCredentialService.cs @@ -1,5 +1,6 @@ using Microsoft.EntityFrameworkCore; using OrganizationService.Core.ApiModels; +using OrganizationService.Core.Enums; using OrganizationService.Core.Exceptions; using OrganizationService.DataAccess.Interfaces; using OrganizationService.DataAccess.Models; @@ -11,27 +12,22 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using static Microsoft.EntityFrameworkCore.DbLoggerCategory; namespace OrganizationService.Service.Implementation { public class StudentCredentialService : BaseService, IStudentCredentialService { private readonly IRepository _studentCredentialRepository; - private readonly IRepository _classRepository; - private readonly IRepository _organizationRepository; public StudentCredentialService( AppSettings appSettings, IUnitOfWork unitOfWork, UserContext userContext, - IRepository studentCredentialRepository, - IRepository classRepository, - IRepository organizationRepository) + IRepository studentCredentialRepository) : base(appSettings, unitOfWork, userContext) { _studentCredentialRepository = studentCredentialRepository; - _classRepository = classRepository; - _organizationRepository = organizationRepository; } private void ValidatePagingModel(StudentCredentialModel studentCredentialModel) @@ -47,10 +43,25 @@ public async Task> GetViewModelsAsync(StudentC // Validate PageIndex and PageSize ValidatePagingModel(studentCredentialModel); - var data = await _studentCredentialRepository.AsNoTracking - .Include(c => c.Class) - .Include(c => c.Organization) - .ToListAsync(); + var data = _studentCredentialRepository.AsNoTracking + .Include(c => c.Class) + .Include(c => c.Organization) + .Where(c => !c.IsDeleted) + .OrderByDescending(c => c.CreatedAt) + .Select(c => new StudentCredentialDto + { + Id = c.Id, + OrganizationId = c.OrganizationId, + ClassId = c.ClassId, + Username = c.Username, + IsUsed = c.IsUsed, + ClassName = c.Class.Name, + OrganizationName = c.Organization.Name + }); + + var list = await data.ToListAsync(); + + return list; } public async Task GetByIdAsync(Guid id) @@ -70,7 +81,9 @@ public async Task> GetViewModelsAsync(StudentC { Id = studentCredential.Id, OrganizationId = studentCredential.OrganizationId, + OrganizationName = studentCredential.Organization.Name, ClassId = studentCredential.ClassId, + ClassName = studentCredential.Class.Name, Username = studentCredential.Username, IsUsed = studentCredential.IsUsed }; @@ -78,6 +91,13 @@ public async Task> GetViewModelsAsync(StudentC public async Task CreateAsync(CreateStudentCredentialRequest request) { + + var exists = await _studentCredentialRepository.FindAsync(x => x.OrganizationId == request.OrganizationId && x.Username == request.Username && !x.IsDeleted); + if (exists == null) + { + throw new ErrorException(StatusCodeEnum.A01, "Username already exists."); + } + var credential = new StudentCredential { Id = Guid.NewGuid(), @@ -86,8 +106,7 @@ public async Task CreateAsync(CreateStudentCredentialReque Username = request.Username, PasswordHashed = BCrypt.Net.BCrypt.HashPassword(request.Password), IsUsed = false, - CreatedAt = DateTime.UtcNow, - CreatedBy = Guid.Empty // TODO: lấy từ context + CreatedAt = DateTime.UtcNow }; await _studentCredentialRepository.CreateAsync(credential); @@ -106,7 +125,7 @@ public async Task CreateAsync(CreateStudentCredentialReque public async Task UpdateAsync(Guid id, UpdateStudentCredentialRequest request) { - var cred = await _context.StudentCredentials.FindAsync(id); + var cred = await _studentCredentialRepository.FindByIdAsync(id); if (cred == null) return false; if (!string.IsNullOrWhiteSpace(request.Password)) @@ -120,21 +139,24 @@ public async Task UpdateAsync(Guid id, UpdateStudentCredentialRequest requ } cred.UpdatedAt = DateTime.UtcNow; - cred.UpdatedBy = Guid.Empty; // TODO: lấy từ context - await _context.SaveChangesAsync(); + await _unitOfWork.SaveChangesAsync(); return true; } public async Task DeleteAsync(Guid id) { - var cred = await _context.StudentCredentials.FindAsync(id); - if (cred == null) return false; + var data = await _studentCredentialRepository.FindByIdAsync(id); + if (data == null) + { + throw new ErrorException(Core.Enums.StatusCodeEnum.A02, "Student credential not found."); + } - _context.StudentCredentials.Remove(cred); - await _context.SaveChangesAsync(); + data.IsDeleted = true; + + _studentCredentialRepository.Delete(data); + await _unitOfWork.SaveChangesAsync(); return true; } } - } diff --git a/OrganizationService/OrganizationService.Service/Interfaces/IClassService.cs b/OrganizationService/OrganizationService.Service/Interfaces/IClassService.cs new file mode 100644 index 00000000..cb0817c1 --- /dev/null +++ b/OrganizationService/OrganizationService.Service/Interfaces/IClassService.cs @@ -0,0 +1,19 @@ +using OrganizationService.Service.ApiModels.Class; +using OrganizationService.Service.Dtos.Class; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OrganizationService.Service.Interfaces +{ + public interface IClassService + { + Task> GetViewModelsAsync(ClassModel classModel); + Task GetByIdAsync(Guid id); + Task CreateAsync(CreateClassRequest request); + Task UpdateAsync(Guid id, UpdateClassRequest request); + Task DeleteAsync(Guid id); + } +} diff --git a/OrganizationService/OrganizationService.Service/Interfaces/IGradeService.cs b/OrganizationService/OrganizationService.Service/Interfaces/IGradeService.cs new file mode 100644 index 00000000..9046d19e --- /dev/null +++ b/OrganizationService/OrganizationService.Service/Interfaces/IGradeService.cs @@ -0,0 +1,19 @@ +using OrganizationService.Service.ApiModels.Grade; +using OrganizationService.Service.Dtos.Grade; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OrganizationService.Service.Interfaces +{ + public interface IGradeService + { + Task> GetViewModelsAsync(GradeModel gradeModel); + Task CreateAsync(CreateGradeRequest request); + Task GetByIdAsync(Guid id); + Task UpdateAsync(Guid id, UpdateGradeRequest request); + Task DeleteAsync(Guid id); + } +} diff --git a/OrganizationService/OrganizationService.Service/Interfaces/IOrganizationMemberService.cs b/OrganizationService/OrganizationService.Service/Interfaces/IOrganizationMemberService.cs new file mode 100644 index 00000000..eaac5546 --- /dev/null +++ b/OrganizationService/OrganizationService.Service/Interfaces/IOrganizationMemberService.cs @@ -0,0 +1,20 @@ +using OrganizationService.Core.Constants; +using OrganizationService.Service.ApiModels.OrganizationMember; +using OrganizationService.Service.Dtos.OrganizationMember; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OrganizationService.Service.Interfaces +{ + public interface IOrganizationMemberService + { + Task> GetViewModelsAsync(OrganizationMemberModel orgMemberModel); + Task GetByIdAsync(Guid id); + Task CreateAsync(CreateOrganizationMemberRequest request); + Task UpdateAsync(Guid id, UpdateOrganizationMemberRequest request); + Task DeleteAsync(Guid id); + } +} diff --git a/OrganizationService/OrganizationService.Service/Interfaces/IOrganizationService.cs b/OrganizationService/OrganizationService.Service/Interfaces/IOrganizationService.cs new file mode 100644 index 00000000..67cda328 --- /dev/null +++ b/OrganizationService/OrganizationService.Service/Interfaces/IOrganizationService.cs @@ -0,0 +1,19 @@ +using OrganizationService.Service.ApiModels.Organization; +using OrganizationService.Service.Dtos.Organization; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OrganizationService.Service.Interfaces +{ + public interface IOrganizationService + { + Task> GetViewModelsAsync(OrganizationModel orgModel); + Task GetByIdAsync(Guid id); + Task CreateAsync(CreateOrganizationRequest request); + Task UpdateAsync(Guid id, UpdateOrganizationRequest request); + Task DeleteAsync(Guid id); + } +} diff --git a/OrganizationService/OrganizationService.Service/Interfaces/IStudentCredentialService.cs b/OrganizationService/OrganizationService.Service/Interfaces/IStudentCredentialService.cs index c361a1a7..01ab41f9 100644 --- a/OrganizationService/OrganizationService.Service/Interfaces/IStudentCredentialService.cs +++ b/OrganizationService/OrganizationService.Service/Interfaces/IStudentCredentialService.cs @@ -10,9 +10,9 @@ namespace OrganizationService.Service.Interfaces { public interface IStudentCredentialService { + Task> GetViewModelsAsync(StudentCredentialModel studentCredentialModel); + Task GetByIdAsync(Guid id); Task CreateAsync(CreateStudentCredentialRequest request); - Task GetByIdAsync(Guid id); - Task> GetByClassIdAsync(Guid classId); Task UpdateAsync(Guid id, UpdateStudentCredentialRequest request); Task DeleteAsync(Guid id); } diff --git a/OrganizationService/OrganizationService.Service/OrganizationService.Service.csproj b/OrganizationService/OrganizationService.Service/OrganizationService.Service.csproj index 5df399b9..5a6e88cb 100644 --- a/OrganizationService/OrganizationService.Service/OrganizationService.Service.csproj +++ b/OrganizationService/OrganizationService.Service/OrganizationService.Service.csproj @@ -7,6 +7,7 @@ + diff --git a/OrganizationService/OrganizationService.UnitTests/OrganizationService.UnitTests.csproj b/OrganizationService/OrganizationService.UnitTests/OrganizationService.UnitTests.csproj index 27ab31f3..578579ee 100644 --- a/OrganizationService/OrganizationService.UnitTests/OrganizationService.UnitTests.csproj +++ b/OrganizationService/OrganizationService.UnitTests/OrganizationService.UnitTests.csproj @@ -10,6 +10,7 @@ +