From ee4df116d13eb54a7088c9641c6c2447941fc9b1 Mon Sep 17 00:00:00 2001 From: Amin <69254513+AminGh05@users.noreply.github.com> Date: Thu, 26 Jun 2025 01:46:39 +0330 Subject: [PATCH 1/4] Update Session08 Backend.md fixed some parts of fixes --- .../Session08/Session08 Backend.md | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/ProjectOrientedSessions/Session08/Session08 Backend.md b/ProjectOrientedSessions/Session08/Session08 Backend.md index bd54829..68339a5 100644 --- a/ProjectOrientedSessions/Session08/Session08 Backend.md +++ b/ProjectOrientedSessions/Session08/Session08 Backend.md @@ -1,12 +1,24 @@ +# Session 8 +Profile + some fixes to database +## Fixes +- [ ] Check for missing `.ValueGeneratedOnAdd()` in all entity configurations in ```Infrastructure/Configurations```. -# Fixes -- [ ] Check for missing `.ValueGeneratedOnAdd()` in all entity configuration. - [ ] Adjust the database setup according to the second version of ERD -- [ ] new erd: https://github.com/TheOrderOfPhoenix/ASP.NET/blob/main/02_ProjectOrientedSessions/docs/AlibabaERD-Version02.pdf -- [ ] Pay attention to the changes in logic and implementation of Person table (Id number is not unique anymore) -- [ ] Add actual data in `TicketStatus`, `Gender`, `TransactionTypes` -- [ ] Add data in `Seat`, `Person`, `TicketOrder`, `Transaction`, `Ticket` for test. It is recommended to write python code for generating data for Seat table, according to the data already stored in Transportation and related Vehicle data + - Some aggregates are added/modified to generate the new database + - New ERD: https://github.com/TheOrderOfPhoenix/ASP.NET/blob/main/ProjectOrientedSessions/docs/AlibabaERD-Version02.pdf + - Note: Pay attention to the changes in logic and implementation of Person table (Id number is not unique anymore). So remove this code in PersonConfiguration: + + ``` + builder.HasIndex(p => p.IdNumber) + .IsUnique(); + ``` + +- [ ] Add actual data in `TicketStatus`, `Gender`, `TransactionTypes` + - You can either add the data in DbContext or the database itself + +- [ ] Add data in `Seat`, `Person`, `TicketOrder`, `Transaction`, `Ticket` for test. It is recommended to write python code for generating data for Seat table, according to the data already stored in Transportation and related Vehicle data. There is also a SeatGenerator in this repository, as well. + - [ ] Fix claim extraction (`sub` → standardize JWT claim mapping). (`IUserContext` implmentation) ### ✅ Profile Page (Account Info Tab) From 1dd5f80808f047fede8ad93eef3b84725ccd5e64 Mon Sep 17 00:00:00 2001 From: Amin <69254513+AminGh05@users.noreply.github.com> Date: Fri, 27 Jun 2025 00:24:44 +0330 Subject: [PATCH 2/4] Update Session08 Backend.md fixed 2 links --- ProjectOrientedSessions/Session08/Session08 Backend.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ProjectOrientedSessions/Session08/Session08 Backend.md b/ProjectOrientedSessions/Session08/Session08 Backend.md index 68339a5..cbb709c 100644 --- a/ProjectOrientedSessions/Session08/Session08 Backend.md +++ b/ProjectOrientedSessions/Session08/Session08 Backend.md @@ -6,7 +6,7 @@ Profile + some fixes to database - [ ] Adjust the database setup according to the second version of ERD - Some aggregates are added/modified to generate the new database - - New ERD: https://github.com/TheOrderOfPhoenix/ASP.NET/blob/main/ProjectOrientedSessions/docs/AlibabaERD-Version02.pdf + - New ERD: [Here](https://github.com/TheOrderOfPhoenix/ASP.NET/blob/main/ProjectOrientedSessions/docs/AlibabaERD-Version02.pdf) - Note: Pay attention to the changes in logic and implementation of Person table (Id number is not unique anymore). So remove this code in PersonConfiguration: ``` @@ -17,7 +17,7 @@ Profile + some fixes to database - [ ] Add actual data in `TicketStatus`, `Gender`, `TransactionTypes` - You can either add the data in DbContext or the database itself -- [ ] Add data in `Seat`, `Person`, `TicketOrder`, `Transaction`, `Ticket` for test. It is recommended to write python code for generating data for Seat table, according to the data already stored in Transportation and related Vehicle data. There is also a SeatGenerator in this repository, as well. +- [ ] Add data in `Seat`, `Person`, `TicketOrder`, `Transaction`, `Ticket` for test. It is recommended to write python code for generating data for Seat table, according to the data already stored in Transportation and related Vehicle data. There is also a [SeatGenerator](https://github.com/TheOrderOfPhoenix/ASP.NET/blob/main/ProjectOrientedSessions/Session08/SeatGenerator.py) in this repository, as well. - [ ] Fix claim extraction (`sub` → standardize JWT claim mapping). (`IUserContext` implmentation) From c28a0de0bd8ee781a5fb4f3681b223450df6f4c3 Mon Sep 17 00:00:00 2001 From: Amin <69254513+AminGh05@users.noreply.github.com> Date: Fri, 27 Jun 2025 01:19:38 +0330 Subject: [PATCH 3/4] Update Session08 Backend.md finished fixes + some minor changes to structure --- .../Session08/Session08 Backend.md | 51 +++++++++++++++---- 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/ProjectOrientedSessions/Session08/Session08 Backend.md b/ProjectOrientedSessions/Session08/Session08 Backend.md index cbb709c..5b2720a 100644 --- a/ProjectOrientedSessions/Session08/Session08 Backend.md +++ b/ProjectOrientedSessions/Session08/Session08 Backend.md @@ -21,7 +21,43 @@ Profile + some fixes to database - [ ] Fix claim extraction (`sub` → standardize JWT claim mapping). (`IUserContext` implmentation) -### ✅ Profile Page (Account Info Tab) +First, create an interface in Application layer: +``` +public interface IUserContext +{ +long GetUserId(); +} +``` +Then, implement it in WebAPI in Auth folder: +``` +public class UserContext : IUserContext +{ + private readonly IHttpContextAccessor _httpContextAccessor; + + public UserContext(IHttpContextAccessor httpContextAccessor) + { + _httpContextAccessor = httpContextAccessor; + } + + public long GetUserId() + { + var userIdStr = _httpContextAccessor.HttpContext?.User?.FindFirst(ClaimTypes.NameIdentifier)?.Value; + if (long.TryParse(userIdStr, out var userId)) + { + return userId; + } + throw new InvalidOperationException("User ID is not available or invalid."); + } +} +``` +Finally, register things in Program.cs +``` +// register user context +builder.Services.AddHttpContextAccessor(); +builder.Services.AddScoped(); +``` + +## ✅ Profile Page (Account Info Tab) - [ ] Create `ProfileDto` to represent combined data for account, person, bank detail, balance. - [ ] Add `GetProfileAsync` in `AccountRepository` and expose via `AccountController`. @@ -33,30 +69,23 @@ Profile + some fixes to database - [ ] Add mapping for all Dtos and fix related properties like `CreatorAccountId`. ---- - -### ✅ List of Travelers +## ✅ List of Travelers - [ ] Add `GetPeople` endpoint in `AccountController`. - [ ] Implement separation of `UpsertAccountPerson` and `UpsertPerson`. - [ ] Adjust Dto: `PersonDto` (with `id`, `creatorAccountId`, `englishFirstName`, etc.). ---- - -### ✅ My Travels Tab +## ✅ My Travels Tab - [ ] Create `TicketOrderSummaryDto` (includes cities, vehicle name, price, etc.). - [ ] Add `GetTravels` in `AccountService`, and expose `GetMyTravels` in controller. ---- -### ✅ My Transactions Tab +## ✅ My Transactions Tab - [ ] Create `TransactionDto` and mapping. - [ ] Add method to get transactions by `AccountId`. - [ ] Expose `GetMyTransactions` in `AccountController`. - [ ] Add modal to simulate balance top-up (manual input). - [ ] Format amount text based on transaction type: green (+) for income, red (–) for expense. - ---- From 33b4345560872f29838a8e5985724efbc30cbafc Mon Sep 17 00:00:00 2001 From: Amin <69254513+AminGh05@users.noreply.github.com> Date: Sat, 28 Jun 2025 00:37:29 +0330 Subject: [PATCH 4/4] Update Session08 Backend.md added the part for get-profile --- .../Session08/Session08 Backend.md | 130 +++++++++++++++++- 1 file changed, 129 insertions(+), 1 deletion(-) diff --git a/ProjectOrientedSessions/Session08/Session08 Backend.md b/ProjectOrientedSessions/Session08/Session08 Backend.md index 5b2720a..13027e1 100644 --- a/ProjectOrientedSessions/Session08/Session08 Backend.md +++ b/ProjectOrientedSessions/Session08/Session08 Backend.md @@ -59,13 +59,141 @@ builder.Services.AddScoped(); ## ✅ Profile Page (Account Info Tab) -- [ ] Create `ProfileDto` to represent combined data for account, person, bank detail, balance. +- [ ] Create `ProfileDto` to represent combined data for account, person, bank detail, balance. +``` +public class ProfileDto +{ + // from account + public string PhoneNumber { get; set; } + public string Email { get; set; } + public decimal Balance { get; set; } + + // from person + public string FirstName { get; set; } + public string LastName { get; set; } + public string IdNumber { get; set; } + public DateTime? BirthDate { get; set; } + + // from bank-account + public string IBAN { get; set; } + public string BankAccountNumber { get; set; } + public int CardNumber { get; set; } +} +``` +You can also find another version of this DTO in [Here](https://github.com/MehrdadShirvani/AlibabaClone-Backend/blob/develop/AlibabaClone.Application/DTOs/Account/ProfileDto.cs) + - [ ] Add `GetProfileAsync` in `AccountRepository` and expose via `AccountController`. + - First, map dto to aggregate + ``` + CreateMap() + .ForMember(dest => dest.PhoneNumber, opt => opt.MapFrom(src => src.PhoneNumber)) + .ForMember(dest => dest.Email, opt => opt.MapFrom(src => src.Email)) + .ForMember(dest => dest.Balance, opt => opt.MapFrom(src => src.Balance)) + .ForMember(dest => dest.FirstName, opt => opt.MapFrom(src => src.Person != null ? src.Person.FirstName : "")) + .ForMember(dest => dest.LastName, opt => opt.MapFrom(src => src.Person != null ? src.Person.LastName : "")) + .ForMember(dest => dest.IdNumber, opt => opt.MapFrom(src => src.Person != null ? src.Person.IdNumber : "")) + .ForMember(dest => dest.BirthDate, opt => opt.MapFrom(src => src.Person != null ? src.Person.BirthDate : (DateTime?) null)) + .ForMember(dest => dest.IBAN, opt => opt.MapFrom(src => src.BankAccount != null ? src.BankAccount.IBAN : "")) + .ForMember(dest => dest.BankAccountNumber, opt => opt.MapFrom(src => src.BankAccount != null ? src.BankAccount.BankAccountNumber : "")) + .ForMember(dest => dest.CardNumber, opt => opt.MapFrom(src => src.BankAccount != null ? src.BankAccount.CardNumber : "")); + ``` + - Then, add the equivalent methods for AccountRepository, AccountService and AccountController + ``` + public class AccountRepository : BaseRepository, IAccountRepository + { + public AccountRepository(AlibabaDbContext context) : base(context) + { + + } + + public async Task GetByPhoneNumberAsync(string phoneNumber) + { + var user = await DbSet.Include(a => a.AccountRoles).ThenInclude(x => x.Role).FirstOrDefaultAsync(x => x.PhoneNumber == phoneNumber); + return user; + } + + public async Task GetProfileAsync(long accountId) + { + var profile = await DbSet + .Include(a => a.Person) + .Include(a => a.BankAccount) + .FirstOrDefaultAsync(a => a.Id == accountId); + + return profile; + } + } + + ``` + + ``` + public class AccountService : IAccountService + { + private readonly IAccountRepository _accountRepository; + private readonly IMapper _mapper; + + public async Task> GetProfileAsync(long accountId) + { + var result = await _accountRepository.GetProfileAsync(accountId); + if (result == null) + { + return Result.NotFound(null); + } + + return Result.Success(_mapper.Map(result)); + } + } + ``` + + ``` + [ApiController] + [Route("api/[controller]")] + public class AccountController : ControllerBase + { + private readonly IUserContext _userContext; + private readonly IAccountService _accountService; + + public AccountController(IUserContext userContext, IAccountService accountService) + { + _userContext = userContext; + _accountService = accountService; + } + + [HttpGet("profile")] + public async Task GetProfile() + { + // get account-id from token + long userId = _userContext.GetUserId(); + // check for user-id to be valid + if (userId <= 0) + { + return Unauthorized(); + } + + var result = await _accountService.GetProfileAsync(userId); + if (result.IsSuccess) + { + return Ok(result.Data); + } + + return result.Status switch + { + ResultStatus.Unauthorized => Unauthorized(result.ErrorMessage), + ResultStatus.NotFound => NotFound(result.ErrorMessage), + ResultStatus.ValidationError => BadRequest(result.ErrorMessage), + _ => StatusCode(500, result.ErrorMessage) + }; + } + } + ``` + + Note: You should add neccessary interfaces and implement them + - [ ] Implement: - [ ] Edit Email (with validation): `EditEmailDto`, service method, and controller endpoint. - [ ] Edit Password: `EditPasswordDto`, service and controller. - [ ] Edit Person Info: `UpsertAccountPersonDto`, and endpoint to upsert personal data. - [ ] Edit BankAccountDetail: `UpsertBankAccountDetailDto` and relevant logic. + - [ ] Add mapping for all Dtos and fix related properties like `CreatorAccountId`.