From 40f83cce77b9da832987772952c7f6d2e00a951b Mon Sep 17 00:00:00 2001 From: pytas0811 Date: Wed, 18 Oct 2023 21:41:19 +0700 Subject: [PATCH 01/10] optimize service --- .../Services/CustomerService.cs | 16 ++++++++++++---- .../Services/LaundryStoreService.cs | 5 ++++- .../Services/StaffService.cs | 11 ++++++++--- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/SWD-Laundry-Backend.Service/Services/CustomerService.cs b/src/SWD-Laundry-Backend.Service/Services/CustomerService.cs index cb2386e..400059c 100644 --- a/src/SWD-Laundry-Backend.Service/Services/CustomerService.cs +++ b/src/SWD-Laundry-Backend.Service/Services/CustomerService.cs @@ -40,8 +40,10 @@ public async Task DeleteAsync(string id, CancellationToken cancellationToke public async Task> GetAllAsync(CustomerQuery? query, CancellationToken cancellationToken = default) { var list = await _repository - .GetAsync(null, cancellationToken: cancellationToken, - c => c.ApplicationUser); + .GetAsync(null, cancellationToken: cancellationToken + , x => x.ApplicationUser + , c => c.ApplicationUser.Wallet + , c => c.Building); return await list.ToListAsync(cancellationToken); } @@ -49,13 +51,19 @@ public async Task> GetAllAsync(CustomerQuery? query, Cance public async Task GetByIdAsync(string id, CancellationToken cancellationToken = default) { - var customer = await _repository.GetSingleAsync(c => c.Id == id, cancellationToken, x => x.ApplicationUser); + var customer = await _repository.GetSingleAsync(c => c.Id == id, cancellationToken + , x => x.ApplicationUser + , c => c.ApplicationUser.Wallet + , c => c.Building); return customer; } public async Task> GetPaginatedAsync(CustomerQuery query, CancellationToken cancellationToken = default) { - var list = await _repository.GetAsync(cancellationToken: cancellationToken); + var list = await _repository.GetAsync(null ,cancellationToken: cancellationToken + , x => x.ApplicationUser + , c => c.ApplicationUser.Wallet + , c => c.Building); var result = await list.PaginatedListAsync(query); return result; diff --git a/src/SWD-Laundry-Backend.Service/Services/LaundryStoreService.cs b/src/SWD-Laundry-Backend.Service/Services/LaundryStoreService.cs index 9f927e2..09134ce 100644 --- a/src/SWD-Laundry-Backend.Service/Services/LaundryStoreService.cs +++ b/src/SWD-Laundry-Backend.Service/Services/LaundryStoreService.cs @@ -52,7 +52,10 @@ public async Task> GetAllAsync(LaundryStoreQuery? quer public async Task> GetPaginatedAsync(LaundryStoreQuery query, CancellationToken cancellationToken = default) { - var list = await _repository.GetAsync(cancellationToken: cancellationToken); + var list = await _repository.GetAsync(null + ,cancellationToken: cancellationToken + , c => c.ApplicationUser + , c => c.ApplicationUser.Wallet); var result = await list.PaginatedListAsync(query); return result; } diff --git a/src/SWD-Laundry-Backend.Service/Services/StaffService.cs b/src/SWD-Laundry-Backend.Service/Services/StaffService.cs index 897797e..157307c 100644 --- a/src/SWD-Laundry-Backend.Service/Services/StaffService.cs +++ b/src/SWD-Laundry-Backend.Service/Services/StaffService.cs @@ -40,20 +40,25 @@ public async Task> GetAllAsync(StaffQuery? query, Cancellatio var list = await _repository .GetAsync(null, cancellationToken: cancellationToken, - c => c.ApplicationUser); + c => c.ApplicationUser + , c => c.ApplicationUser.Wallet); return await list.ToListAsync(cancellationToken); } public async Task GetByIdAsync(string id, CancellationToken cancellationToken = default) { - var entity = await _repository.GetSingleAsync(c => c.Id == id, cancellationToken); + var entity = await _repository.GetSingleAsync(c => c.Id == id, cancellationToken + , c => c.ApplicationUser + , c => c.ApplicationUser.Wallet); return entity; } public async Task> GetPaginatedAsync(StaffQuery query, CancellationToken cancellationToken = default) { - var list = await _repository.GetAsync(null, cancellationToken: cancellationToken, c => c.ApplicationUser); + var list = await _repository.GetAsync(null, cancellationToken: cancellationToken + , c => c.ApplicationUser + , c => c.ApplicationUser.Wallet); var result = await list.PaginatedListAsync(query); return result; From da73f77f489b30dfc72b68ed76392d06d6f482a8 Mon Sep 17 00:00:00 2001 From: Nero <67089844+k-nero@users.noreply.github.com> Date: Fri, 20 Oct 2023 14:47:30 +0700 Subject: [PATCH 02/10] Authen response update --- .../Interface/IIdentityService.cs | 1 + .../Services/IdentityService.cs | 7 +++++++ .../Controllers/AuthenticateController.cs | 14 ++++++++++++-- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/SWD-Laundry-Backend.Contract.Service/Interface/IIdentityService.cs b/src/SWD-Laundry-Backend.Contract.Service/Interface/IIdentityService.cs index 68fc613..16bd87c 100644 --- a/src/SWD-Laundry-Backend.Contract.Service/Interface/IIdentityService.cs +++ b/src/SWD-Laundry-Backend.Contract.Service/Interface/IIdentityService.cs @@ -14,4 +14,5 @@ public interface IIdentityService : IBaseIdentityService public Task> GetClaimsAsync(ApplicationUser user); public Task SetVerfiedEmailAsync(ApplicationUser user, string email); + public Task SetWalletAsync(ApplicationUser user, string walletId); } diff --git a/src/SWD-Laundry-Backend.Service/Services/IdentityService.cs b/src/SWD-Laundry-Backend.Service/Services/IdentityService.cs index 0754179..1252eea 100644 --- a/src/SWD-Laundry-Backend.Service/Services/IdentityService.cs +++ b/src/SWD-Laundry-Backend.Service/Services/IdentityService.cs @@ -119,4 +119,11 @@ public async Task SetVerfiedEmailAsync(ApplicationUser user, string email) { await _userManager.SetEmailAsync(user, email); } + + public async Task SetWalletAsync(ApplicationUser user, string walletId) + { + user.WalletID = walletId; + var rs = await _userManager.UpdateAsync(user); + return rs.ToApplicationResult().Succeeded ? 1 : 0; + } } diff --git a/src/SWD-Laundry-Backend/Controllers/AuthenticateController.cs b/src/SWD-Laundry-Backend/Controllers/AuthenticateController.cs index 1a61ae0..0998646 100644 --- a/src/SWD-Laundry-Backend/Controllers/AuthenticateController.cs +++ b/src/SWD-Laundry-Backend/Controllers/AuthenticateController.cs @@ -9,6 +9,7 @@ using SWD_Laundry_Backend.Contract.Repository.Entity.IdentityModels; using SWD_Laundry_Backend.Contract.Service.Interface; using SWD_Laundry_Backend.Core.Config; +using SWD_Laundry_Backend.Core.Models; using SWD_Laundry_Backend.Core.Utils; namespace SWD_Laundry_Backend.Controllers; @@ -30,11 +31,13 @@ public class AuthenticateController : ApiControllerBase private readonly FirebaseApp _firebaseApp; private readonly IIdentityService _identityService; private readonly FirebaseAuth _firebaseAuth = FirebaseAuth.DefaultInstance; + private readonly IWalletService _walletService; - public AuthenticateController(FirebaseApp firebaseApp, IIdentityService identityService) + public AuthenticateController(FirebaseApp firebaseApp, IIdentityService identityService, IWalletService walletService) { _firebaseApp = firebaseApp; _identityService = identityService; + _walletService = walletService; } [HttpPost] @@ -71,6 +74,11 @@ public async Task Login([FromBody] Token token) { await _identityService.SetUserFullNameAsync(identity, user.DisplayName); } + var walletId = await _walletService.CreateAsync(new WalletModel + { + Balance = 0, + }); + await _identityService.SetWalletAsync(identity, walletId); } } if (identity != null) @@ -114,6 +122,7 @@ public async Task AddToRole([FromBody] RegisterRole reg) private async Task CreateAccessTokenAsync(ApplicationUser user) { var userClaims = await _identityService.GetClaimsAsync(user); + var wallet = await _walletService.GetByIdAsync(user.WalletID); var roles = await _identityService.GetRolesAsync(user); var roleClaims = new List(); if(roles != null) @@ -126,7 +135,8 @@ private async Task CreateAccessTokenAsync(ApplicationUser user) var claims = new[] { new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), - new Claim("id", user.Id) + new Claim("id", user.Id), + new Claim("wallet", wallet.Balance.ToString()), }.Union(userClaims).Union(roleClaims); var key = SystemSettingModel.Configs["Jwt:SecrectKey"]; var symmetricSecurityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key)); From 52c4353f0ab42b9aabf78bc3322a7382031bc52c Mon Sep 17 00:00:00 2001 From: Nero <67089844+k-nero@users.noreply.github.com> Date: Sat, 21 Oct 2023 20:43:56 +0700 Subject: [PATCH 03/10] Update Authen --- .../Models/LoginModel.cs | 4 ++++ .../Controllers/AuthenticateController.cs | 18 +++++++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) create mode 100644 src/SWD-Laundry-Backend.Core/Models/LoginModel.cs diff --git a/src/SWD-Laundry-Backend.Core/Models/LoginModel.cs b/src/SWD-Laundry-Backend.Core/Models/LoginModel.cs new file mode 100644 index 0000000..c8f54ba --- /dev/null +++ b/src/SWD-Laundry-Backend.Core/Models/LoginModel.cs @@ -0,0 +1,4 @@ +namespace SWD_Laundry_Backend.Core.Models; +public readonly struct LoginModel +{ +} diff --git a/src/SWD-Laundry-Backend/Controllers/AuthenticateController.cs b/src/SWD-Laundry-Backend/Controllers/AuthenticateController.cs index 0998646..62bddcb 100644 --- a/src/SWD-Laundry-Backend/Controllers/AuthenticateController.cs +++ b/src/SWD-Laundry-Backend/Controllers/AuthenticateController.cs @@ -14,9 +14,11 @@ namespace SWD_Laundry_Backend.Controllers; -public readonly struct Token +public readonly struct LoginModel { - public string AccessToken { get; init; } + public string? AccessToken { get; init; } + public string? UserName { get; init; } + public string? Password { get; init; } } public readonly struct RegisterRole @@ -46,7 +48,7 @@ public AuthenticateController(FirebaseApp firebaseApp, IIdentityService identity [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] [ProducesDefaultResponseType] - public async Task Login([FromBody] Token token) + public async Task Login([FromBody] LoginModel token) { try @@ -124,6 +126,7 @@ private async Task CreateAccessTokenAsync(ApplicationUser user) var userClaims = await _identityService.GetClaimsAsync(user); var wallet = await _walletService.GetByIdAsync(user.WalletID); var roles = await _identityService.GetRolesAsync(user); + user.Wallet = wallet; var roleClaims = new List(); if(roles != null) { @@ -135,8 +138,13 @@ private async Task CreateAccessTokenAsync(ApplicationUser user) var claims = new[] { new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), - new Claim("id", user.Id), - new Claim("wallet", wallet.Balance.ToString()), + new Claim("Email", user.Email ?? ""), + new Claim("UserId", user.Id.ToString()), + new Claim("FullName", user.Name ?? ""), + new Claim("WalletBalance", user.Wallet.Balance.ToString()), + new Claim("PhoneNumber", user.PhoneNumber ?? ""), + new Claim("AvatarUrl", user.ImageUrl ?? ""), + new Claim("Username", user.UserName ?? ""), }.Union(userClaims).Union(roleClaims); var key = SystemSettingModel.Configs["Jwt:SecrectKey"]; var symmetricSecurityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key)); From a0e43fbb5509b10f042e3908022944c15a78ffb6 Mon Sep 17 00:00:00 2001 From: Nero <67089844+k-nero@users.noreply.github.com> Date: Sat, 21 Oct 2023 20:48:51 +0700 Subject: [PATCH 04/10] Image URL --- .../Interface/IIdentityService.cs | 1 + src/SWD-Laundry-Backend.Service/Services/IdentityService.cs | 6 ++++++ .../Controllers/AuthenticateController.cs | 4 ++++ 3 files changed, 11 insertions(+) diff --git a/src/SWD-Laundry-Backend.Contract.Service/Interface/IIdentityService.cs b/src/SWD-Laundry-Backend.Contract.Service/Interface/IIdentityService.cs index 16bd87c..5a0f434 100644 --- a/src/SWD-Laundry-Backend.Contract.Service/Interface/IIdentityService.cs +++ b/src/SWD-Laundry-Backend.Contract.Service/Interface/IIdentityService.cs @@ -15,4 +15,5 @@ public interface IIdentityService : IBaseIdentityService public Task> GetClaimsAsync(ApplicationUser user); public Task SetVerfiedEmailAsync(ApplicationUser user, string email); public Task SetWalletAsync(ApplicationUser user, string walletId); + public Task SetUserAvatarUrlAsync(ApplicationUser identity, string photoUrl); } diff --git a/src/SWD-Laundry-Backend.Service/Services/IdentityService.cs b/src/SWD-Laundry-Backend.Service/Services/IdentityService.cs index 1252eea..9fc15c2 100644 --- a/src/SWD-Laundry-Backend.Service/Services/IdentityService.cs +++ b/src/SWD-Laundry-Backend.Service/Services/IdentityService.cs @@ -120,6 +120,12 @@ public async Task SetVerfiedEmailAsync(ApplicationUser user, string email) await _userManager.SetEmailAsync(user, email); } + public async Task SetUserAvatarUrlAsync(ApplicationUser user, string photoUrl) + { + user.ImageUrl = photoUrl; + await _userManager.UpdateAsync(user); + } + public async Task SetWalletAsync(ApplicationUser user, string walletId) { user.WalletID = walletId; diff --git a/src/SWD-Laundry-Backend/Controllers/AuthenticateController.cs b/src/SWD-Laundry-Backend/Controllers/AuthenticateController.cs index 62bddcb..9aa6ac7 100644 --- a/src/SWD-Laundry-Backend/Controllers/AuthenticateController.cs +++ b/src/SWD-Laundry-Backend/Controllers/AuthenticateController.cs @@ -76,6 +76,10 @@ public async Task Login([FromBody] LoginModel token) { await _identityService.SetUserFullNameAsync(identity, user.DisplayName); } + if (!user.PhotoUrl.IsNullOrEmpty()) + { + await _identityService.SetUserAvatarUrlAsync(identity, user.PhotoUrl); + } var walletId = await _walletService.CreateAsync(new WalletModel { Balance = 0, From 7849560a855dfbe4815c006db877b956c8e79e58 Mon Sep 17 00:00:00 2001 From: pytas0811 Date: Sat, 21 Oct 2023 22:45:27 +0700 Subject: [PATCH 05/10] Update Delete method --- .../Entity/BaseEntity.cs | 1 + .../QueryObject/BaseQuery.cs | 2 + ...0231021141521_UpdateDatabase11.Designer.cs | 858 ++++++++++++++++++ .../20231021141521_UpdateDatabase11.cs | 139 +++ .../Migrations/AppDbContextModelSnapshot.cs | 33 + .../Services/BuildingService.cs | 9 +- .../Services/CustomerService.cs | 11 +- .../Services/LaundryStoreService.cs | 12 +- .../Services/OrderHistoryService.cs | 10 +- .../Services/OrderService.cs | 18 +- .../Services/PaymentService.cs | 10 +- .../Services/StaffService.cs | 10 +- .../Services/StaffTripService.cs | 11 +- .../Services/TimeScheduleService.cs | 9 +- .../Services/TransactionService.cs | 9 +- .../Services/WalletService.cs | 9 +- .../Controllers/BuildingController.cs | 2 +- 17 files changed, 1115 insertions(+), 38 deletions(-) create mode 100644 src/SWD-Laundry-Backend.Repository/Migrations/20231021141521_UpdateDatabase11.Designer.cs create mode 100644 src/SWD-Laundry-Backend.Repository/Migrations/20231021141521_UpdateDatabase11.cs diff --git a/src/SWD-Laundry-Backend.Contract.Repository/Entity/BaseEntity.cs b/src/SWD-Laundry-Backend.Contract.Repository/Entity/BaseEntity.cs index 5340694..1dd98e7 100644 --- a/src/SWD-Laundry-Backend.Contract.Repository/Entity/BaseEntity.cs +++ b/src/SWD-Laundry-Backend.Contract.Repository/Entity/BaseEntity.cs @@ -13,6 +13,7 @@ protected BaseEntity() [Key] public string Id { get; set; } + public bool IsDelete { get; set; } = false; public string? CreatedBy { get; set; } public string? LastUpdatedBy { get; set; } //public string? DeletedBy { get; set; } diff --git a/src/SWD-Laundry-Backend.Core/QueryObject/BaseQuery.cs b/src/SWD-Laundry-Backend.Core/QueryObject/BaseQuery.cs index fbbc9bb..983fe15 100644 --- a/src/SWD-Laundry-Backend.Core/QueryObject/BaseQuery.cs +++ b/src/SWD-Laundry-Backend.Core/QueryObject/BaseQuery.cs @@ -13,4 +13,6 @@ public record class BaseQuery public DateTime? EndDate { get; init; } [BindProperty(Name = "sort", SupportsGet = true)] public string? Sort { get; init; } + [BindProperty(Name = "is-deleted", SupportsGet = true)] + public bool IsDeleted { get; init; } = false; } diff --git a/src/SWD-Laundry-Backend.Repository/Migrations/20231021141521_UpdateDatabase11.Designer.cs b/src/SWD-Laundry-Backend.Repository/Migrations/20231021141521_UpdateDatabase11.Designer.cs new file mode 100644 index 0000000..d84c668 --- /dev/null +++ b/src/SWD-Laundry-Backend.Repository/Migrations/20231021141521_UpdateDatabase11.Designer.cs @@ -0,0 +1,858 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using SWD_Laundry_Backend.Repository.Infrastructure; + +#nullable disable + +namespace SWD_Laundry_Backend.Repository.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20231021141521_UpdateDatabase11")] + partial class UpdateDatabase11 + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.11") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderKey") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("Name") + .HasColumnType("nvarchar(450)"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("SWD_Laundry_Backend.Contract.Repository.Entity.Building", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("Address") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedTime") + .HasColumnType("datetimeoffset"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("IsDelete") + .HasColumnType("bit"); + + b.Property("LastUpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdatedTime") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Buildings"); + }); + + modelBuilder.Entity("SWD_Laundry_Backend.Contract.Repository.Entity.Customer", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("ApplicationUserID") + .HasColumnType("nvarchar(450)"); + + b.Property("BuildingID") + .HasColumnType("nvarchar(450)"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedTime") + .HasColumnType("datetimeoffset"); + + b.Property("IsDelete") + .HasColumnType("bit"); + + b.Property("LastUpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdatedTime") + .HasColumnType("datetimeoffset"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationUserID"); + + b.HasIndex("BuildingID"); + + b.ToTable("Customers"); + }); + + modelBuilder.Entity("SWD_Laundry_Backend.Contract.Repository.Entity.IdentityModels.ApplicationUser", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("ImageUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("WalletID") + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.HasIndex("WalletID") + .IsUnique() + .HasFilter("[WalletID] IS NOT NULL"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("SWD_Laundry_Backend.Contract.Repository.Entity.LaundryStore", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("Address") + .HasColumnType("nvarchar(max)"); + + b.Property("ApplicationUserID") + .HasColumnType("nvarchar(450)"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedTime") + .HasColumnType("datetimeoffset"); + + b.Property("EndTime") + .HasColumnType("datetime2"); + + b.Property("IsDelete") + .HasColumnType("bit"); + + b.Property("LastUpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdatedTime") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.Property("StartTime") + .HasColumnType("datetime2"); + + b.Property("Status") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationUserID"); + + b.ToTable("LaundryStores"); + }); + + modelBuilder.Entity("SWD_Laundry_Backend.Contract.Repository.Entity.Order", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("Address") + .HasColumnType("nvarchar(max)"); + + b.Property("Amount") + .HasColumnType("smallint"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedTime") + .HasColumnType("datetimeoffset"); + + b.Property("CustomerID") + .HasColumnType("nvarchar(450)"); + + b.Property("DeliveryTimeFrame") + .HasColumnType("int"); + + b.Property("ExpectedFinishDate") + .HasColumnType("datetime2"); + + b.Property("IsDelete") + .HasColumnType("bit"); + + b.Property("LastUpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdatedTime") + .HasColumnType("datetimeoffset"); + + b.Property("LaundryStoreID") + .HasColumnType("nvarchar(450)"); + + b.Property("OrderDate") + .HasColumnType("datetime2"); + + b.Property("PaymentType") + .HasColumnType("int"); + + b.Property("StaffID") + .HasColumnType("nvarchar(450)"); + + b.Property("TotalPrice") + .HasColumnType("float"); + + b.HasKey("Id"); + + b.HasIndex("CustomerID"); + + b.HasIndex("LaundryStoreID"); + + b.HasIndex("StaffID"); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("SWD_Laundry_Backend.Contract.Repository.Entity.OrderHistory", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedTime") + .HasColumnType("datetimeoffset"); + + b.Property("DeliveryStatus") + .HasColumnType("int"); + + b.Property("IsDelete") + .HasColumnType("bit"); + + b.Property("LastUpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdatedTime") + .HasColumnType("datetimeoffset"); + + b.Property("LaundryStatus") + .HasColumnType("int"); + + b.Property("Message") + .HasColumnType("nvarchar(max)"); + + b.Property("OrderID") + .HasColumnType("nvarchar(450)"); + + b.Property("OrderStatus") + .HasColumnType("int"); + + b.Property("Title") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("OrderID"); + + b.ToTable("OrderHistories"); + }); + + modelBuilder.Entity("SWD_Laundry_Backend.Contract.Repository.Entity.Payment", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedTime") + .HasColumnType("datetimeoffset"); + + b.Property("IsDelete") + .HasColumnType("bit"); + + b.Property("LastUpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdatedTime") + .HasColumnType("datetimeoffset"); + + b.Property("OrderId") + .HasColumnType("nvarchar(450)"); + + b.Property("Price") + .HasColumnType("float"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.ToTable("Payments"); + }); + + modelBuilder.Entity("SWD_Laundry_Backend.Contract.Repository.Entity.Staff_Trip", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("BuildingID") + .HasColumnType("nvarchar(450)"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedTime") + .HasColumnType("datetimeoffset"); + + b.Property("IsDelete") + .HasColumnType("bit"); + + b.Property("LastUpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdatedTime") + .HasColumnType("datetimeoffset"); + + b.Property("StaffID") + .HasColumnType("nvarchar(450)"); + + b.Property("TimeScheduleID") + .HasColumnType("nvarchar(450)"); + + b.Property("TripCollect") + .HasColumnType("int"); + + b.Property("TripType") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("BuildingID"); + + b.HasIndex("StaffID"); + + b.HasIndex("TimeScheduleID"); + + b.ToTable("Staff_Trips"); + }); + + modelBuilder.Entity("SWD_Laundry_Backend.Contract.Repository.Entity.TimeSchedule", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedTime") + .HasColumnType("datetimeoffset"); + + b.Property("DayOfWeek") + .HasColumnType("int"); + + b.Property("EndTime") + .HasColumnType("datetime2"); + + b.Property("IsDelete") + .HasColumnType("bit"); + + b.Property("LastUpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdatedTime") + .HasColumnType("datetimeoffset"); + + b.Property("StartTime") + .HasColumnType("datetime2"); + + b.Property("TimeFrame") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("TimeSchedules"); + }); + + modelBuilder.Entity("SWD_Laundry_Backend.Contract.Repository.Entity.Transaction", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("Amount") + .HasColumnType("float"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedTime") + .HasColumnType("datetimeoffset"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("IsDelete") + .HasColumnType("bit"); + + b.Property("LastUpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdatedTime") + .HasColumnType("datetimeoffset"); + + b.Property("PaymentID") + .HasColumnType("nvarchar(450)"); + + b.Property("PaymentType") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("TransactionType") + .HasColumnType("int"); + + b.Property("WalletID") + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("PaymentID"); + + b.HasIndex("WalletID"); + + b.ToTable("Transaction"); + }); + + modelBuilder.Entity("SWD_Laundry_Backend.Contract.Repository.Entity.Wallet", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("Balance") + .HasColumnType("float"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedTime") + .HasColumnType("datetimeoffset"); + + b.Property("IsDelete") + .HasColumnType("bit"); + + b.Property("LastUpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdatedTime") + .HasColumnType("datetimeoffset"); + + b.HasKey("Id"); + + b.ToTable("Wallets"); + }); + + modelBuilder.Entity("Staff", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("ApplicationUserID") + .HasColumnType("nvarchar(450)"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedTime") + .HasColumnType("datetimeoffset"); + + b.Property("IsDelete") + .HasColumnType("bit"); + + b.Property("LastUpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdatedTime") + .HasColumnType("datetimeoffset"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationUserID"); + + b.ToTable("Staffs"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("SWD_Laundry_Backend.Contract.Repository.Entity.IdentityModels.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("SWD_Laundry_Backend.Contract.Repository.Entity.IdentityModels.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SWD_Laundry_Backend.Contract.Repository.Entity.IdentityModels.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("SWD_Laundry_Backend.Contract.Repository.Entity.IdentityModels.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("SWD_Laundry_Backend.Contract.Repository.Entity.Customer", b => + { + b.HasOne("SWD_Laundry_Backend.Contract.Repository.Entity.IdentityModels.ApplicationUser", "ApplicationUser") + .WithMany() + .HasForeignKey("ApplicationUserID"); + + b.HasOne("SWD_Laundry_Backend.Contract.Repository.Entity.Building", "Building") + .WithMany() + .HasForeignKey("BuildingID"); + + b.Navigation("ApplicationUser"); + + b.Navigation("Building"); + }); + + modelBuilder.Entity("SWD_Laundry_Backend.Contract.Repository.Entity.IdentityModels.ApplicationUser", b => + { + b.HasOne("SWD_Laundry_Backend.Contract.Repository.Entity.Wallet", "Wallet") + .WithOne("ApplicationUser") + .HasForeignKey("SWD_Laundry_Backend.Contract.Repository.Entity.IdentityModels.ApplicationUser", "WalletID"); + + b.Navigation("Wallet"); + }); + + modelBuilder.Entity("SWD_Laundry_Backend.Contract.Repository.Entity.LaundryStore", b => + { + b.HasOne("SWD_Laundry_Backend.Contract.Repository.Entity.IdentityModels.ApplicationUser", "ApplicationUser") + .WithMany() + .HasForeignKey("ApplicationUserID"); + + b.Navigation("ApplicationUser"); + }); + + modelBuilder.Entity("SWD_Laundry_Backend.Contract.Repository.Entity.Order", b => + { + b.HasOne("SWD_Laundry_Backend.Contract.Repository.Entity.Customer", "Customer") + .WithMany() + .HasForeignKey("CustomerID"); + + b.HasOne("SWD_Laundry_Backend.Contract.Repository.Entity.LaundryStore", "LaundryStore") + .WithMany() + .HasForeignKey("LaundryStoreID"); + + b.HasOne("Staff", "Staff") + .WithMany() + .HasForeignKey("StaffID"); + + b.Navigation("Customer"); + + b.Navigation("LaundryStore"); + + b.Navigation("Staff"); + }); + + modelBuilder.Entity("SWD_Laundry_Backend.Contract.Repository.Entity.OrderHistory", b => + { + b.HasOne("SWD_Laundry_Backend.Contract.Repository.Entity.Order", "Order") + .WithMany() + .HasForeignKey("OrderID"); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("SWD_Laundry_Backend.Contract.Repository.Entity.Payment", b => + { + b.HasOne("SWD_Laundry_Backend.Contract.Repository.Entity.Order", "Orders") + .WithMany() + .HasForeignKey("OrderId"); + + b.Navigation("Orders"); + }); + + modelBuilder.Entity("SWD_Laundry_Backend.Contract.Repository.Entity.Staff_Trip", b => + { + b.HasOne("SWD_Laundry_Backend.Contract.Repository.Entity.Building", "Building") + .WithMany() + .HasForeignKey("BuildingID"); + + b.HasOne("Staff", "Staff") + .WithMany() + .HasForeignKey("StaffID"); + + b.HasOne("SWD_Laundry_Backend.Contract.Repository.Entity.TimeSchedule", "TimeSchedule") + .WithMany() + .HasForeignKey("TimeScheduleID"); + + b.Navigation("Building"); + + b.Navigation("Staff"); + + b.Navigation("TimeSchedule"); + }); + + modelBuilder.Entity("SWD_Laundry_Backend.Contract.Repository.Entity.Transaction", b => + { + b.HasOne("SWD_Laundry_Backend.Contract.Repository.Entity.Payment", "Payment") + .WithMany() + .HasForeignKey("PaymentID"); + + b.HasOne("SWD_Laundry_Backend.Contract.Repository.Entity.Wallet", "Wallet") + .WithMany() + .HasForeignKey("WalletID"); + + b.Navigation("Payment"); + + b.Navigation("Wallet"); + }); + + modelBuilder.Entity("Staff", b => + { + b.HasOne("SWD_Laundry_Backend.Contract.Repository.Entity.IdentityModels.ApplicationUser", "ApplicationUser") + .WithMany() + .HasForeignKey("ApplicationUserID"); + + b.Navigation("ApplicationUser"); + }); + + modelBuilder.Entity("SWD_Laundry_Backend.Contract.Repository.Entity.Wallet", b => + { + b.Navigation("ApplicationUser"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/SWD-Laundry-Backend.Repository/Migrations/20231021141521_UpdateDatabase11.cs b/src/SWD-Laundry-Backend.Repository/Migrations/20231021141521_UpdateDatabase11.cs new file mode 100644 index 0000000..fbf5cc1 --- /dev/null +++ b/src/SWD-Laundry-Backend.Repository/Migrations/20231021141521_UpdateDatabase11.cs @@ -0,0 +1,139 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace SWD_Laundry_Backend.Repository.Migrations +{ + /// + public partial class UpdateDatabase11 : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "IsDelete", + table: "Wallets", + type: "bit", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "IsDelete", + table: "Transaction", + type: "bit", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "IsDelete", + table: "TimeSchedules", + type: "bit", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "IsDelete", + table: "Staffs", + type: "bit", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "IsDelete", + table: "Staff_Trips", + type: "bit", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "IsDelete", + table: "Payments", + type: "bit", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "IsDelete", + table: "Orders", + type: "bit", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "IsDelete", + table: "OrderHistories", + type: "bit", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "IsDelete", + table: "LaundryStores", + type: "bit", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "IsDelete", + table: "Customers", + type: "bit", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "IsDelete", + table: "Buildings", + type: "bit", + nullable: false, + defaultValue: false); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "IsDelete", + table: "Wallets"); + + migrationBuilder.DropColumn( + name: "IsDelete", + table: "Transaction"); + + migrationBuilder.DropColumn( + name: "IsDelete", + table: "TimeSchedules"); + + migrationBuilder.DropColumn( + name: "IsDelete", + table: "Staffs"); + + migrationBuilder.DropColumn( + name: "IsDelete", + table: "Staff_Trips"); + + migrationBuilder.DropColumn( + name: "IsDelete", + table: "Payments"); + + migrationBuilder.DropColumn( + name: "IsDelete", + table: "Orders"); + + migrationBuilder.DropColumn( + name: "IsDelete", + table: "OrderHistories"); + + migrationBuilder.DropColumn( + name: "IsDelete", + table: "LaundryStores"); + + migrationBuilder.DropColumn( + name: "IsDelete", + table: "Customers"); + + migrationBuilder.DropColumn( + name: "IsDelete", + table: "Buildings"); + } + } +} diff --git a/src/SWD-Laundry-Backend.Repository/Migrations/AppDbContextModelSnapshot.cs b/src/SWD-Laundry-Backend.Repository/Migrations/AppDbContextModelSnapshot.cs index 9987dc0..d436dca 100644 --- a/src/SWD-Laundry-Backend.Repository/Migrations/AppDbContextModelSnapshot.cs +++ b/src/SWD-Laundry-Backend.Repository/Migrations/AppDbContextModelSnapshot.cs @@ -172,6 +172,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Description") .HasColumnType("nvarchar(max)"); + b.Property("IsDelete") + .HasColumnType("bit"); + b.Property("LastUpdatedBy") .HasColumnType("nvarchar(max)"); @@ -203,6 +206,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("CreatedTime") .HasColumnType("datetimeoffset"); + b.Property("IsDelete") + .HasColumnType("bit"); + b.Property("LastUpdatedBy") .HasColumnType("nvarchar(max)"); @@ -316,6 +322,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("EndTime") .HasColumnType("datetime2"); + b.Property("IsDelete") + .HasColumnType("bit"); + b.Property("LastUpdatedBy") .HasColumnType("nvarchar(max)"); @@ -364,6 +373,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("ExpectedFinishDate") .HasColumnType("datetime2"); + b.Property("IsDelete") + .HasColumnType("bit"); + b.Property("LastUpdatedBy") .HasColumnType("nvarchar(max)"); @@ -410,6 +422,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("DeliveryStatus") .HasColumnType("int"); + b.Property("IsDelete") + .HasColumnType("bit"); + b.Property("LastUpdatedBy") .HasColumnType("nvarchar(max)"); @@ -449,6 +464,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("CreatedTime") .HasColumnType("datetimeoffset"); + b.Property("IsDelete") + .HasColumnType("bit"); + b.Property("LastUpdatedBy") .HasColumnType("nvarchar(max)"); @@ -482,6 +500,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("CreatedTime") .HasColumnType("datetimeoffset"); + b.Property("IsDelete") + .HasColumnType("bit"); + b.Property("LastUpdatedBy") .HasColumnType("nvarchar(max)"); @@ -528,6 +549,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("EndTime") .HasColumnType("datetime2"); + b.Property("IsDelete") + .HasColumnType("bit"); + b.Property("LastUpdatedBy") .HasColumnType("nvarchar(max)"); @@ -562,6 +586,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Description") .HasColumnType("nvarchar(max)"); + b.Property("IsDelete") + .HasColumnType("bit"); + b.Property("LastUpdatedBy") .HasColumnType("nvarchar(max)"); @@ -606,6 +633,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("CreatedTime") .HasColumnType("datetimeoffset"); + b.Property("IsDelete") + .HasColumnType("bit"); + b.Property("LastUpdatedBy") .HasColumnType("nvarchar(max)"); @@ -631,6 +661,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("CreatedTime") .HasColumnType("datetimeoffset"); + b.Property("IsDelete") + .HasColumnType("bit"); + b.Property("LastUpdatedBy") .HasColumnType("nvarchar(max)"); diff --git a/src/SWD-Laundry-Backend.Service/Services/BuildingService.cs b/src/SWD-Laundry-Backend.Service/Services/BuildingService.cs index 4c800f0..cbce487 100644 --- a/src/SWD-Laundry-Backend.Service/Services/BuildingService.cs +++ b/src/SWD-Laundry-Backend.Service/Services/BuildingService.cs @@ -34,7 +34,10 @@ public async Task CreateAsync(BuildingModel model, CancellationToken can public async Task DeleteAsync(string id, CancellationToken cancellationToken = default) { - int i = await _buildingRepository.DeleteAsync(x => x.Id == id, cancellationToken: cancellationToken); + int i = await _buildingRepository.UpdateAsync(x => x.Id == id, + x => x + .SetProperty(x => x.IsDelete, true), + cancellationToken: cancellationToken); return i; } @@ -52,7 +55,9 @@ public async Task> GetAllAsync(BuildingQuery? query, Cance public async Task> GetPaginatedAsync(BuildingQuery query, CancellationToken cancellationToken = default) { - var buildings = await _buildingRepository.GetAsync(cancellationToken: cancellationToken); + var buildings = await _buildingRepository + .GetAsync(c => c.IsDelete == query.IsDeleted + ,cancellationToken: cancellationToken); var result = await buildings.PaginatedListAsync(query); return result; } diff --git a/src/SWD-Laundry-Backend.Service/Services/CustomerService.cs b/src/SWD-Laundry-Backend.Service/Services/CustomerService.cs index 400059c..419ec86 100644 --- a/src/SWD-Laundry-Backend.Service/Services/CustomerService.cs +++ b/src/SWD-Laundry-Backend.Service/Services/CustomerService.cs @@ -33,8 +33,11 @@ public async Task CreateAsync(CustomerModel model, CancellationToken can public async Task DeleteAsync(string id, CancellationToken cancellationToken = default) { - var numberOfRows = await _repository.DeleteAsync(x => x.Id == id, cancellationToken: cancellationToken); - return numberOfRows; + int i = await _repository.UpdateAsync(x => x.Id == id, + x => x + .SetProperty(x => x.IsDelete, true), + cancellationToken: cancellationToken); + return i; } public async Task> GetAllAsync(CustomerQuery? query, CancellationToken cancellationToken = default) @@ -60,7 +63,9 @@ public async Task> GetAllAsync(CustomerQuery? query, Cance public async Task> GetPaginatedAsync(CustomerQuery query, CancellationToken cancellationToken = default) { - var list = await _repository.GetAsync(null ,cancellationToken: cancellationToken + var list = await _repository.GetAsync( + c => c.IsDelete == query.IsDeleted + ,cancellationToken: cancellationToken , x => x.ApplicationUser , c => c.ApplicationUser.Wallet , c => c.Building); diff --git a/src/SWD-Laundry-Backend.Service/Services/LaundryStoreService.cs b/src/SWD-Laundry-Backend.Service/Services/LaundryStoreService.cs index 09134ce..2abc2e6 100644 --- a/src/SWD-Laundry-Backend.Service/Services/LaundryStoreService.cs +++ b/src/SWD-Laundry-Backend.Service/Services/LaundryStoreService.cs @@ -33,8 +33,11 @@ public async Task CreateAsync(LaundryStoreModel model, CancellationToken public async Task DeleteAsync(string id, CancellationToken cancellationToken = default) { - var numberOfRows = await _repository.DeleteAsync(x => x.Id == id, cancellationToken: cancellationToken); - return numberOfRows; + int i = await _repository.UpdateAsync(x => x.Id == id, + x => x + .SetProperty(x => x.IsDelete, true), + cancellationToken: cancellationToken); + return i; } public async Task> GetAllAsync(LaundryStoreQuery? query, CancellationToken cancellationToken = default) @@ -52,8 +55,9 @@ public async Task> GetAllAsync(LaundryStoreQuery? quer public async Task> GetPaginatedAsync(LaundryStoreQuery query, CancellationToken cancellationToken = default) { - var list = await _repository.GetAsync(null - ,cancellationToken: cancellationToken + var list = await _repository.GetAsync( + c => c.IsDelete == query.IsDeleted + , cancellationToken: cancellationToken , c => c.ApplicationUser , c => c.ApplicationUser.Wallet); var result = await list.PaginatedListAsync(query); diff --git a/src/SWD-Laundry-Backend.Service/Services/OrderHistoryService.cs b/src/SWD-Laundry-Backend.Service/Services/OrderHistoryService.cs index 679bbb1..9442916 100644 --- a/src/SWD-Laundry-Backend.Service/Services/OrderHistoryService.cs +++ b/src/SWD-Laundry-Backend.Service/Services/OrderHistoryService.cs @@ -75,8 +75,11 @@ public async Task CreateAsync(OrderHistoryModel model, CancellationToken public async Task DeleteAsync(string id, CancellationToken cancellationToken = default) { - var numberOfRows = await _repository.DeleteAsync(x => x.Id == id, cancellationToken: cancellationToken); - return numberOfRows; + int i = await _repository.UpdateAsync(x => x.Id == id, + x => x + .SetProperty(x => x.IsDelete, true), + cancellationToken: cancellationToken); + return i; } public async Task> GetAllAsync(OrderHistoryQuery query, CancellationToken cancellationToken = default) @@ -103,7 +106,8 @@ public async Task> GetAllAsync(OrderHistoryQuery query public async Task> GetPaginatedAsync(OrderHistoryQuery query, CancellationToken cancellationToken = default) { - var list = await _repository.GetAsync(null, + var list = await _repository.GetAsync( + c => c.IsDelete == query.IsDeleted, cancellationToken: cancellationToken, c => c.Order, c => c.Order.LaundryStore); if (query.OrderId != null) diff --git a/src/SWD-Laundry-Backend.Service/Services/OrderService.cs b/src/SWD-Laundry-Backend.Service/Services/OrderService.cs index 1b71906..915da6a 100644 --- a/src/SWD-Laundry-Backend.Service/Services/OrderService.cs +++ b/src/SWD-Laundry-Backend.Service/Services/OrderService.cs @@ -1,5 +1,4 @@ -using System.Linq.Expressions; -using AutoMapper; +using AutoMapper; using Invedia.DI.Attributes; using Microsoft.EntityFrameworkCore; @@ -35,8 +34,11 @@ public async Task CreateAsync(OrderModel model, CancellationToken cancel public async Task DeleteAsync(string id, CancellationToken cancellationToken = default) { - var numberOfRows = await _repository.DeleteAsync(x => x.Id == id, cancellationToken: cancellationToken); - return numberOfRows; + int i = await _repository.UpdateAsync(x => x.Id == id, + x => x + .SetProperty(x => x.IsDelete, true), + cancellationToken: cancellationToken); + return i; } public async Task> GetAllAsync(OrderQuery? query, CancellationToken cancellationToken = default) @@ -73,13 +75,13 @@ public async Task UpdateAsync(string id, OrderModel model, CancellationToke return numberOfRows; } - public async Task> GetPaginatedAsync(OrderQuery query, CancellationToken cancellationToken = default) { var list = await _repository - .GetAsync(null - ,cancellationToken: cancellationToken - ,c => c.Customer + .GetAsync( + c => c.IsDelete == query.IsDeleted + , cancellationToken: cancellationToken + , c => c.Customer , c => c.Staff , c => c.LaundryStore); diff --git a/src/SWD-Laundry-Backend.Service/Services/PaymentService.cs b/src/SWD-Laundry-Backend.Service/Services/PaymentService.cs index d77dffb..5c4c1cd 100644 --- a/src/SWD-Laundry-Backend.Service/Services/PaymentService.cs +++ b/src/SWD-Laundry-Backend.Service/Services/PaymentService.cs @@ -32,8 +32,11 @@ public async Task CreateAsync(PaymentModel model, CancellationToken canc public async Task DeleteAsync(string id, CancellationToken cancellationToken = default) { - var numberOfRows = await _repository.DeleteAsync(x => x.Id == id, cancellationToken: cancellationToken); - return numberOfRows; + int i = await _repository.UpdateAsync(x => x.Id == id, + x => x + .SetProperty(x => x.IsDelete, true), + cancellationToken: cancellationToken); + return i; } public async Task> GetAllAsync(PaymentQuery? query, CancellationToken cancellationToken = default) @@ -51,7 +54,8 @@ public async Task> GetAllAsync(PaymentQuery? query, Cancell public async Task> GetPaginatedAsync(PaymentQuery query, CancellationToken cancellationToken = default) { var list = await _repository - .GetAsync(null, cancellationToken: cancellationToken, c => c.Orders); + .GetAsync(c => c.IsDelete == query.IsDeleted + , cancellationToken: cancellationToken, c => c.Orders); var result = await list.PaginatedListAsync(query); diff --git a/src/SWD-Laundry-Backend.Service/Services/StaffService.cs b/src/SWD-Laundry-Backend.Service/Services/StaffService.cs index 157307c..50bb313 100644 --- a/src/SWD-Laundry-Backend.Service/Services/StaffService.cs +++ b/src/SWD-Laundry-Backend.Service/Services/StaffService.cs @@ -31,8 +31,11 @@ public async Task CreateAsync(StaffModel model, CancellationToken cancel public async Task DeleteAsync(string id, CancellationToken cancellationToken = default) { - var numberOfRows = await _repository.DeleteAsync(x => x.Id == id, cancellationToken: cancellationToken); - return numberOfRows; + int i = await _repository.UpdateAsync(x => x.Id == id, + x => x + .SetProperty(x => x.IsDelete, true), + cancellationToken: cancellationToken); + return i; } public async Task> GetAllAsync(StaffQuery? query, CancellationToken cancellationToken = default) @@ -56,7 +59,8 @@ public async Task> GetAllAsync(StaffQuery? query, Cancellatio public async Task> GetPaginatedAsync(StaffQuery query, CancellationToken cancellationToken = default) { - var list = await _repository.GetAsync(null, cancellationToken: cancellationToken + var list = await _repository.GetAsync(c => c.IsDelete == query.IsDeleted + , cancellationToken: cancellationToken , c => c.ApplicationUser , c => c.ApplicationUser.Wallet); var result = await list.PaginatedListAsync(query); diff --git a/src/SWD-Laundry-Backend.Service/Services/StaffTripService.cs b/src/SWD-Laundry-Backend.Service/Services/StaffTripService.cs index ec1f97a..1e1e16b 100644 --- a/src/SWD-Laundry-Backend.Service/Services/StaffTripService.cs +++ b/src/SWD-Laundry-Backend.Service/Services/StaffTripService.cs @@ -40,8 +40,11 @@ public async Task CreateAsync(StaffTripModel model, CancellationToken ca public async Task DeleteAsync(string id, CancellationToken cancellationToken = default) { - var numberOfRows = await _repository.DeleteAsync(x => x.Id == id, cancellationToken: cancellationToken); - return numberOfRows; + int i = await _repository.UpdateAsync(x => x.Id == id, + x => x + .SetProperty(x => x.IsDelete, true), + cancellationToken: cancellationToken); + return i; } public async Task> GetAllAsync(StaffTripQuery? query, CancellationToken cancellationToken = default) @@ -61,7 +64,9 @@ public async Task> GetAllAsync(StaffTripQuery? query, Ca public async Task> GetPaginatedAsync(StaffTripQuery query, CancellationToken cancellationToken = default) { - var list = await _repository.GetAsync(cancellationToken: cancellationToken); + var list = await _repository.GetAsync( + c => c.IsDelete == query.IsDeleted + , cancellationToken: cancellationToken); var result = await list.PaginatedListAsync(query); return result; diff --git a/src/SWD-Laundry-Backend.Service/Services/TimeScheduleService.cs b/src/SWD-Laundry-Backend.Service/Services/TimeScheduleService.cs index f27cce6..20e7877 100644 --- a/src/SWD-Laundry-Backend.Service/Services/TimeScheduleService.cs +++ b/src/SWD-Laundry-Backend.Service/Services/TimeScheduleService.cs @@ -33,8 +33,11 @@ public async Task CreateAsync(TimeScheduleModel model, CancellationToken public async Task DeleteAsync(string id, CancellationToken cancellationToken = default) { - var numberOfRows = await _repository.DeleteAsync(x => x.Id == id, cancellationToken); - return numberOfRows; + int i = await _repository.UpdateAsync(x => x.Id == id, + x => x + .SetProperty(x => x.IsDelete, true), + cancellationToken: cancellationToken); + return i; } public async Task> GetAllAsync(TimeScheduleQuery? query, CancellationToken cancellationToken = default) @@ -54,7 +57,7 @@ public async Task> GetPaginatedAsync(TimeScheduleQue { var list = await _repository - .GetAsync(null + .GetAsync(c => c.IsDelete == query.IsDeleted , cancellationToken: cancellationToken); var result = await list.PaginatedListAsync(query); diff --git a/src/SWD-Laundry-Backend.Service/Services/TransactionService.cs b/src/SWD-Laundry-Backend.Service/Services/TransactionService.cs index 31452b1..187d8f5 100644 --- a/src/SWD-Laundry-Backend.Service/Services/TransactionService.cs +++ b/src/SWD-Laundry-Backend.Service/Services/TransactionService.cs @@ -33,8 +33,11 @@ public async Task CreateAsync(TransactionModel model, CancellationToken public async Task DeleteAsync(string id, CancellationToken cancellationToken = default) { - var numberOfRows = await _repository.DeleteAsync(x => x.Id == id, cancellationToken: cancellationToken); - return numberOfRows; + int i = await _repository.UpdateAsync(x => x.Id == id, + x => x + .SetProperty(x => x.IsDelete, true), + cancellationToken: cancellationToken); + return i; } public async Task> GetAllAsync(TransactionQuery? query, CancellationToken cancellationToken = default) @@ -53,7 +56,7 @@ public async Task> GetAllAsync(TransactionQuery? query, public async Task> GetPaginatedAsync(TransactionQuery query, CancellationToken cancellationToken = default) { var list = await _repository - .GetAsync(null + .GetAsync(c => c.IsDelete == query.IsDeleted , cancellationToken: cancellationToken); diff --git a/src/SWD-Laundry-Backend.Service/Services/WalletService.cs b/src/SWD-Laundry-Backend.Service/Services/WalletService.cs index a839ded..4e65408 100644 --- a/src/SWD-Laundry-Backend.Service/Services/WalletService.cs +++ b/src/SWD-Laundry-Backend.Service/Services/WalletService.cs @@ -33,7 +33,10 @@ public async Task CreateAsync(WalletModel model, CancellationToken cance public async Task DeleteAsync(string id, CancellationToken cancellationToken = default) { - int i = await _repository.DeleteAsync(x => x.Id == id, cancellationToken: cancellationToken); + int i = await _repository.UpdateAsync(x => x.Id == id, + x => x + .SetProperty(x => x.IsDelete, true), + cancellationToken: cancellationToken); return i; } @@ -51,7 +54,9 @@ public async Task> GetAllAsync(WalletQuery? query, Cancellat public async Task> GetPaginatedAsync(WalletQuery query, CancellationToken cancellationToken = default) { - var list = await _repository.GetAsync(cancellationToken: cancellationToken); + var list = await _repository.GetAsync( + c => c.IsDelete == query.IsDeleted + , cancellationToken: cancellationToken); var result = await list.PaginatedListAsync(query) ; return result; diff --git a/src/SWD-Laundry-Backend/Controllers/BuildingController.cs b/src/SWD-Laundry-Backend/Controllers/BuildingController.cs index ce90dab..06c69bd 100644 --- a/src/SWD-Laundry-Backend/Controllers/BuildingController.cs +++ b/src/SWD-Laundry-Backend/Controllers/BuildingController.cs @@ -8,7 +8,7 @@ namespace SWD_Laundry_Backend.Controllers; -[Authorize(Roles = "Admin, Staff")] +//[Authorize(Roles = "Admin, Staff")] [ApiController] public class BuildingController : ApiControllerBase { From b118cb4a4f2aace7d8dd14092e79c5d651882ae4 Mon Sep 17 00:00:00 2001 From: pytas0811 Date: Sat, 21 Oct 2023 23:16:18 +0700 Subject: [PATCH 06/10] Update delete repository --- Script.sql | Bin 257082 -> 201000 bytes .../Base/BaseRepository.cs | 5 ++++- .../Services/BuildingService.cs | 6 ++---- .../Services/CustomerService.cs | 6 ++---- .../Services/LaundryStoreService.cs | 6 ++---- .../Services/OrderHistoryService.cs | 6 ++---- .../Services/OrderService.cs | 6 ++---- .../Services/PaymentService.cs | 6 ++---- .../Services/StaffService.cs | 6 ++---- .../Services/StaffTripService.cs | 6 ++---- .../Services/TimeScheduleService.cs | 6 ++---- .../Services/TransactionService.cs | 6 ++---- .../Services/WalletService.cs | 6 ++---- .../Controllers/BuildingController.cs | 2 +- src/SWD-Laundry-Backend/Program.cs | 10 +++++----- 15 files changed, 32 insertions(+), 51 deletions(-) diff --git a/Script.sql b/Script.sql index 478e5d7acf80a974386ba6eb84fd3a87e88134f0..e3d55893eb197cfacd2ca497c282cb2d2bd34c31 100644 GIT binary patch literal 201000 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 U4o&hIgXRddzyI%Hz1wjAA8U5MLI3~& literal 257082 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

gPs}Nt)iXR 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 AddAsync(T entity, CancellationToken cancellationTo public virtual async Task DeleteAsync(Expression> filter, CancellationToken cancellationToken = default) { - var i = await DbSet.Where(filter).ExecuteDeleteAsync(cancellationToken); + //var i = await DbSet.Where(filter).ExecuteDeleteAsync(cancellationToken); + var i = await DbSet.Where(filter) + .ExecuteUpdateAsync(x => x.SetProperty(x => x.IsDelete, true) + , cancellationToken); return i; } diff --git a/src/SWD-Laundry-Backend.Service/Services/BuildingService.cs b/src/SWD-Laundry-Backend.Service/Services/BuildingService.cs index cbce487..d33edf9 100644 --- a/src/SWD-Laundry-Backend.Service/Services/BuildingService.cs +++ b/src/SWD-Laundry-Backend.Service/Services/BuildingService.cs @@ -34,10 +34,8 @@ public async Task CreateAsync(BuildingModel model, CancellationToken can public async Task DeleteAsync(string id, CancellationToken cancellationToken = default) { - int i = await _buildingRepository.UpdateAsync(x => x.Id == id, - x => x - .SetProperty(x => x.IsDelete, true), - cancellationToken: cancellationToken); + int i = await _buildingRepository.DeleteAsync(x => x.Id == id, + cancellationToken); return i; } diff --git a/src/SWD-Laundry-Backend.Service/Services/CustomerService.cs b/src/SWD-Laundry-Backend.Service/Services/CustomerService.cs index 419ec86..e497603 100644 --- a/src/SWD-Laundry-Backend.Service/Services/CustomerService.cs +++ b/src/SWD-Laundry-Backend.Service/Services/CustomerService.cs @@ -33,10 +33,8 @@ public async Task CreateAsync(CustomerModel model, CancellationToken can public async Task DeleteAsync(string id, CancellationToken cancellationToken = default) { - int i = await _repository.UpdateAsync(x => x.Id == id, - x => x - .SetProperty(x => x.IsDelete, true), - cancellationToken: cancellationToken); + int i = await _repository.DeleteAsync(x => x.Id == id, + cancellationToken); return i; } diff --git a/src/SWD-Laundry-Backend.Service/Services/LaundryStoreService.cs b/src/SWD-Laundry-Backend.Service/Services/LaundryStoreService.cs index 2abc2e6..13c0cc6 100644 --- a/src/SWD-Laundry-Backend.Service/Services/LaundryStoreService.cs +++ b/src/SWD-Laundry-Backend.Service/Services/LaundryStoreService.cs @@ -33,10 +33,8 @@ public async Task CreateAsync(LaundryStoreModel model, CancellationToken public async Task DeleteAsync(string id, CancellationToken cancellationToken = default) { - int i = await _repository.UpdateAsync(x => x.Id == id, - x => x - .SetProperty(x => x.IsDelete, true), - cancellationToken: cancellationToken); + int i = await _repository.DeleteAsync(x => x.Id == id, + cancellationToken); return i; } diff --git a/src/SWD-Laundry-Backend.Service/Services/OrderHistoryService.cs b/src/SWD-Laundry-Backend.Service/Services/OrderHistoryService.cs index 9442916..4cabdb9 100644 --- a/src/SWD-Laundry-Backend.Service/Services/OrderHistoryService.cs +++ b/src/SWD-Laundry-Backend.Service/Services/OrderHistoryService.cs @@ -75,10 +75,8 @@ public async Task CreateAsync(OrderHistoryModel model, CancellationToken public async Task DeleteAsync(string id, CancellationToken cancellationToken = default) { - int i = await _repository.UpdateAsync(x => x.Id == id, - x => x - .SetProperty(x => x.IsDelete, true), - cancellationToken: cancellationToken); + int i = await _repository.DeleteAsync(x => x.Id == id, + cancellationToken); return i; } diff --git a/src/SWD-Laundry-Backend.Service/Services/OrderService.cs b/src/SWD-Laundry-Backend.Service/Services/OrderService.cs index 915da6a..328de20 100644 --- a/src/SWD-Laundry-Backend.Service/Services/OrderService.cs +++ b/src/SWD-Laundry-Backend.Service/Services/OrderService.cs @@ -34,10 +34,8 @@ public async Task CreateAsync(OrderModel model, CancellationToken cancel public async Task DeleteAsync(string id, CancellationToken cancellationToken = default) { - int i = await _repository.UpdateAsync(x => x.Id == id, - x => x - .SetProperty(x => x.IsDelete, true), - cancellationToken: cancellationToken); + int i = await _repository.DeleteAsync(x => x.Id == id, + cancellationToken); return i; } diff --git a/src/SWD-Laundry-Backend.Service/Services/PaymentService.cs b/src/SWD-Laundry-Backend.Service/Services/PaymentService.cs index 5c4c1cd..db9975f 100644 --- a/src/SWD-Laundry-Backend.Service/Services/PaymentService.cs +++ b/src/SWD-Laundry-Backend.Service/Services/PaymentService.cs @@ -32,10 +32,8 @@ public async Task CreateAsync(PaymentModel model, CancellationToken canc public async Task DeleteAsync(string id, CancellationToken cancellationToken = default) { - int i = await _repository.UpdateAsync(x => x.Id == id, - x => x - .SetProperty(x => x.IsDelete, true), - cancellationToken: cancellationToken); + int i = await _repository.DeleteAsync(x => x.Id == id, + cancellationToken); return i; } diff --git a/src/SWD-Laundry-Backend.Service/Services/StaffService.cs b/src/SWD-Laundry-Backend.Service/Services/StaffService.cs index 50bb313..ad606c2 100644 --- a/src/SWD-Laundry-Backend.Service/Services/StaffService.cs +++ b/src/SWD-Laundry-Backend.Service/Services/StaffService.cs @@ -31,10 +31,8 @@ public async Task CreateAsync(StaffModel model, CancellationToken cancel public async Task DeleteAsync(string id, CancellationToken cancellationToken = default) { - int i = await _repository.UpdateAsync(x => x.Id == id, - x => x - .SetProperty(x => x.IsDelete, true), - cancellationToken: cancellationToken); + int i = await _repository.DeleteAsync(x => x.Id == id, + cancellationToken); return i; } diff --git a/src/SWD-Laundry-Backend.Service/Services/StaffTripService.cs b/src/SWD-Laundry-Backend.Service/Services/StaffTripService.cs index 1e1e16b..7cb03c8 100644 --- a/src/SWD-Laundry-Backend.Service/Services/StaffTripService.cs +++ b/src/SWD-Laundry-Backend.Service/Services/StaffTripService.cs @@ -40,10 +40,8 @@ public async Task CreateAsync(StaffTripModel model, CancellationToken ca public async Task DeleteAsync(string id, CancellationToken cancellationToken = default) { - int i = await _repository.UpdateAsync(x => x.Id == id, - x => x - .SetProperty(x => x.IsDelete, true), - cancellationToken: cancellationToken); + int i = await _repository.DeleteAsync(x => x.Id == id, + cancellationToken); return i; } diff --git a/src/SWD-Laundry-Backend.Service/Services/TimeScheduleService.cs b/src/SWD-Laundry-Backend.Service/Services/TimeScheduleService.cs index 20e7877..7558dbe 100644 --- a/src/SWD-Laundry-Backend.Service/Services/TimeScheduleService.cs +++ b/src/SWD-Laundry-Backend.Service/Services/TimeScheduleService.cs @@ -33,10 +33,8 @@ public async Task CreateAsync(TimeScheduleModel model, CancellationToken public async Task DeleteAsync(string id, CancellationToken cancellationToken = default) { - int i = await _repository.UpdateAsync(x => x.Id == id, - x => x - .SetProperty(x => x.IsDelete, true), - cancellationToken: cancellationToken); + int i = await _repository.DeleteAsync(x => x.Id == id, + cancellationToken); return i; } diff --git a/src/SWD-Laundry-Backend.Service/Services/TransactionService.cs b/src/SWD-Laundry-Backend.Service/Services/TransactionService.cs index 187d8f5..00550b8 100644 --- a/src/SWD-Laundry-Backend.Service/Services/TransactionService.cs +++ b/src/SWD-Laundry-Backend.Service/Services/TransactionService.cs @@ -33,10 +33,8 @@ public async Task CreateAsync(TransactionModel model, CancellationToken public async Task DeleteAsync(string id, CancellationToken cancellationToken = default) { - int i = await _repository.UpdateAsync(x => x.Id == id, - x => x - .SetProperty(x => x.IsDelete, true), - cancellationToken: cancellationToken); + int i = await _repository.DeleteAsync(x => x.Id == id, + cancellationToken); return i; } diff --git a/src/SWD-Laundry-Backend.Service/Services/WalletService.cs b/src/SWD-Laundry-Backend.Service/Services/WalletService.cs index 4e65408..47462f3 100644 --- a/src/SWD-Laundry-Backend.Service/Services/WalletService.cs +++ b/src/SWD-Laundry-Backend.Service/Services/WalletService.cs @@ -33,10 +33,8 @@ public async Task CreateAsync(WalletModel model, CancellationToken cance public async Task DeleteAsync(string id, CancellationToken cancellationToken = default) { - int i = await _repository.UpdateAsync(x => x.Id == id, - x => x - .SetProperty(x => x.IsDelete, true), - cancellationToken: cancellationToken); + int i = await _repository.DeleteAsync(x => x.Id == id, + cancellationToken); return i; } diff --git a/src/SWD-Laundry-Backend/Controllers/BuildingController.cs b/src/SWD-Laundry-Backend/Controllers/BuildingController.cs index 06c69bd..ce90dab 100644 --- a/src/SWD-Laundry-Backend/Controllers/BuildingController.cs +++ b/src/SWD-Laundry-Backend/Controllers/BuildingController.cs @@ -8,7 +8,7 @@ namespace SWD_Laundry_Backend.Controllers; -//[Authorize(Roles = "Admin, Staff")] +[Authorize(Roles = "Admin, Staff")] [ApiController] public class BuildingController : ApiControllerBase { diff --git a/src/SWD-Laundry-Backend/Program.cs b/src/SWD-Laundry-Backend/Program.cs index 88eda9a..90c957a 100644 --- a/src/SWD-Laundry-Backend/Program.cs +++ b/src/SWD-Laundry-Backend/Program.cs @@ -102,11 +102,11 @@ public static async Task Main(string[] args) }); - builder.Services.AddSingleton(FirebaseApp.Create(new AppOptions() - { - Credential = await GoogleCredential.FromFileAsync(builder.Configuration["Firebase:Credential"], cancellationToken: default), - ServiceAccountId = builder.Configuration["Firebase:ServiceAccountId"], - })); + //builder.Services.AddSingleton(FirebaseApp.Create(new AppOptions() + //{ + // Credential = await GoogleCredential.FromFileAsync(builder.Configuration["Firebase:Credential"], cancellationToken: default), + // ServiceAccountId = builder.Configuration["Firebase:ServiceAccountId"], + //})); builder.Services.AddDbContext(options => From f14e39d112bca884319104b95de48d2a62b1033c Mon Sep 17 00:00:00 2001 From: Nero Date: Sat, 21 Oct 2023 23:18:06 +0700 Subject: [PATCH 07/10] Update Program.cs --- src/SWD-Laundry-Backend/Program.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/SWD-Laundry-Backend/Program.cs b/src/SWD-Laundry-Backend/Program.cs index 90c957a..88eda9a 100644 --- a/src/SWD-Laundry-Backend/Program.cs +++ b/src/SWD-Laundry-Backend/Program.cs @@ -102,11 +102,11 @@ public static async Task Main(string[] args) }); - //builder.Services.AddSingleton(FirebaseApp.Create(new AppOptions() - //{ - // Credential = await GoogleCredential.FromFileAsync(builder.Configuration["Firebase:Credential"], cancellationToken: default), - // ServiceAccountId = builder.Configuration["Firebase:ServiceAccountId"], - //})); + builder.Services.AddSingleton(FirebaseApp.Create(new AppOptions() + { + Credential = await GoogleCredential.FromFileAsync(builder.Configuration["Firebase:Credential"], cancellationToken: default), + ServiceAccountId = builder.Configuration["Firebase:ServiceAccountId"], + })); builder.Services.AddDbContext(options => From 91b3c7c4841e55d79a7d05543dedd96525648ae7 Mon Sep 17 00:00:00 2001 From: Nero <67089844+k-nero@users.noreply.github.com> Date: Sat, 21 Oct 2023 23:19:16 +0700 Subject: [PATCH 08/10] minor update --- src/SWD-Laundry-Backend.Core/Models/LoginModel.cs | 5 ++++- .../Controllers/AuthenticateController.cs | 7 ------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/SWD-Laundry-Backend.Core/Models/LoginModel.cs b/src/SWD-Laundry-Backend.Core/Models/LoginModel.cs index c8f54ba..a06813a 100644 --- a/src/SWD-Laundry-Backend.Core/Models/LoginModel.cs +++ b/src/SWD-Laundry-Backend.Core/Models/LoginModel.cs @@ -1,4 +1,7 @@ namespace SWD_Laundry_Backend.Core.Models; public readonly struct LoginModel { -} + public string? AccessToken { get; init; } + public string? UserName { get; init; } + public string? Password { get; init; } +} \ No newline at end of file diff --git a/src/SWD-Laundry-Backend/Controllers/AuthenticateController.cs b/src/SWD-Laundry-Backend/Controllers/AuthenticateController.cs index 9aa6ac7..beb38e3 100644 --- a/src/SWD-Laundry-Backend/Controllers/AuthenticateController.cs +++ b/src/SWD-Laundry-Backend/Controllers/AuthenticateController.cs @@ -14,13 +14,6 @@ namespace SWD_Laundry_Backend.Controllers; -public readonly struct LoginModel -{ - public string? AccessToken { get; init; } - public string? UserName { get; init; } - public string? Password { get; init; } -} - public readonly struct RegisterRole { public string Email { get; init; } From c1e85142ffacbfbb33da92f051a972fef3132213 Mon Sep 17 00:00:00 2001 From: Nero <67089844+k-nero@users.noreply.github.com> Date: Sun, 22 Oct 2023 16:08:25 +0700 Subject: [PATCH 09/10] Minor Update --- .../Models/PaymentModel.cs | 5 +- .../Services/BuildingService.cs | 3 +- .../Services/PaypalService.cs | 2 + .../Controllers/AuthenticateController.cs | 78 ++++++++++++------- .../Controllers/PaypalController.cs | 1 - 5 files changed, 53 insertions(+), 36 deletions(-) diff --git a/src/SWD-Laundry-Backend.Core/Models/PaymentModel.cs b/src/SWD-Laundry-Backend.Core/Models/PaymentModel.cs index e450316..9b0b11f 100644 --- a/src/SWD-Laundry-Backend.Core/Models/PaymentModel.cs +++ b/src/SWD-Laundry-Backend.Core/Models/PaymentModel.cs @@ -1,7 +1,4 @@ -using StackExchange.Redis; -using System.ComponentModel.DataAnnotations.Schema; - -namespace SWD_Laundry_Backend.Core.Models; +namespace SWD_Laundry_Backend.Core.Models; public class PaymentModel { diff --git a/src/SWD-Laundry-Backend.Service/Services/BuildingService.cs b/src/SWD-Laundry-Backend.Service/Services/BuildingService.cs index d33edf9..3472785 100644 --- a/src/SWD-Laundry-Backend.Service/Services/BuildingService.cs +++ b/src/SWD-Laundry-Backend.Service/Services/BuildingService.cs @@ -34,8 +34,7 @@ public async Task CreateAsync(BuildingModel model, CancellationToken can public async Task DeleteAsync(string id, CancellationToken cancellationToken = default) { - int i = await _buildingRepository.DeleteAsync(x => x.Id == id, - cancellationToken); + int i = await _buildingRepository.DeleteAsync(x => x.Id == id, cancellationToken); return i; } diff --git a/src/SWD-Laundry-Backend.Service/Services/PaypalService.cs b/src/SWD-Laundry-Backend.Service/Services/PaypalService.cs index 8f720a4..d9e30c9 100644 --- a/src/SWD-Laundry-Backend.Service/Services/PaypalService.cs +++ b/src/SWD-Laundry-Backend.Service/Services/PaypalService.cs @@ -86,6 +86,8 @@ public async Task CreatePaypalOrderAsync(TransactionModel m client.DefaultRequestHeaders.Add("Accept-Language", "en_US"); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", access_token.Value.access_token); model.Status = Core.Enum.TransactionStatus.Pending; + model.PaymentType = Core.Enum.PaymentType.Paypal; + model.TransactionType = Core.Enum.AllowedTransactionType.Deposit; var transId = await _transactionService.CreateAsync(model, cancellationToken); var order = new PaypalOrderRequest() diff --git a/src/SWD-Laundry-Backend/Controllers/AuthenticateController.cs b/src/SWD-Laundry-Backend/Controllers/AuthenticateController.cs index beb38e3..1dd23b2 100644 --- a/src/SWD-Laundry-Backend/Controllers/AuthenticateController.cs +++ b/src/SWD-Laundry-Backend/Controllers/AuthenticateController.cs @@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.IdentityModel.Tokens; +using SWD_Laundry_Backend.Contract.Repository.Entity; using SWD_Laundry_Backend.Contract.Repository.Entity.IdentityModels; using SWD_Laundry_Backend.Contract.Service.Interface; using SWD_Laundry_Backend.Core.Config; @@ -46,38 +47,52 @@ public async Task Login([FromBody] LoginModel token) try { - var decodedToken = await _firebaseAuth.VerifyIdTokenAsync(token.AccessToken); - var uid = decodedToken.Uid; - var user = await _firebaseAuth.GetUserAsync(uid); - var identity = await _identityService.GetUserByUserNameAsync(user.Email); + FirebaseToken? decodedToken = null; + string uid = ""; + UserRecord? user = null; + ApplicationUser? identity = null; + if (!token.AccessToken.IsNullOrEmpty()) + { + decodedToken = await _firebaseAuth.VerifyIdTokenAsync(token.AccessToken); + if (decodedToken != null) + { + uid = decodedToken.Uid; + user = await _firebaseAuth.GetUserAsync(uid); + } + } object? customToken = null; - if (identity == null) + + if (user != null) { - var result = await _identityService.CreateUserAsync(user.Email, CoreHelper.CreateRandomPassword(20)); identity = await _identityService.GetUserByUserNameAsync(user.Email); - if(identity != null) + if (identity == null) { - if (!result.Result.Errors.IsNullOrEmpty()) - { - return BadRequest(result); - } - if (!user.PhoneNumber.IsNullOrEmpty()) + var result = await _identityService.CreateUserAsync(user.Email, CoreHelper.CreateRandomPassword(20)); + identity = await _identityService.GetUserByUserNameAsync(user.Email); + if (identity != null) { - await _identityService.SetVerifiedPhoneNumberAsync(identity, user.PhoneNumber); + if (!result.Result.Errors.IsNullOrEmpty()) + { + return BadRequest(result); + } + if (!user.PhoneNumber.IsNullOrEmpty()) + { + await _identityService.SetVerifiedPhoneNumberAsync(identity, user.PhoneNumber); + } + if (!user.DisplayName.IsNullOrEmpty()) + { + await _identityService.SetUserFullNameAsync(identity, user.DisplayName); + } + if (!user.PhotoUrl.IsNullOrEmpty()) + { + await _identityService.SetUserAvatarUrlAsync(identity, user.PhotoUrl); + } + var walletId = await _walletService.CreateAsync(new WalletModel + { + Balance = 0, + }); + await _identityService.SetWalletAsync(identity, walletId); } - if (!user.DisplayName.IsNullOrEmpty()) - { - await _identityService.SetUserFullNameAsync(identity, user.DisplayName); - } - if (!user.PhotoUrl.IsNullOrEmpty()) - { - await _identityService.SetUserAvatarUrlAsync(identity, user.PhotoUrl); - } - var walletId = await _walletService.CreateAsync(new WalletModel - { - Balance = 0, - }); - await _identityService.SetWalletAsync(identity, walletId); } } if (identity != null) @@ -121,11 +136,15 @@ public async Task AddToRole([FromBody] RegisterRole reg) private async Task CreateAccessTokenAsync(ApplicationUser user) { var userClaims = await _identityService.GetClaimsAsync(user); - var wallet = await _walletService.GetByIdAsync(user.WalletID); + Wallet? wallet = null; + if (user.WalletID != null) + { + wallet = await _walletService.GetByIdAsync(user.WalletID); + } var roles = await _identityService.GetRolesAsync(user); user.Wallet = wallet; var roleClaims = new List(); - if(roles != null) + if (roles != null) { for (int i = 0; i < roles.Count; i++) { @@ -153,7 +172,8 @@ private async Task CreateAccessTokenAsync(ApplicationUser user) expires: DateTime.UtcNow.AddMinutes(240), signingCredentials: signingCredentials); var token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken); - return new { + return new + { accesstoken = token, role = roles }; diff --git a/src/SWD-Laundry-Backend/Controllers/PaypalController.cs b/src/SWD-Laundry-Backend/Controllers/PaypalController.cs index 5aa61c8..20aeb7f 100644 --- a/src/SWD-Laundry-Backend/Controllers/PaypalController.cs +++ b/src/SWD-Laundry-Backend/Controllers/PaypalController.cs @@ -2,7 +2,6 @@ using SWD_Laundry_Backend.Contract.Service.Interface; using SWD_Laundry_Backend.Core.Models; using SWD_Laundry_Backend.Core.Models.Common; -using SWD_Laundry_Backend.Core.ValueObject; using static SWD_Laundry_Backend.Core.ValueObject.PaypalApiObjectModel.PaypalOrder; namespace SWD_Laundry_Backend.Controllers; From e932e343f1566826dbd88963c91730aae5d28b18 Mon Sep 17 00:00:00 2001 From: Nero <67089844+k-nero@users.noreply.github.com> Date: Sun, 22 Oct 2023 16:14:07 +0700 Subject: [PATCH 10/10] update dependency --- .../SWD-Laundry-Backend.Contract.Repository.csproj | 8 ++++---- .../SWD-Laundry-Backend.Core.csproj | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/SWD-Laundry-Backend.Contract.Repository/SWD-Laundry-Backend.Contract.Repository.csproj b/src/SWD-Laundry-Backend.Contract.Repository/SWD-Laundry-Backend.Contract.Repository.csproj index 63275a1..28280c1 100644 --- a/src/SWD-Laundry-Backend.Contract.Repository/SWD-Laundry-Backend.Contract.Repository.csproj +++ b/src/SWD-Laundry-Backend.Contract.Repository/SWD-Laundry-Backend.Contract.Repository.csproj @@ -9,10 +9,10 @@ - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/SWD-Laundry-Backend.Core/SWD-Laundry-Backend.Core.csproj b/src/SWD-Laundry-Backend.Core/SWD-Laundry-Backend.Core.csproj index 0f58992..289d367 100644 --- a/src/SWD-Laundry-Backend.Core/SWD-Laundry-Backend.Core.csproj +++ b/src/SWD-Laundry-Backend.Core/SWD-Laundry-Backend.Core.csproj @@ -12,12 +12,12 @@ - + - - - + + +