diff --git a/docker-compose.yml b/docker-compose.yml index ad39382..7cb492e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,13 +2,13 @@ services: projectr.backend: build: - context: ./src - dockerfile: Dockerfile + context: . + dockerfile: src/Dockerfile container_name: projectr-api depends_on: db: - condition: service_healthy + condition: service_started seq: condition: service_started @@ -30,9 +30,9 @@ services: - WhatsApp__BusinessAccountId=${WhatsApp__BusinessAccountId} - WhatsApp__UseMock=${WhatsApp__UseMock} - - Cloudinary__CloudName=${Cloudinary__CloudName} - - Cloudinary__ApiKey=${Cloudinary__ApiKey} - - Cloudinary__ApiSecret=${Cloudinary__ApiSecret} + # - Cloudinary__CloudName=${Cloudinary__CloudName} + # - Cloudinary__ApiKey=${Cloudinary__ApiKey} + # - Cloudinary__ApiSecret=${Cloudinary__ApiSecret} # Serilog Seq config - Serilog__WriteTo__0__Name=Seq @@ -43,25 +43,36 @@ services: - "5001:5001" db: - image: postgres:15 - container_name: postgres - restart: always + image: mcr.microsoft.com/mssql/server:2022-latest + container_name: sqlserver environment: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: password - POSTGRES_DB: projectr - - ports: - - "4400:80" - - "5432:5432" - volumes: - - postgres_data:/var/lib/postgresql/data + - ACCEPT_EULA=Y + - SA_PASSWORD=Test@1234 healthcheck: - test: [ "CMD-SHELL", "pg_isready -U postgres" ] + # test: ["CMD-SHELL", "timeout 5 bash -c ' GetByBusiness(Guid Id, [FromQuery] bool includeAll = false) + { + BusinessAvailabilityModel[] result = await _manager.GetByBusinessId(Id, includeAll); + return Ok(result); + } + + [Produces("application/json")] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ResponseModel))] + [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(ResponseModel))] + [HttpGet("{id:guid}")] + public async Task Get(Guid id) + { + ResponseModel result = await _manager.GetByIdAsync(id); + return result.Status ? Ok(result) : BadRequest(); + } + + [Produces("application/json")] + [ProducesResponseType(StatusCodes.Status201Created, Type = typeof(ResponseModel))] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ResponseModel))] + [HttpPost] + public async Task Add([FromBody] AddBusinessAvailabilityModel model) + { + if (model == null || !ModelState.IsValid) + { + return BadRequest(ModelState); + } + + ResponseModel result = await _manager.AddAsync(model); + return result.Status ? Ok(result) : BadRequest(result); + } + + [Produces("application/json")] + [ProducesResponseType(StatusCodes.Status201Created, Type = typeof(ResponseModel))] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ResponseModel))] + [HttpPut("{id:guid}")] + public async Task Update(Guid id, [FromBody] UpdateBusinessAvailabilityModel model) + { + if (model == null || !ModelState.IsValid) + { + return BadRequest(ModelState); + } + + ResponseModel result = await _manager.UpdateAsync(id, model); + return result.Status ? Ok(result) : BadRequest(result); + } + } +} diff --git a/src/Controllers/BusinessesController.cs b/src/Controllers/BusinessesController.cs index 3c41c71..5a96b7d 100644 --- a/src/Controllers/BusinessesController.cs +++ b/src/Controllers/BusinessesController.cs @@ -58,6 +58,7 @@ public async Task Add([FromBody] AddBusinessModel business) return BadRequest(ModelState); } + business.UserId = UserId; ResponseModel result = await _businessManager.AddAsync(business); return result.Status ? Ok(result) : BadRequest(result); } @@ -89,13 +90,13 @@ public async Task Delete([FromRoute] Guid id) } [Produces("application/json")] - [ProducesResponseType(StatusCodes.Status201Created, Type = typeof(ResponseModel))] [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ResponseModel))] - [HttpGet("GetByUser")] - public async Task GetByUserId() + [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(ResponseModel))] + [HttpGet("/Userbusinesses")] + public async Task GetUserBusinesses() { - BaseResponseModel result = await _businessManager.GetByUserId(UserId); - return result.Status ? Ok(result) : BadRequest(result); + BusinessModel[] result = await _businessManager.GetBusinessByUserAsync(UserId); + return Ok(result); } [Consumes("multipart/form-data")] diff --git a/src/Controllers/IndustryController.cs b/src/Controllers/IndustryController.cs index e752fcd..e57133a 100644 --- a/src/Controllers/IndustryController.cs +++ b/src/Controllers/IndustryController.cs @@ -1,57 +1,82 @@ using Microsoft.AspNetCore.Mvc; using ProjectR.Backend.Application.Interfaces.Managers; using ProjectR.Backend.Application.Models; +using ProjectR.Backend.Domain.Entities; +using ProjectR.Backend.Infrastructure.Managers; namespace ProjectR.Backend.Controllers { [ApiController] [Route("api/[controller]")] - public class IndustryController : ControllerBase + public class IndustryController : BaseController { - private readonly IIndustryManager _manager; + private readonly IIndustryManager _industryManager; - public IndustryController(IIndustryManager manager) + public IndustryController(IIndustryManager industryManager) { - _manager = manager; + _industryManager = industryManager; } + [Produces("application/json")] + [ProducesResponseType(StatusCodes.Status201Created, Type = typeof(ResponseModel))] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ResponseModel))] [HttpPost] - public async Task Create([FromBody] IndustryModel industry) + public async Task Add([FromBody] AddIndustryModel industry) { - var id = await _manager.CreateIndustryAsync(industry.Name, industry.Description); - return CreatedAtAction(nameof(GetById), new { id }, null); - } - [HttpGet("{id}")] - public async Task GetById(Guid id) - { - var industry = await _manager.GetIndustryByIdAsync(id); - if (industry == null) + if (industry == null || !ModelState.IsValid) { - return NotFound(); + return BadRequest(ModelState); } - return Ok(industry); + + ResponseModel result = await _industryManager.AddAsync(industry); + return result.Status ? Ok(result) : BadRequest(result); + } + + [Produces("application/json")] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ResponseModel))] + [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(ResponseModel))] + [HttpGet("{id:guid}")] + public async Task Get(Guid id) + { + ResponseModel result = await _industryManager.GetByIdAsync(id); + return result.Status ? Ok(result) : BadRequest(); } + [Produces("application/json")] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ResponseModel))] + [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(ResponseModel))] [HttpGet] public async Task GetAll() { - var industries = await _manager.GetAllIndustriesAsync(); - return Ok(industries); + IndustryModel[] result = await _industryManager.GetAllAsync(); + return Ok(result); } - [HttpPut("{id}")] - public async Task Update(Guid id, [FromBody] IndustryModel industry) + [Produces("application/json")] + [ProducesResponseType(StatusCodes.Status201Created, Type = typeof(ResponseModel))] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ResponseModel))] + [HttpPut] + public async Task Update([FromBody] IndustryModel industry) { - await _manager.UpdateIndustryAsync(id, industry.Name, industry.Description); - return NoContent(); + if (industry == null || !ModelState.IsValid) + { + return BadRequest(ModelState); + } + + ResponseModel result = await _industryManager.UpdateAsync(industry); + return result.Status ? Ok(result) : BadRequest(result); + } + [Produces("application/json")] + [ProducesResponseType(StatusCodes.Status201Created, Type = typeof(ResponseModel))] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ResponseModel))] [HttpDelete("{id}")] - public async Task Delete(Guid id) + public async Task Delete([FromRoute] Guid id) { - await _manager.DeleteIndustryAsync(id); - return NoContent(); + BaseResponseModel result = await _industryManager.DeleteAsync(id); + return result.Status ? Ok(result) : BadRequest(result); } } } diff --git a/src/ProjectR.Backend.Application/Interfaces/Managers/IBusinessAvailabilityManager.cs b/src/ProjectR.Backend.Application/Interfaces/Managers/IBusinessAvailabilityManager.cs new file mode 100644 index 0000000..d23f4cc --- /dev/null +++ b/src/ProjectR.Backend.Application/Interfaces/Managers/IBusinessAvailabilityManager.cs @@ -0,0 +1,18 @@ +using ProjectR.Backend.Application.Models; + +namespace ProjectR.Backend.Application.Interfaces.Managers +{ + public interface IBusinessAvailabilityManager + { + Task> GetByIdAsync(Guid id); + Task> AddAsync(AddBusinessAvailabilityModel model); + Task> UpdateAsync(Guid id, UpdateBusinessAvailabilityModel model); + Task GetByBusinessId(Guid businessId, bool includeAll = false); + /// + /// Check if the business has any availability set already within a date range + /// + /// + /// + Task HasActiveAvailabilityAsync(Guid businessId, DateTime startDate, DateTime endDate); + } +} \ No newline at end of file diff --git a/src/ProjectR.Backend.Application/Interfaces/Managers/IBusinessManager.cs b/src/ProjectR.Backend.Application/Interfaces/Managers/IBusinessManager.cs index 50d790b..e55441e 100644 --- a/src/ProjectR.Backend.Application/Interfaces/Managers/IBusinessManager.cs +++ b/src/ProjectR.Backend.Application/Interfaces/Managers/IBusinessManager.cs @@ -8,14 +8,14 @@ public interface IBusinessManager Task> GetByIdAsync(Guid id); Task> GetBySlugAsync(string slug); Task GetAllAsync(); + Task GetBusinessByUserAsync(Guid UserId); Task> AddAsync(AddBusinessModel[] businesses); Task> AddAsync(AddBusinessModel business); Task> UpdateAsync(BusinessModel business); Task> UpdateAsync(BusinessModel[] businesses); Task DeleteAsync(BusinessModel[] businesses); Task DeleteAsync(Guid id); - Task> GetByUserId(Guid userId); Task IsBusinessExist(Guid userId); - Task> UploadLogoAsync(Guid id, IFormFile file); + Task IsBusinessExist(Guid userId, Guid BusinessId); } } diff --git a/src/ProjectR.Backend.Application/Interfaces/Managers/IIndustryManager.cs b/src/ProjectR.Backend.Application/Interfaces/Managers/IIndustryManager.cs index 54b1207..2bd49b4 100644 --- a/src/ProjectR.Backend.Application/Interfaces/Managers/IIndustryManager.cs +++ b/src/ProjectR.Backend.Application/Interfaces/Managers/IIndustryManager.cs @@ -5,10 +5,10 @@ namespace ProjectR.Backend.Application.Interfaces.Managers { public interface IIndustryManager { - Task CreateIndustryAsync(string name, string? description); - Task GetIndustryByIdAsync(Guid id); - Task> GetAllIndustriesAsync(); - Task UpdateIndustryAsync(Guid id, string name, string? description); - Task DeleteIndustryAsync(Guid id); + Task> AddAsync(AddIndustryModel industry); + Task> GetByIdAsync(Guid id); + Task GetAllAsync(); + Task> UpdateAsync(IndustryModel industry); + Task DeleteAsync(Guid id); } } diff --git a/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessAvailabilityRepository.cs b/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessAvailabilityRepository.cs new file mode 100644 index 0000000..a13b89c --- /dev/null +++ b/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessAvailabilityRepository.cs @@ -0,0 +1,13 @@ +using ProjectR.Backend.Application.Models; + +namespace ProjectR.Backend.Application.Interfaces.Repository +{ + public interface IBusinessAvailabilityRepository + { + Task GetByIdAsync(Guid id); + Task GetAllByBusinessIdAsync(Guid id, bool includeAll = false); + Task AddAsync(BusinessAvailabilityModel model); + Task UpdateAsync(Guid id, UpdateBusinessAvailabilityModel model); + Task HasActiveAvailabilityAsync(Guid businessId, DateTime startDate, DateTime endDate); + } +} \ No newline at end of file diff --git a/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessRepository.cs b/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessRepository.cs index 31c0521..d190d0f 100644 --- a/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessRepository.cs +++ b/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessRepository.cs @@ -7,6 +7,7 @@ public interface IBusinessRepository Task GetByIdAsync(Guid id); Task GetBySlugAsync(string slug); Task GetAllAsync(); + Task GetBusinessByUserAsync(Guid UserId); Task AddAsync(BusinessModel[] businessModels); Task AddAsync(BusinessModel businessModel); Task UpdateAsync(BusinessModel[] businessModels); @@ -14,7 +15,7 @@ public interface IBusinessRepository Task DeleteAsync(BusinessModel[] businessModels); Task DeleteAsync(BusinessModel businessModel); Task SlugExistsAsync(string shortLink, Guid? excludedId = null); - Task GetByUserId(Guid userId); Task IsBusinessExist(Guid userId); + Task IsBusinessExist(Guid userId, Guid BusinessId); } } diff --git a/src/ProjectR.Backend.Application/Interfaces/Repository/IIndustryRepository.cs b/src/ProjectR.Backend.Application/Interfaces/Repository/IIndustryRepository.cs index a880395..45070f9 100644 --- a/src/ProjectR.Backend.Application/Interfaces/Repository/IIndustryRepository.cs +++ b/src/ProjectR.Backend.Application/Interfaces/Repository/IIndustryRepository.cs @@ -1,13 +1,14 @@ -using ProjectR.Backend.Domain.Entities; +using ProjectR.Backend.Application.Models; +using ProjectR.Backend.Domain.Entities; namespace ProjectR.Backend.Application.Interfaces.Repository { public interface IIndustryRepository { - Task CreateAsync(Industry industry); - Task GetByIdAsync(Guid id); - Task> GetAllAsync(); - Task UpdateAsync(Industry industry); - Task DeleteAsync(Guid id); + Task AddAsync(IndustryModel industry); + Task GetByIdAsync(Guid id); + Task GetAllAsync(); + Task UpdateAsync(IndustryModel industry); + Task DeleteAsync(IndustryModel industry); } } \ No newline at end of file diff --git a/src/ProjectR.Backend.Application/Models/BreakModel.cs b/src/ProjectR.Backend.Application/Models/BreakModel.cs new file mode 100644 index 0000000..ee0ea05 --- /dev/null +++ b/src/ProjectR.Backend.Application/Models/BreakModel.cs @@ -0,0 +1,32 @@ +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; + +namespace ProjectR.Backend.Domain.Entities +{ + /// + /// This is the avaibility for a business for a given period + /// + public class BreakModel : BaseObject + { + [Required] + public Guid BusinessAvailabilitySlotId { get; set; } + + //public BusinessAvailabilitySlot? BusinessAvailabilitySlot { get; set; } + + [DataType(DataType.Time, ErrorMessage = "Invalid time format")] + public DateTimeOffset? StartTime { get; set; } + + [DataType(DataType.Time, ErrorMessage = "Invalid time format")] + public DateTimeOffset? EndTime { get; set; } + } + + public class AddBreakModel + { + [DataType(DataType.Time, ErrorMessage = "Invalid time format")] + public DateTimeOffset? StartTime { get; set; } + + [DataType(DataType.Time, ErrorMessage = "Invalid time format")] + public DateTimeOffset? EndTime { get; set; } + } +} + diff --git a/src/ProjectR.Backend.Application/Models/BusinessAvailabilityModel.cs b/src/ProjectR.Backend.Application/Models/BusinessAvailabilityModel.cs new file mode 100644 index 0000000..55dbba8 --- /dev/null +++ b/src/ProjectR.Backend.Application/Models/BusinessAvailabilityModel.cs @@ -0,0 +1,50 @@ +using ProjectR.Backend.Domain.Entities; +using System.ComponentModel.DataAnnotations; + +namespace ProjectR.Backend.Application.Models +{ + + public class BusinessAvailabilityModel + { + public Guid Id { get; set; } + + [Required] + public Guid BusinessId { get; set; } + + [Required] + public DateTime? StartDate { get; set; } + + [Required] + public DateTime? EndDate { get; set; } + + [Required, MinLength(1, ErrorMessage = "At least one slot is required")] + public ICollection? Slots { get; set; } + } + + /// + /// This is a bucket for business availability slots for a given period + /// + public class AddBusinessAvailabilityModel + { + [Required] + public Guid BusinessId { get; set; } + + [DataType(DataType.Date, ErrorMessage = "Invalid date format")] + public DateTime? StartDate { get; set; } + + [DataType(DataType.Date, ErrorMessage = "Invalid date format")] + public DateTime? EndDate { get; set; } + + public List Slots { get; set; } = []; + } + + public class UpdateBusinessAvailabilityModel + { + [Required] + public Guid BusinessId { get; set; } + + [Required, MinLength(1, ErrorMessage = "At least one slot is required")] + public List? Slots { get; set; } + } +} + diff --git a/src/ProjectR.Backend.Application/Models/BusinessAvailabilitySlotModel.cs b/src/ProjectR.Backend.Application/Models/BusinessAvailabilitySlotModel.cs new file mode 100644 index 0000000..a84bfa3 --- /dev/null +++ b/src/ProjectR.Backend.Application/Models/BusinessAvailabilitySlotModel.cs @@ -0,0 +1,44 @@ +using ProjectR.Backend.Domain.Entities; +using System.ComponentModel.DataAnnotations; + +namespace ProjectR.Backend.Application.Models +{ + /// + /// This is the avaibility slot for a business for a given period and represents a day in the week + /// + public class BusinessAvailabilitySlotModel + { + [Required] + public Guid BusinessAvailabilityId { get; set; } + + //public BusinessAvailabilityModel? BusinessAvailability { get; set; } + + [DataType(DataType.Time, ErrorMessage = "Invalid time format")] + public DateTimeOffset? StartTime { get; set; } + + [DataType(DataType.Time, ErrorMessage = "Invalid time format")] + public DateTimeOffset? EndTime { get; set; } + + public DayOfWeek DayOfWeek { get; set; } + + [DataType(DataType.Date, ErrorMessage = "Invalid date format")] + public DateTimeOffset Date { get; set; } + + public List? Breaks { get; set; } + } + + public class AddBusinessAvailabilitySlotModel + { + [DataType(DataType.Date, ErrorMessage = "Invalid date format")] + public DateTimeOffset Date { get; set; } + + [DataType(DataType.Time, ErrorMessage = "Invalid time format")] + public DateTimeOffset? StartTime { get; set; } + + [DataType(DataType.Time, ErrorMessage = "Invalid time format")] + public DateTimeOffset? EndTime { get; set; } + + public List Breaks { get; set; } = []; + } +} + diff --git a/src/ProjectR.Backend.Application/Models/BusinessModel.cs b/src/ProjectR.Backend.Application/Models/BusinessModel.cs index b08c630..64a7fe0 100644 --- a/src/ProjectR.Backend.Application/Models/BusinessModel.cs +++ b/src/ProjectR.Backend.Application/Models/BusinessModel.cs @@ -1,11 +1,11 @@ -using Microsoft.AspNetCore.Http; using System.ComponentModel.DataAnnotations; -using System.Runtime.CompilerServices; +using System.Text.Json.Serialization; namespace ProjectR.Backend.Application.Models { public class BusinessModel { + [JsonIgnore] public Guid UserId { get; set; } public Guid Id { get; set; } public string? Name { get; set; } @@ -19,17 +19,20 @@ public class BusinessModel public string? Latitude { get; set; } public string? ShortLink { get; set; } public string? Logo { get; set; } - } public class AddBusinessModel { + [JsonIgnore] public Guid UserId { get; set; } + [Required(ErrorMessage = "Name is required")] public string? Name { get; set; } public string? Type { get; set; } + [Required(ErrorMessage = "Phone Code is required")] public string? PhoneCode { get; set; } + [Required(ErrorMessage = "Phone Number is required")] public string? PhoneNumber { get; set; } public string? Industry { get; set; } diff --git a/src/ProjectR.Backend.Application/Models/IndustryModel.cs b/src/ProjectR.Backend.Application/Models/IndustryModel.cs index 4e79951..23fd0db 100644 --- a/src/ProjectR.Backend.Application/Models/IndustryModel.cs +++ b/src/ProjectR.Backend.Application/Models/IndustryModel.cs @@ -6,9 +6,17 @@ public class IndustryModel { public Guid Id { get; set; } - [Required(ErrorMessage = "Industry Name is Required")] public string? Name { get; set; } public string? Description { get; set; } } + + public class AddIndustryModel + { + + [Required(ErrorMessage = "Industry Name is Required")] + public string? Name { get; set; } + + public string? Description { get; set; } + } } diff --git a/src/ProjectR.Backend.Application/Models/ResponseModel.cs b/src/ProjectR.Backend.Application/Models/ResponseModel.cs index 9112872..370e6f4 100644 --- a/src/ProjectR.Backend.Application/Models/ResponseModel.cs +++ b/src/ProjectR.Backend.Application/Models/ResponseModel.cs @@ -4,15 +4,17 @@ public class BaseResponseModel { public bool Status { get; private set; } public string? Message { get; private set; } - public BaseResponseModel(string? message = "", bool status = true) + public string[] Errors { get; private set; } + public BaseResponseModel(string? message = "", bool status = true, string[]? errors = null) { Message = message; Status = status; + Errors = errors ?? Array.Empty(); } } public class ResponseModel : BaseResponseModel { - public ResponseModel(string? message, T? data, bool status = true) : base(message, status) + public ResponseModel(string? message, T? data, bool status = true, string[]? errors = null) : base(message, status, errors) { Data = data; } diff --git a/src/ProjectR.Backend.Application/Models/UserModel.cs b/src/ProjectR.Backend.Application/Models/UserModel.cs index ba7b889..0ee5362 100644 --- a/src/ProjectR.Backend.Application/Models/UserModel.cs +++ b/src/ProjectR.Backend.Application/Models/UserModel.cs @@ -21,14 +21,8 @@ public class UserModel public class AddUserModel { - // [Required(ErrorMessage = "Email is required")] - // [EmailAddress(ErrorMessage = "Invalid email format.")] public string Email { get; set; } = string.Empty; - // [Required(ErrorMessage = "Phone number is required")] - // [RegularExpression(@"^\d{10,15}$", ErrorMessage = "Invalid phone number format. It should be between 10 to 15 digits.")] public string PhoneNumber { get; set; } = string.Empty; - // [Required(ErrorMessage = "Phone Code is required.")] - // [RegularExpression(@"^\+\d{1,3}$", ErrorMessage = "Invalid phone code format. Use the format +[country code].")] public string PhoneCode { get; set; } = string.Empty; [Required(ErrorMessage = "Account type is required")] public AccountType AccountType { get; set; } diff --git a/src/ProjectR.Backend.Application/ProjectR.Backend.Application.csproj b/src/ProjectR.Backend.Application/ProjectR.Backend.Application.csproj index 4500a87..c33e90f 100644 --- a/src/ProjectR.Backend.Application/ProjectR.Backend.Application.csproj +++ b/src/ProjectR.Backend.Application/ProjectR.Backend.Application.csproj @@ -17,6 +17,9 @@ + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/ProjectR.Backend.Application/Settings/BusinessAvailabilitySettings.cs b/src/ProjectR.Backend.Application/Settings/BusinessAvailabilitySettings.cs new file mode 100644 index 0000000..59abbab --- /dev/null +++ b/src/ProjectR.Backend.Application/Settings/BusinessAvailabilitySettings.cs @@ -0,0 +1,10 @@ +namespace ProjectR.Backend.Application.Settings +{ + public class BusinessAvailabilitySettings + { + /// + /// Maximum number of days in advance a booking can be made + /// + public int MaxAdvanceBookingInDays { get; set; } + } +} diff --git a/src/ProjectR.Backend.Application/Validators/BusinessAvailabilityValidator.cs b/src/ProjectR.Backend.Application/Validators/BusinessAvailabilityValidator.cs new file mode 100644 index 0000000..e9b8553 --- /dev/null +++ b/src/ProjectR.Backend.Application/Validators/BusinessAvailabilityValidator.cs @@ -0,0 +1,230 @@ +using FluentValidation; +using Microsoft.Extensions.Options; +using ProjectR.Backend.Application.Models; +using ProjectR.Backend.Application.Settings; +using ProjectR.Backend.Domain.Entities; + +namespace ProjectR.Backend.Application.Validators +{ + public class BusinessAvailabilityValidator : AbstractValidator + { + private readonly BusinessAvailabilitySettings _settings; + + public BusinessAvailabilityValidator(IOptions settings) + { + #region Validation Checks + //check that the end date is after the start date + //check if the business exist + //check if business availability already exists for the business + + //check that slots are valid i.e One slot to One day of the week + //check that only one date is used in the slots + //check that there are not dup + + //ensure that start time of the date is before the end time + //ensure that the times in the breaks are within the time of the slot + //should we let users have breaks occupying the whole slot time? + #endregion + + _settings = settings.Value; + + // Rule: BusinessId required + RuleFor(x => x.BusinessId) + .NotEmpty().WithMessage("BusinessId is required."); + + // Rule: StartDate and EndDate required and valid + RuleFor(x => x.StartDate) + .NotNull().WithMessage("Start date is required."); + + RuleFor(x => x.EndDate) + .NotNull().WithMessage("End date is required."); + + // Rule: EndDate must be after StartDate + RuleFor(x => x.EndDate) + .GreaterThanOrEqualTo(x => x.StartDate) + .When(x => x.StartDate.HasValue && x.EndDate.HasValue) + .WithMessage("End date must be after or equal to start date."); + + //Rule: Cannot add dates in the past + RuleFor(x => x.StartDate) + .GreaterThanOrEqualTo(x => DateTime.UtcNow) + .WithMessage("Start Date cannot be in the past"); + + // Rule: Gap must not exceed settings.MaxAdvanceBookingInDays + RuleFor(x => x) + .Must(x => + { + if (x.StartDate.HasValue && x.EndDate.HasValue) + { + TimeSpan diff = x.EndDate.Value + - x.StartDate.Value; + return diff.Days <= _settings.MaxAdvanceBookingInDays; + } + + return true; + }) + .WithMessage($"The gap between start and end date cannot exceed {_settings.MaxAdvanceBookingInDays} days."); + + // Rule: At least one slot required + RuleFor(x => x.Slots) + .NotNull().WithMessage("At least one slot is required.") + .Must(slots => slots != null && slots.Count > 0) + .WithMessage("At least one slot is required."); + + // Rule: Each slot must have valid times and date + RuleForEach(x => x.Slots).SetValidator(new AddBusinessAvailabilitySlotValidator()); + + // Rule: No overlapping slots on the same date + RuleFor(x => x.Slots) + .Must(slots => + { + if (slots == null) + { + return true; + } + + IEnumerable> slotGroups = slots.GroupBy(s => s.Date.Date); + foreach (IGrouping group in slotGroups) + { + List slotList = group.ToList(); + for (int i = 0; i < slotList.Count; i++) + { + for (int j = i + 1; j < slotList.Count; j++) + { + AddBusinessAvailabilitySlotModel a = slotList[i]; + AddBusinessAvailabilitySlotModel b = slotList[j]; + if (a.StartTime.HasValue && a.EndTime.HasValue && b.StartTime.HasValue && b.EndTime.HasValue) + { + if (a.StartTime < b.EndTime && b.StartTime < a.EndTime) + { + return false; + } + } + } + } + } + + return true; + }) + .WithMessage("Slots must not overlap on the same date."); + + // Rule: Breaks must not overlap within the same slot + RuleFor(x => x.Slots) + .Must(slots => + { + if (slots == null) + { + return true; + } + + foreach (AddBusinessAvailabilitySlotModel? slot in slots) + { + if (slot.Breaks == null) + { + continue; + } + + List breaks = slot.Breaks; + for (int i = 0; i < breaks.Count; i++) + { + for (int j = i + 1; j < breaks.Count; j++) + { + AddBreakModel a = breaks[i]; + AddBreakModel b = breaks[j]; + if (a.StartTime.HasValue && a.EndTime.HasValue && b.StartTime.HasValue && b.EndTime.HasValue) + { + if (a.StartTime < b.EndTime && b.StartTime < a.EndTime) + { + return false; + } + } + } + } + } + + return true; + }) + .WithMessage("Breaks within a slot must not overlap."); + + // Rule: Each break must be within the slot's time range + RuleFor(x => x.Slots) + .Must(slots => + { + if (slots == null) + { + return true; + } + + foreach (AddBusinessAvailabilitySlotModel? slot in slots) + { + if (slot.Breaks == null) + { + continue; + } + + foreach (AddBreakModel brk in slot.Breaks) + { + if (slot.StartTime.HasValue && slot.EndTime.HasValue && brk.StartTime.HasValue && brk.EndTime.HasValue) + { + if (brk.StartTime < slot.StartTime || brk.EndTime > slot.EndTime) + { + return false; + } + } + } + } + + return true; + }) + .WithMessage("Breaks must be within the slot's start and end time."); + } + } + + public class AddBusinessAvailabilitySlotValidator : AbstractValidator + { + public AddBusinessAvailabilitySlotValidator() + { + RuleFor(x => x.Date) + .NotEmpty().WithMessage("Slot date is required."); + + RuleFor(x => x.StartTime) + .NotNull().WithMessage("Slot start time is required."); + + RuleFor(x => x.EndTime) + .NotNull().WithMessage("Slot end time is required."); + + RuleFor(x => x) + .Must(x => x.StartTime.HasValue && x.EndTime.HasValue && x.EndTime > x.StartTime) + .WithMessage("Slot end time must be after start time."); + + + //Rule: Cannot add times in the past + RuleFor(x => x.StartTime) + .GreaterThanOrEqualTo(x => DateTime.UtcNow) + .WithMessage("Slot StartTime cannot be in the past"); + + RuleForEach(x => x.Breaks).SetValidator(new AddBreakValidator()); + } + } + + public class AddBreakValidator : AbstractValidator + { + public AddBreakValidator() + { + RuleFor(x => x.StartTime) + .NotNull().WithMessage("Break start time is required."); + + RuleFor(x => x.EndTime) + .NotNull().WithMessage("Break end time is required."); + + RuleFor(x => x) + .Must(x => x.StartTime.HasValue && x.EndTime.HasValue && x.EndTime > x.StartTime) + .WithMessage("Break end time must be after start time."); + + //Rule: Cannot add time in the past + RuleFor(x => x.StartTime) + .GreaterThanOrEqualTo(x => DateTime.UtcNow) + .WithMessage("Break StartTime cannot be in the past"); + } + } +} \ No newline at end of file diff --git a/src/ProjectR.Backend.Domain/Entities/Appointment.cs b/src/ProjectR.Backend.Domain/Entities/Appointment.cs index b99a8fe..93ca6e8 100644 --- a/src/ProjectR.Backend.Domain/Entities/Appointment.cs +++ b/src/ProjectR.Backend.Domain/Entities/Appointment.cs @@ -1,3 +1,4 @@ +using ProjectR.Backend.Shared; using System.Collections.ObjectModel; using System.ComponentModel.DataAnnotations; @@ -5,17 +6,11 @@ namespace ProjectR.Backend.Domain.Entities { public class Appointment : BaseObject { - // public Guid BusinessId { get; set; } - // public Business? Business { get; set; } - // public DateOnly? StartDate { get; set; } - // public DateOnly? EndDate { get; set; } - // /// - // /// This will be used in scenerios where we decide to use templating. - // /// Templating allows a business to reuse a previous availability without necessarily setting it all over again - // /// - // public DateOnly? ValidFrom { get; set; } - // public DateOnly? ValidTo { get; set; } - // public Collection? Slots { get; set; } + [Required] + public Guid CustomerId { get; set; } + public Customer? Customer { get; set; } + [Required] + public AppointmentStatus Status { get; set; } } } diff --git a/src/ProjectR.Backend.Domain/Entities/BaseObject.cs b/src/ProjectR.Backend.Domain/Entities/BaseObject.cs index cd3f829..98ae4a8 100644 --- a/src/ProjectR.Backend.Domain/Entities/BaseObject.cs +++ b/src/ProjectR.Backend.Domain/Entities/BaseObject.cs @@ -8,6 +8,6 @@ public class BaseObject public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow; public DateTimeOffset UpdatedAt { get; set; } public string? UpdatedBy { get; set; } - public RecordStatus? RecordStatus { get; set; } + public RecordStatus? RecordStatus { get; set; } = Shared.RecordStatus.Active; } } \ No newline at end of file diff --git a/src/ProjectR.Backend.Domain/Entities/Break.cs b/src/ProjectR.Backend.Domain/Entities/Break.cs new file mode 100644 index 0000000..b8d2579 --- /dev/null +++ b/src/ProjectR.Backend.Domain/Entities/Break.cs @@ -0,0 +1,19 @@ +using System.ComponentModel.DataAnnotations; + +namespace ProjectR.Backend.Domain.Entities +{ + /// + /// This is the avaibility for a business for a given period + /// + public class Break : BaseObject + { + [Required] + public Guid BusinessAvailabilitySlotId { get; set; } + public BusinessAvailabilitySlot? BusinessAvailabilitySlot { get; set; } + [Required] + public DateTimeOffset? StartTime { get; set; } + [Required] + public DateTimeOffset? EndTime { get; set; } + } +} + diff --git a/src/ProjectR.Backend.Domain/Entities/BusinessAvailability.cs b/src/ProjectR.Backend.Domain/Entities/BusinessAvailability.cs index 2c1599c..f0e66ae 100644 --- a/src/ProjectR.Backend.Domain/Entities/BusinessAvailability.cs +++ b/src/ProjectR.Backend.Domain/Entities/BusinessAvailability.cs @@ -1,21 +1,18 @@ -using System.Collections.ObjectModel; -using System.ComponentModel.DataAnnotations; +using ProjectR.Backend.Shared; namespace ProjectR.Backend.Domain.Entities { + /// + /// This is a bucket for business availability slots for a given period + /// public class BusinessAvailability : BaseObject { public Guid BusinessId { get; set; } public Business? Business { get; set; } - public DateOnly? StartDate { get; set; } - public DateOnly? EndDate { get; set; } - /// - /// This will be used in scenerios where we decide to use templating. - /// Templating allows a business to reuse a previous availability without necessarily setting it all over again - /// - public DateOnly? ValidFrom { get; set; } - public DateOnly? ValidTo { get; set; } - public Collection? Slots { get; set; } + public DateTimeOffset? StartDate { get; set; } + public DateTimeOffset? EndDate { get; set; } + public ICollection? Slots { get; set; } + //RecordStatus } } diff --git a/src/ProjectR.Backend.Domain/Entities/BusinessAvailabilitySlot.cs b/src/ProjectR.Backend.Domain/Entities/BusinessAvailabilitySlot.cs index dd3a30b..417e175 100644 --- a/src/ProjectR.Backend.Domain/Entities/BusinessAvailabilitySlot.cs +++ b/src/ProjectR.Backend.Domain/Entities/BusinessAvailabilitySlot.cs @@ -3,7 +3,7 @@ namespace ProjectR.Backend.Domain.Entities { /// - /// This is the avaibility for a business for a given period + /// This is the avaibility slot for a business for a given period and represents a day in the week /// public class BusinessAvailabilitySlot : BaseObject { @@ -11,16 +11,15 @@ public class BusinessAvailabilitySlot : BaseObject public Guid BusinessAvailabilityId { get; set; } public BusinessAvailability? BusinessAvailability { get; set; } [Required] - public TimeOnly? StartTime { get; set; } + public DateTimeOffset? StartTime { get; set; } [Required] - public TimeOnly? EndTime { get; set; } - public DayOfWeek DayOfWeek { get; set; } - + public DateTimeOffset? EndTime { get; set; } + public DayOfWeek DayOfWeek { get; set; } /// - /// keeping the breaks here as a list of time(may be better to extract and compre that way) - /// This is subject to restructuring if need be in the future + /// The specific date for this slot. Slots are generally recurring weekly but this date represents the specific date for this slot /// - public List? Breaks { get; set; } + public DateTimeOffset Date { get; set; } + public ICollection? Breaks { get; set; } } } diff --git a/src/ProjectR.Backend.Domain/Entities/Customer.cs b/src/ProjectR.Backend.Domain/Entities/Customer.cs new file mode 100644 index 0000000..2157b26 --- /dev/null +++ b/src/ProjectR.Backend.Domain/Entities/Customer.cs @@ -0,0 +1,20 @@ +using ProjectR.Backend.Shared; +using System.ComponentModel.DataAnnotations; + +namespace ProjectR.Backend.Domain.Entities +{ + /// + /// This represents a customer that has booked a business in the system. We collect this information to be able to retain customer information and contact them if need be + /// + public class Customer : BaseObject + { + public string? PhoneNumber { get; set; } + public string? PhoneCode { get; set; } + public string? Email { get; set; } + /// + /// This identifies a user type in the system [Business, Client, Admin etc] + /// + public string? Name { get; set; } + } +} + diff --git a/src/ProjectR.Backend.Infrastructure/Managers/BusinessAvailabilityManager.cs b/src/ProjectR.Backend.Infrastructure/Managers/BusinessAvailabilityManager.cs new file mode 100644 index 0000000..d455e30 --- /dev/null +++ b/src/ProjectR.Backend.Infrastructure/Managers/BusinessAvailabilityManager.cs @@ -0,0 +1,82 @@ +using FluentValidation; +using FluentValidation.Results; +using Microsoft.Extensions.Options; +using ProjectR.Backend.Application.Interfaces.Managers; +using ProjectR.Backend.Application.Interfaces.Repository; +using ProjectR.Backend.Application.Models; +using ProjectR.Backend.Application.Settings; +using ProjectR.Backend.Shared.Mappers; + +namespace ProjectR.Backend.Infrastructure.Managers +{ + public class BusinessAvailabilityManager : IBusinessAvailabilityManager + { + public readonly IBusinessAvailabilityRepository _repository; + public readonly IBusinessManager _businessManager; + private readonly IValidator _validator; + + public BusinessAvailabilityManager(IBusinessAvailabilityRepository repository, IValidator validator, IBusinessManager businessManager) + { + _repository = repository; + _businessManager = businessManager ?? throw new ArgumentNullException(nameof(businessManager)); + _validator = validator ?? throw new ArgumentNullException(nameof(validator)); + } + + public async Task> AddAsync(AddBusinessAvailabilityModel model) + { + ResponseModel business = await _businessManager.GetByIdAsync(model.BusinessId); + if (business.Data == null) + { + return new ResponseModel("Business not found", null, false); + } + + //TODO: check if the business already has availability set for the same day and time range + //for example, if the business has availability on 12th - 19th June, it should not be able to add another availability for the same date range + + ValidationResult validate = _validator.Validate(model); + if (!validate.IsValid) + { + return new ResponseModel(message: "Validation errors occurred", data: null, status: false, errors: validate.Errors.Select(e => e.ErrorMessage).ToArray()); + } + + BusinessAvailabilityModel newAvailability = Mapper.Map(model); + await _repository.AddAsync(newAvailability); + return new ResponseModel(message: "Business Availability created successfully", data: newAvailability, status: true); + } + + public async Task GetByBusinessId(Guid businessId, bool includeAll = false) + { + BusinessAvailabilityModel[] result = await _repository.GetAllByBusinessIdAsync(businessId, includeAll); + return result; + } + + public async Task> GetByIdAsync(Guid id) + { + BusinessAvailabilityModel? result = await _repository.GetByIdAsync(id); + return new ResponseModel(message: result != null ? "Business Availability retrieved successfully" : "Business Availability not found", data: result, status: result != null); + } + + public async Task HasActiveAvailabilityAsync(Guid businessId, DateTime startDate, DateTime endDate) + { + return await _repository.HasActiveAvailabilityAsync(businessId, startDate, endDate); + } + + public async Task> UpdateAsync(Guid id, UpdateBusinessAvailabilityModel model) + { + BusinessAvailabilityModel? existing = await _repository.GetByIdAsync(id); + if (existing == null) + { + return new ResponseModel("Business Availability not found", null, false); + } + + UpdateBusinessAvailabilityModel updatedAvailability = Mapper.Map(model); + BusinessAvailabilityModel result = await _repository.UpdateAsync(id, updatedAvailability); + + //put all notification into a table and have a background service send them out or Send them out in parallel using Task.WhenAll + //TODO: send notification to business owner about the update (via WhatsApp) + //TODO: send notification to customers who have bookings in the updated slots (WhatsApp) + //TODO: send out a SignalR notification to connected clients about the update + return new ResponseModel("Business Availability updated successfully", result, true); + } + } +} diff --git a/src/ProjectR.Backend.Infrastructure/Managers/BusinessManager.cs b/src/ProjectR.Backend.Infrastructure/Managers/BusinessManager.cs index d0addbc..630a20f 100644 --- a/src/ProjectR.Backend.Infrastructure/Managers/BusinessManager.cs +++ b/src/ProjectR.Backend.Infrastructure/Managers/BusinessManager.cs @@ -10,13 +10,11 @@ public class BusinessManager : IBusinessManager { public readonly IBusinessRepository _businessRepository; private readonly ISlugService _slugService; - private readonly ICloudinaryService _cloudinaryService; - public BusinessManager(IBusinessRepository businessRepository, ISlugService slugService, ICloudinaryService cloudinaryService) + public BusinessManager(IBusinessRepository businessRepository, ISlugService slugService) { _businessRepository = businessRepository; _slugService = slugService; - _cloudinaryService = cloudinaryService; } public async Task> AddAsync(AddBusinessModel business) @@ -87,7 +85,6 @@ public async Task> AddAsync(AddBusinessModel[] bu BusinessModel[] result = await _businessRepository.AddAsync(models); return new ResponseModel(message: "Businesses Added Successfully", data: result, status: true); - } public async Task DeleteAsync(BusinessModel[] businesses) @@ -125,10 +122,9 @@ public async Task> GetBySlugAsync(string slug) return new ResponseModel(message: result != null ? "Business retrieved successfully" : "Business not found", data: result, status: result != null); } - public async Task> GetByUserId(Guid userId) + public async Task GetBusinessByUserAsync(Guid UserId) { - BusinessModel? result = await _businessRepository.GetByUserId(userId); - return new ResponseModel(message: result != null ? "Business retrieved successfully" : "Business not found", data: result, status: result != null); + return await _businessRepository.GetBusinessByUserAsync(UserId); } public async Task IsBusinessExist(Guid userId) @@ -136,6 +132,11 @@ public async Task IsBusinessExist(Guid userId) return await _businessRepository.IsBusinessExist(userId); } + public async Task IsBusinessExist(Guid userId, Guid BusinessId) + { + return await _businessRepository.IsBusinessExist(userId,BusinessId); + } + public async Task> UpdateAsync(BusinessModel business) { diff --git a/src/ProjectR.Backend.Infrastructure/Managers/IndustryManager.cs b/src/ProjectR.Backend.Infrastructure/Managers/IndustryManager.cs index f8cabc3..7d6ec53 100644 --- a/src/ProjectR.Backend.Infrastructure/Managers/IndustryManager.cs +++ b/src/ProjectR.Backend.Infrastructure/Managers/IndustryManager.cs @@ -1,66 +1,67 @@ using ProjectR.Backend.Application.Interfaces.Managers; -using ProjectR.Backend.Application.Models; using ProjectR.Backend.Application.Interfaces.Repository; +using ProjectR.Backend.Application.Models; using ProjectR.Backend.Domain.Entities; +using ProjectR.Backend.Persistence.Repository; namespace ProjectR.Backend.Infrastructure.Managers { public class IndustryManager : IIndustryManager { - private readonly IIndustryRepository _repository; + private readonly IIndustryRepository _industryRepository; public IndustryManager(IIndustryRepository repository) { - _repository = repository; + _industryRepository = repository; } - public async Task CreateIndustryAsync(string name, string? description) + public async Task> AddAsync(AddIndustryModel model) { - var industry = new Industry - { - Id = Guid.NewGuid(), - Name = name, - Description = description + IndustryModel entity = new() + { + Name = model.Name, + Description = model.Description, }; - return await _repository.CreateAsync(industry); + IndustryModel result = await _industryRepository.AddAsync(entity); + return new ResponseModel(message: "Business Added Successfully", data: result, status: true); } - public async Task GetIndustryByIdAsync(Guid id) + public async Task> GetByIdAsync(Guid id) { - var industry = await _repository.GetByIdAsync(id); - return industry == null ? null : new Industry - { - Id = industry.Id, - Name = industry.Name , - Description = industry.Description - }; + IndustryModel? result = await _industryRepository.GetByIdAsync(id); + return new ResponseModel(message: result != null ? "Industry retrieved successfully" : "Industry not found", data: result, status: result != null); + } - public async Task> GetAllIndustriesAsync() + public async Task GetAllAsync() { - var industries = await _repository.GetAllAsync(); - return industries.Select(i => new Industry - { - Id = i.Id, - Name = i.Name, - Description = i.Description - }).ToList(); + return await _industryRepository.GetAllAsync(); } - public async Task UpdateIndustryAsync(Guid id, string name, string? description) + public async Task DeleteAsync(Guid id) { - var industry = await _repository.GetByIdAsync(id); - if (industry != null) + IndustryModel? existingIndustry = await _industryRepository.GetByIdAsync(id); + if (existingIndustry == null) { - industry.Name = name; - industry.Description = description; - await _repository.UpdateAsync(industry); + return new BaseResponseModel(message: "Industry not found", status: false); } + + await _industryRepository.DeleteAsync(existingIndustry); + return new BaseResponseModel(message: "Industry succesfully deleted", status: true); } - public async Task DeleteIndustryAsync(Guid id) + + + public async Task> UpdateAsync(IndustryModel industry) { - await _repository.DeleteAsync(id); + IndustryModel? existingIndustry = await _industryRepository.GetByIdAsync(industry.Id); + if (existingIndustry == null) + { + return new ResponseModel(message: "Industry not found", data: default, status: false); + } + + IndustryModel result = await _industryRepository.UpdateAsync(industry); + return new ResponseModel(message: "Business updated successfully", data: result, status: true); } } } diff --git a/src/ProjectR.Backend.Infrastructure/ProjectR.Backend.Infrastructure.csproj b/src/ProjectR.Backend.Infrastructure/ProjectR.Backend.Infrastructure.csproj index d256f27..0e7cd7a 100644 --- a/src/ProjectR.Backend.Infrastructure/ProjectR.Backend.Infrastructure.csproj +++ b/src/ProjectR.Backend.Infrastructure/ProjectR.Backend.Infrastructure.csproj @@ -8,6 +8,8 @@ + + diff --git a/src/ProjectR.Backend.Infrastructure/Providers/WhatsAppProvider.cs b/src/ProjectR.Backend.Infrastructure/Providers/WhatsAppProvider.cs index 959a2d8..a274149 100644 --- a/src/ProjectR.Backend.Infrastructure/Providers/WhatsAppProvider.cs +++ b/src/ProjectR.Backend.Infrastructure/Providers/WhatsAppProvider.cs @@ -97,6 +97,7 @@ public async Task SendInteractiveReplyButtonMessageAsync(InteractiveMessag return default; } } + public async Task SendSimpleMessageAsync(SimpleMessageModel model) { if (_settings.UseMock) diff --git a/src/ProjectR.Backend.Infrastructure/ServiceConfigurations/ServiceCollectionRegistration.cs b/src/ProjectR.Backend.Infrastructure/ServiceConfigurations/ServiceCollectionRegistration.cs index 600bae5..5fc8bed 100644 --- a/src/ProjectR.Backend.Infrastructure/ServiceConfigurations/ServiceCollectionRegistration.cs +++ b/src/ProjectR.Backend.Infrastructure/ServiceConfigurations/ServiceCollectionRegistration.cs @@ -1,4 +1,5 @@ using CloudinaryDotNet; +using FluentValidation; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; @@ -13,6 +14,7 @@ using ProjectR.Backend.Application.Interfaces.Repository; using ProjectR.Backend.Application.Interfaces.Utility; using ProjectR.Backend.Application.Settings; +using ProjectR.Backend.Application.Validators; using ProjectR.Backend.Infrastructure.Managers; using ProjectR.Backend.Infrastructure.Providers; using ProjectR.Backend.Infrastructure.Utility; @@ -34,6 +36,11 @@ public static void RegisterServices(this IServiceCollection services, IConfigura services.Configure(configuration.GetSection("Twilio")); services.Configure(configuration.GetSection("Otp")); services.Configure(configuration.GetSection("Cloudinary")); + services.Configure(configuration.GetSection("BusinessAvailability")); + #endregion + + #region Validators + services.AddValidatorsFromAssemblyContaining(); #endregion #region Providers @@ -48,6 +55,7 @@ public static void RegisterServices(this IServiceCollection services, IConfigura services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); #endregion #region Managers @@ -62,6 +70,7 @@ public static void RegisterServices(this IServiceCollection services, IConfigura services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); #endregion #region Services @@ -138,9 +147,9 @@ public static void RegisterDatabaseServices(this IServiceCollection services, IC { string connectionString = configuration.GetConnectionString("DefaultConnection")!; services.AddDbContext(options => - options.UseNpgsql(connectionString, options => + options.UseSqlServer(connectionString, options => { - options.EnableRetryOnFailure(maxRetryCount: 5, maxRetryDelay: TimeSpan.FromSeconds(10), errorCodesToAdd: []); + options.EnableRetryOnFailure(maxRetryCount: 5, maxRetryDelay: TimeSpan.FromSeconds(10), errorNumbersToAdd: []); })); } public static void RegisterHttpClients(this IServiceCollection services, IConfiguration configuration) diff --git a/src/ProjectR.Backend.Persistence/Configurations/BreakConfiguration.cs b/src/ProjectR.Backend.Persistence/Configurations/BreakConfiguration.cs new file mode 100644 index 0000000..0341e93 --- /dev/null +++ b/src/ProjectR.Backend.Persistence/Configurations/BreakConfiguration.cs @@ -0,0 +1,28 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using ProjectR.Backend.Domain.Entities; + +namespace ProjectR.Backend.Persistence.Configurations +{ + public class BreakConfiguration : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(x => x.Id); + + builder.Property(x => x.BusinessAvailabilitySlotId) + .IsRequired(); + + builder.HasOne(x => x.BusinessAvailabilitySlot) + .WithMany(x => x.Breaks) + .HasForeignKey(x => x.BusinessAvailabilitySlotId) + .OnDelete(DeleteBehavior.Cascade); + + builder.Property(x => x.StartTime) + .IsRequired(); + + builder.Property(x => x.EndTime) + .IsRequired(); + } + } +} diff --git a/src/ProjectR.Backend.Persistence/Configurations/BusinessAvailabilityConfiguration.cs b/src/ProjectR.Backend.Persistence/Configurations/BusinessAvailabilityConfiguration.cs index eb01198..bf17da2 100644 --- a/src/ProjectR.Backend.Persistence/Configurations/BusinessAvailabilityConfiguration.cs +++ b/src/ProjectR.Backend.Persistence/Configurations/BusinessAvailabilityConfiguration.cs @@ -8,21 +8,26 @@ public class BusinessAvailabilityConfiguration : IEntityTypeConfiguration builder) { - builder.HasKey(e => e.Id); - builder.Property(e => e.BusinessId).IsRequired(); - builder.Property(e => e.StartDate).IsRequired(); - builder.Property(e => e.EndDate).IsRequired(); - builder.Property(e => e.ValidFrom); - builder.Property(e => e.ValidTo); + builder.HasKey(x => x.Id); - builder.HasOne(e => e.Business) - .WithMany() - .HasForeignKey(e => e.BusinessId) - .OnDelete(DeleteBehavior.Cascade); + builder.Property(x => x.BusinessId) + .IsRequired(); - builder.HasMany(e => e.Slots) - .WithOne() - .HasForeignKey(e => e.BusinessAvailabilityId); + builder.HasOne(x => x.Business) + .WithMany() + .HasForeignKey(x => x.BusinessId) + .OnDelete(DeleteBehavior.Cascade); + + builder.Property(x => x.StartDate) + .IsRequired(); + + builder.Property(x => x.EndDate) + .IsRequired(); + + builder.HasMany(x => x.Slots) + .WithOne(x => x.BusinessAvailability) + .HasForeignKey(x => x.BusinessAvailabilityId) + .OnDelete(DeleteBehavior.Cascade); } } } diff --git a/src/ProjectR.Backend.Persistence/Configurations/BusinessAvailabilitySlotConfiguration.cs b/src/ProjectR.Backend.Persistence/Configurations/BusinessAvailabilitySlotConfiguration.cs new file mode 100644 index 0000000..f253a15 --- /dev/null +++ b/src/ProjectR.Backend.Persistence/Configurations/BusinessAvailabilitySlotConfiguration.cs @@ -0,0 +1,36 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using ProjectR.Backend.Domain.Entities; + +namespace ProjectR.Backend.Persistence.Configurations +{ + public class BusinessAvailabilitySlotConfiguration : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(x => x.Id); + + builder.Property(x => x.BusinessAvailabilityId) + .IsRequired(); + + builder.HasOne(x => x.BusinessAvailability) + .WithMany(x => x.Slots) + .HasForeignKey(x => x.BusinessAvailabilityId) + .OnDelete(DeleteBehavior.Cascade); + + builder.Property(x => x.StartTime) + .IsRequired(); + + builder.Property(x => x.EndTime) + .IsRequired(); + + builder.Property(x => x.DayOfWeek) + .IsRequired(); + + builder.HasMany(x => x.Breaks) + .WithOne(x => x.BusinessAvailabilitySlot) + .HasForeignKey(x => x.BusinessAvailabilitySlotId) + .OnDelete(DeleteBehavior.Cascade); + } + } +} diff --git a/src/ProjectR.Backend.Persistence/DatabaseContext/DatabaseContext.cs b/src/ProjectR.Backend.Persistence/DatabaseContext/DatabaseContext.cs index 2c13020..387e31c 100644 --- a/src/ProjectR.Backend.Persistence/DatabaseContext/DatabaseContext.cs +++ b/src/ProjectR.Backend.Persistence/DatabaseContext/DatabaseContext.cs @@ -11,6 +11,7 @@ public class AppDbContext : DbContext public DbSet Businesses => Set(); public DbSet BusinessAvailabilities => Set(); public DbSet BusinessAvailabilitySlots => Set(); + public DbSet Breaks => Set(); public DbSet Otps => Set(); public DbSet Industries { get; set; } diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250711140719_InitialMigration.Designer.cs b/src/ProjectR.Backend.Persistence/Migrations/20250711140719_InitialMigration.Designer.cs deleted file mode 100644 index 1e2093e..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250711140719_InitialMigration.Designer.cs +++ /dev/null @@ -1,271 +0,0 @@ -// -using System; -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; -using ProjectR.Backend.Persistence.DatabaseContext; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - [DbContext(typeof(AppDbContext))] - [Migration("20250711140719_InitialMigration")] - partial class InitialMigration - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.7") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("About") - .HasMaxLength(1000) - .HasColumnType("character varying(1000)"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Industry") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("Latitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Location") - .HasMaxLength(255) - .HasColumnType("character varying(255)"); - - b.Property("Longitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Name") - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("PhoneCode") - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .HasMaxLength(15) - .HasColumnType("character varying(15)"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("ServiceType") - .HasColumnType("integer"); - - b.Property("Type") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("businesses", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("BusinessId") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EndDate") - .HasColumnType("date"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartDate") - .HasColumnType("date"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.Property("ValidFrom") - .HasColumnType("date"); - - b.Property("ValidTo") - .HasColumnType("date"); - - b.HasKey("Id"); - - b.HasIndex("BusinessId"); - - b.ToTable("BusinessAvailabilities"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.PrimitiveCollection>("Breaks") - .HasColumnType("time without time zone[]"); - - b.Property("BusinessAvailabilityId") - .HasColumnType("uuid"); - - b.Property("BusinessAvailabilityId1") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DayOfWeek") - .HasColumnType("integer"); - - b.Property("EndTime") - .HasColumnType("time without time zone"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartTime") - .HasColumnType("time without time zone"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("BusinessAvailabilityId"); - - b.HasIndex("BusinessAvailabilityId1"); - - b.ToTable("BusinessAvailabilitySlots"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("AccountType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Email") - .HasColumnType("text"); - - b.Property("PhoneCode") - .IsRequired() - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .IsRequired() - .HasColumnType("text"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("RegistrationType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("users", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.Business", "Business") - .WithMany() - .HasForeignKey("BusinessId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Business"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", null) - .WithMany("Slots") - .HasForeignKey("BusinessAvailabilityId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", "BusinessAvailability") - .WithMany() - .HasForeignKey("BusinessAvailabilityId1") - .HasConstraintName("FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessA~1"); - - b.Navigation("BusinessAvailability"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Navigation("Slots"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250711140719_InitialMigration.cs b/src/ProjectR.Backend.Persistence/Migrations/20250711140719_InitialMigration.cs deleted file mode 100644 index 197477d..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250711140719_InitialMigration.cs +++ /dev/null @@ -1,162 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - /// - public partial class InitialMigration : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "users", - columns: table => new - { - Id = table.Column(type: "uuid", nullable: false), - PhoneNumber = table.Column(type: "text", nullable: false), - PhoneCode = table.Column(type: "character varying(4)", maxLength: 4, nullable: false), - Email = table.Column(type: "text", nullable: true), - AccountType = table.Column(type: "integer", nullable: false, defaultValue: 1), - RegistrationType = table.Column(type: "integer", nullable: false, defaultValue: 1), - CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), - UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false), - UpdatedBy = table.Column(type: "text", nullable: true), - RecordStatus = table.Column(type: "integer", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_users", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "businesses", - columns: table => new - { - Id = table.Column(type: "uuid", nullable: false), - UserId = table.Column(type: "uuid", nullable: false), - Name = table.Column(type: "character varying(200)", maxLength: 200, nullable: true), - Type = table.Column(type: "character varying(100)", maxLength: 100, nullable: true), - PhoneCode = table.Column(type: "character varying(4)", maxLength: 4, nullable: true), - PhoneNumber = table.Column(type: "character varying(15)", maxLength: 15, nullable: true), - Industry = table.Column(type: "character varying(100)", maxLength: 100, nullable: true), - About = table.Column(type: "character varying(1000)", maxLength: 1000, nullable: true), - ServiceType = table.Column(type: "integer", nullable: true), - Location = table.Column(type: "character varying(255)", maxLength: 255, nullable: true), - Longitude = table.Column(type: "character varying(10)", maxLength: 10, nullable: true), - Latitude = table.Column(type: "character varying(10)", maxLength: 10, nullable: true), - CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), - UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false), - UpdatedBy = table.Column(type: "text", nullable: true), - RecordStatus = table.Column(type: "integer", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_businesses", x => x.Id); - table.ForeignKey( - name: "FK_businesses_users_UserId", - column: x => x.UserId, - principalTable: "users", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "BusinessAvailabilities", - columns: table => new - { - Id = table.Column(type: "uuid", nullable: false), - BusinessId = table.Column(type: "uuid", nullable: false), - StartDate = table.Column(type: "date", nullable: false), - EndDate = table.Column(type: "date", nullable: false), - ValidFrom = table.Column(type: "date", nullable: true), - ValidTo = table.Column(type: "date", nullable: true), - CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), - UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false), - UpdatedBy = table.Column(type: "text", nullable: true), - RecordStatus = table.Column(type: "integer", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_BusinessAvailabilities", x => x.Id); - table.ForeignKey( - name: "FK_BusinessAvailabilities_businesses_BusinessId", - column: x => x.BusinessId, - principalTable: "businesses", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "BusinessAvailabilitySlots", - columns: table => new - { - Id = table.Column(type: "uuid", nullable: false), - BusinessAvailabilityId = table.Column(type: "uuid", nullable: false), - BusinessAvailabilityId1 = table.Column(type: "uuid", nullable: true), - StartTime = table.Column(type: "time without time zone", nullable: false), - EndTime = table.Column(type: "time without time zone", nullable: false), - DayOfWeek = table.Column(type: "integer", nullable: false), - Breaks = table.Column>(type: "time without time zone[]", nullable: true), - CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), - UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false), - UpdatedBy = table.Column(type: "text", nullable: true), - RecordStatus = table.Column(type: "integer", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_BusinessAvailabilitySlots", x => x.Id); - table.ForeignKey( - name: "FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessAv~", - column: x => x.BusinessAvailabilityId, - principalTable: "BusinessAvailabilities", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessA~1", - column: x => x.BusinessAvailabilityId1, - principalTable: "BusinessAvailabilities", - principalColumn: "Id"); - }); - - migrationBuilder.CreateIndex( - name: "IX_BusinessAvailabilities_BusinessId", - table: "BusinessAvailabilities", - column: "BusinessId"); - - migrationBuilder.CreateIndex( - name: "IX_BusinessAvailabilitySlots_BusinessAvailabilityId", - table: "BusinessAvailabilitySlots", - column: "BusinessAvailabilityId"); - - migrationBuilder.CreateIndex( - name: "IX_BusinessAvailabilitySlots_BusinessAvailabilityId1", - table: "BusinessAvailabilitySlots", - column: "BusinessAvailabilityId1"); - - migrationBuilder.CreateIndex( - name: "IX_businesses_UserId", - table: "businesses", - column: "UserId"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "BusinessAvailabilitySlots"); - - migrationBuilder.DropTable( - name: "BusinessAvailabilities"); - - migrationBuilder.DropTable( - name: "businesses"); - - migrationBuilder.DropTable( - name: "users"); - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250715221843_AddedNameToAppTheme.Designer.cs b/src/ProjectR.Backend.Persistence/Migrations/20250715221843_AddedNameToAppTheme.Designer.cs deleted file mode 100644 index a0eb7c1..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250715221843_AddedNameToAppTheme.Designer.cs +++ /dev/null @@ -1,285 +0,0 @@ -// -using System; -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; -using ProjectR.Backend.Persistence.DatabaseContext; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - [DbContext(typeof(AppDbContext))] - [Migration("20250715221843_AddedNameToAppTheme")] - partial class AddedNameToAppTheme - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.7") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.AppTheme", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Name") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("AppThemes"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("About") - .HasMaxLength(1000) - .HasColumnType("character varying(1000)"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Industry") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("Latitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Location") - .HasMaxLength(255) - .HasColumnType("character varying(255)"); - - b.Property("Longitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Name") - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("PhoneCode") - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .HasMaxLength(15) - .HasColumnType("character varying(15)"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("ServiceType") - .HasColumnType("integer"); - - b.Property("Type") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("businesses", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("BusinessId") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EndDate") - .HasColumnType("date"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartDate") - .HasColumnType("date"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.Property("ValidFrom") - .HasColumnType("date"); - - b.Property("ValidTo") - .HasColumnType("date"); - - b.HasKey("Id"); - - b.HasIndex("BusinessId"); - - b.ToTable("BusinessAvailabilities"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.PrimitiveCollection>("Breaks") - .HasColumnType("time without time zone[]"); - - b.Property("BusinessAvailabilityId") - .HasColumnType("uuid"); - - b.Property("BusinessAvailabilityId1") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DayOfWeek") - .HasColumnType("integer"); - - b.Property("EndTime") - .HasColumnType("time without time zone"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartTime") - .HasColumnType("time without time zone"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("BusinessAvailabilityId"); - - b.HasIndex("BusinessAvailabilityId1"); - - b.ToTable("BusinessAvailabilitySlots"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("AccountType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Email") - .HasColumnType("text"); - - b.Property("PhoneCode") - .IsRequired() - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .IsRequired() - .HasColumnType("text"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("RegistrationType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("users", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.Business", "Business") - .WithMany() - .HasForeignKey("BusinessId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Business"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", null) - .WithMany("Slots") - .HasForeignKey("BusinessAvailabilityId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", "BusinessAvailability") - .WithMany() - .HasForeignKey("BusinessAvailabilityId1") - .HasConstraintName("FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessA~1"); - - b.Navigation("BusinessAvailability"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Navigation("Slots"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250715221843_AddedNameToAppTheme.cs b/src/ProjectR.Backend.Persistence/Migrations/20250715221843_AddedNameToAppTheme.cs deleted file mode 100644 index b695934..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250715221843_AddedNameToAppTheme.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - /// - public partial class AddedNameToAppTheme : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "AppThemes", - columns: table => new - { - Id = table.Column(type: "uuid", nullable: false), - Name = table.Column(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AppThemes", x => x.Id); - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "AppThemes"); - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250721134000_AddedURLandShortLinkToBusinessTable.Designer.cs b/src/ProjectR.Backend.Persistence/Migrations/20250721134000_AddedURLandShortLinkToBusinessTable.Designer.cs deleted file mode 100644 index c2b3cda..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250721134000_AddedURLandShortLinkToBusinessTable.Designer.cs +++ /dev/null @@ -1,291 +0,0 @@ -// -using System; -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; -using ProjectR.Backend.Persistence.DatabaseContext; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - [DbContext(typeof(AppDbContext))] - [Migration("20250721134000_AddedURLandShortLinkToBusinessTable")] - partial class AddedURLandShortLinkToBusinessTable - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.7") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.AppTheme", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Name") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("AppThemes"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("About") - .HasMaxLength(1000) - .HasColumnType("character varying(1000)"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Industry") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("Latitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Location") - .HasMaxLength(255) - .HasColumnType("character varying(255)"); - - b.Property("Logo") - .HasColumnType("text"); - - b.Property("Longitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Name") - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("PhoneCode") - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .HasMaxLength(15) - .HasColumnType("character varying(15)"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("ServiceType") - .HasColumnType("integer"); - - b.Property("ShortLink") - .HasColumnType("text"); - - b.Property("Type") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("businesses", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("BusinessId") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EndDate") - .HasColumnType("date"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartDate") - .HasColumnType("date"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.Property("ValidFrom") - .HasColumnType("date"); - - b.Property("ValidTo") - .HasColumnType("date"); - - b.HasKey("Id"); - - b.HasIndex("BusinessId"); - - b.ToTable("BusinessAvailabilities"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.PrimitiveCollection>("Breaks") - .HasColumnType("time without time zone[]"); - - b.Property("BusinessAvailabilityId") - .HasColumnType("uuid"); - - b.Property("BusinessAvailabilityId1") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DayOfWeek") - .HasColumnType("integer"); - - b.Property("EndTime") - .HasColumnType("time without time zone"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartTime") - .HasColumnType("time without time zone"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("BusinessAvailabilityId"); - - b.HasIndex("BusinessAvailabilityId1"); - - b.ToTable("BusinessAvailabilitySlots"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("AccountType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Email") - .HasColumnType("text"); - - b.Property("PhoneCode") - .IsRequired() - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .IsRequired() - .HasColumnType("text"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("RegistrationType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("users", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.Business", "Business") - .WithMany() - .HasForeignKey("BusinessId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Business"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", null) - .WithMany("Slots") - .HasForeignKey("BusinessAvailabilityId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", "BusinessAvailability") - .WithMany() - .HasForeignKey("BusinessAvailabilityId1") - .HasConstraintName("FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessA~1"); - - b.Navigation("BusinessAvailability"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Navigation("Slots"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250721134000_AddedURLandShortLinkToBusinessTable.cs b/src/ProjectR.Backend.Persistence/Migrations/20250721134000_AddedURLandShortLinkToBusinessTable.cs deleted file mode 100644 index 6011c99..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250721134000_AddedURLandShortLinkToBusinessTable.cs +++ /dev/null @@ -1,38 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - /// - public partial class AddedURLandShortLinkToBusinessTable : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "Logo", - table: "businesses", - type: "text", - nullable: true); - - migrationBuilder.AddColumn( - name: "ShortLink", - table: "businesses", - type: "text", - nullable: true); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "Logo", - table: "businesses"); - - migrationBuilder.DropColumn( - name: "ShortLink", - table: "businesses"); - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250730144416_AddedOtpTable.Designer.cs b/src/ProjectR.Backend.Persistence/Migrations/20250730144416_AddedOtpTable.Designer.cs deleted file mode 100644 index 50be6f8..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250730144416_AddedOtpTable.Designer.cs +++ /dev/null @@ -1,335 +0,0 @@ -// -using System; -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; -using ProjectR.Backend.Persistence.DatabaseContext; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - [DbContext(typeof(AppDbContext))] - [Migration("20250730144416_AddedOtpTable")] - partial class AddedOtpTable - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.7") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.AppTheme", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Name") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("AppThemes"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("About") - .HasMaxLength(1000) - .HasColumnType("character varying(1000)"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Industry") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("Latitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Location") - .HasMaxLength(255) - .HasColumnType("character varying(255)"); - - b.Property("Logo") - .HasColumnType("text"); - - b.Property("Longitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Name") - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("PhoneCode") - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .HasMaxLength(15) - .HasColumnType("character varying(15)"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("ServiceType") - .HasColumnType("integer"); - - b.Property("ShortLink") - .HasColumnType("text"); - - b.Property("Type") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("businesses", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("BusinessId") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EndDate") - .HasColumnType("date"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartDate") - .HasColumnType("date"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.Property("ValidFrom") - .HasColumnType("date"); - - b.Property("ValidTo") - .HasColumnType("date"); - - b.HasKey("Id"); - - b.HasIndex("BusinessId"); - - b.ToTable("BusinessAvailabilities"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.PrimitiveCollection>("Breaks") - .HasColumnType("time without time zone[]"); - - b.Property("BusinessAvailabilityId") - .HasColumnType("uuid"); - - b.Property("BusinessAvailabilityId1") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DayOfWeek") - .HasColumnType("integer"); - - b.Property("EndTime") - .HasColumnType("time without time zone"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartTime") - .HasColumnType("time without time zone"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("BusinessAvailabilityId"); - - b.HasIndex("BusinessAvailabilityId1"); - - b.ToTable("BusinessAvailabilitySlots"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Otp", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Code") - .HasColumnType("text"); - - b.Property("CountryCode") - .HasColumnType("text"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DeliveryMode") - .HasColumnType("integer"); - - b.Property("Email") - .HasColumnType("text"); - - b.Property("ExpiryDate") - .HasColumnType("timestamp with time zone"); - - b.Property("OtpType") - .HasColumnType("integer"); - - b.Property("PhoneNumber") - .HasColumnType("text"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("Otps"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("AccountType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Email") - .HasColumnType("text"); - - b.Property("PhoneCode") - .IsRequired() - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .IsRequired() - .HasColumnType("text"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("RegistrationType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("users", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.Business", "Business") - .WithMany() - .HasForeignKey("BusinessId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Business"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", null) - .WithMany("Slots") - .HasForeignKey("BusinessAvailabilityId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", "BusinessAvailability") - .WithMany() - .HasForeignKey("BusinessAvailabilityId1") - .HasConstraintName("FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessA~1"); - - b.Navigation("BusinessAvailability"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Navigation("Slots"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250730144416_AddedOtpTable.cs b/src/ProjectR.Backend.Persistence/Migrations/20250730144416_AddedOtpTable.cs deleted file mode 100644 index 5140bac..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250730144416_AddedOtpTable.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - /// - public partial class AddedOtpTable : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "Otps", - columns: table => new - { - Id = table.Column(type: "uuid", nullable: false), - PhoneNumber = table.Column(type: "text", nullable: true), - CountryCode = table.Column(type: "text", nullable: true), - Email = table.Column(type: "text", nullable: true), - Code = table.Column(type: "text", nullable: true), - ExpiryDate = table.Column(type: "timestamp with time zone", nullable: false), - OtpType = table.Column(type: "integer", nullable: false), - DeliveryMode = table.Column(type: "integer", nullable: false), - CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), - UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false), - UpdatedBy = table.Column(type: "text", nullable: true), - RecordStatus = table.Column(type: "integer", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Otps", x => x.Id); - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "Otps"); - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250809114128_AddedWebhookMessageTable.cs b/src/ProjectR.Backend.Persistence/Migrations/20250809114128_AddedWebhookMessageTable.cs deleted file mode 100644 index b3c4efd..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250809114128_AddedWebhookMessageTable.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - /// - public partial class AddedWebhookMessageTable : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "WebhookMessages", - columns: table => new - { - Id = table.Column(type: "uuid", nullable: false), - Source = table.Column(type: "integer", nullable: false), - Payload = table.Column(type: "text", nullable: true), - IsProcessed = table.Column(type: "boolean", nullable: false), - LastProcessedDate = table.Column(type: "timestamp with time zone", nullable: true), - LastProcessedResult = table.Column(type: "text", nullable: true), - CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), - UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false), - UpdatedBy = table.Column(type: "text", nullable: true), - RecordStatus = table.Column(type: "integer", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_WebhookMessages", x => x.Id); - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "WebhookMessages"); - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250818204545_AddedIndustryTable.Designer.cs b/src/ProjectR.Backend.Persistence/Migrations/20250818204545_AddedIndustryTable.Designer.cs deleted file mode 100644 index cc15775..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250818204545_AddedIndustryTable.Designer.cs +++ /dev/null @@ -1,355 +0,0 @@ -// -using System; -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; -using ProjectR.Backend.Persistence.DatabaseContext; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - [DbContext(typeof(AppDbContext))] - [Migration("20250818204545_AddedIndustryTable")] - partial class AddedIndustryTable - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.7") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.AppTheme", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Name") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("AppThemes"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("About") - .HasMaxLength(1000) - .HasColumnType("character varying(1000)"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Industry") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("Latitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Location") - .HasMaxLength(255) - .HasColumnType("character varying(255)"); - - b.Property("Logo") - .HasColumnType("text"); - - b.Property("Longitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Name") - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("PhoneCode") - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .HasMaxLength(15) - .HasColumnType("character varying(15)"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("ServiceType") - .HasColumnType("integer"); - - b.Property("ShortLink") - .HasColumnType("text"); - - b.Property("Type") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("businesses", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("BusinessId") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EndDate") - .HasColumnType("date"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartDate") - .HasColumnType("date"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.Property("ValidFrom") - .HasColumnType("date"); - - b.Property("ValidTo") - .HasColumnType("date"); - - b.HasKey("Id"); - - b.HasIndex("BusinessId"); - - b.ToTable("BusinessAvailabilities"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.PrimitiveCollection>("Breaks") - .HasColumnType("time without time zone[]"); - - b.Property("BusinessAvailabilityId") - .HasColumnType("uuid"); - - b.Property("BusinessAvailabilityId1") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DayOfWeek") - .HasColumnType("integer"); - - b.Property("EndTime") - .HasColumnType("time without time zone"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartTime") - .HasColumnType("time without time zone"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("BusinessAvailabilityId"); - - b.HasIndex("BusinessAvailabilityId1"); - - b.ToTable("BusinessAvailabilitySlots"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Industry", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Description") - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.HasKey("Id"); - - b.ToTable("Industries"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Otp", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Code") - .HasColumnType("text"); - - b.Property("CountryCode") - .HasColumnType("text"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DeliveryMode") - .HasColumnType("integer"); - - b.Property("Email") - .HasColumnType("text"); - - b.Property("ExpiryDate") - .HasColumnType("timestamp with time zone"); - - b.Property("OtpType") - .HasColumnType("integer"); - - b.Property("PhoneNumber") - .HasColumnType("text"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("Otps"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("AccountType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Email") - .HasColumnType("text"); - - b.Property("PhoneCode") - .IsRequired() - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .IsRequired() - .HasColumnType("text"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("RegistrationType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("users", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.Business", "Business") - .WithMany() - .HasForeignKey("BusinessId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Business"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", null) - .WithMany("Slots") - .HasForeignKey("BusinessAvailabilityId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", "BusinessAvailability") - .WithMany() - .HasForeignKey("BusinessAvailabilityId1") - .HasConstraintName("FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessA~1"); - - b.Navigation("BusinessAvailability"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Navigation("Slots"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250818204545_AddedIndustryTable.cs b/src/ProjectR.Backend.Persistence/Migrations/20250818204545_AddedIndustryTable.cs deleted file mode 100644 index 7ad2d57..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250818204545_AddedIndustryTable.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - /// - public partial class AddedIndustryTable : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "Industries", - columns: table => new - { - Id = table.Column(type: "uuid", nullable: false), - Name = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), - Description = table.Column(type: "character varying(500)", maxLength: 500, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Industries", x => x.Id); - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "Industries"); - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250819082107_AddIndustryDescription.Designer.cs b/src/ProjectR.Backend.Persistence/Migrations/20250819082107_AddIndustryDescription.Designer.cs deleted file mode 100644 index e2b96cb..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250819082107_AddIndustryDescription.Designer.cs +++ /dev/null @@ -1,355 +0,0 @@ -// -using System; -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; -using ProjectR.Backend.Persistence.DatabaseContext; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - [DbContext(typeof(AppDbContext))] - [Migration("20250819082107_AddIndustryDescription")] - partial class AddIndustryDescription - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.7") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.AppTheme", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Name") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("AppThemes"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("About") - .HasMaxLength(1000) - .HasColumnType("character varying(1000)"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Industry") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("Latitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Location") - .HasMaxLength(255) - .HasColumnType("character varying(255)"); - - b.Property("Logo") - .HasColumnType("text"); - - b.Property("Longitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Name") - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("PhoneCode") - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .HasMaxLength(15) - .HasColumnType("character varying(15)"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("ServiceType") - .HasColumnType("integer"); - - b.Property("ShortLink") - .HasColumnType("text"); - - b.Property("Type") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("businesses", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("BusinessId") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EndDate") - .HasColumnType("date"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartDate") - .HasColumnType("date"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.Property("ValidFrom") - .HasColumnType("date"); - - b.Property("ValidTo") - .HasColumnType("date"); - - b.HasKey("Id"); - - b.HasIndex("BusinessId"); - - b.ToTable("BusinessAvailabilities"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.PrimitiveCollection>("Breaks") - .HasColumnType("time without time zone[]"); - - b.Property("BusinessAvailabilityId") - .HasColumnType("uuid"); - - b.Property("BusinessAvailabilityId1") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DayOfWeek") - .HasColumnType("integer"); - - b.Property("EndTime") - .HasColumnType("time without time zone"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartTime") - .HasColumnType("time without time zone"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("BusinessAvailabilityId"); - - b.HasIndex("BusinessAvailabilityId1"); - - b.ToTable("BusinessAvailabilitySlots"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Industry", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Description") - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.HasKey("Id"); - - b.ToTable("Industries"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Otp", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Code") - .HasColumnType("text"); - - b.Property("CountryCode") - .HasColumnType("text"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DeliveryMode") - .HasColumnType("integer"); - - b.Property("Email") - .HasColumnType("text"); - - b.Property("ExpiryDate") - .HasColumnType("timestamp with time zone"); - - b.Property("OtpType") - .HasColumnType("integer"); - - b.Property("PhoneNumber") - .HasColumnType("text"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("Otps"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("AccountType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Email") - .HasColumnType("text"); - - b.Property("PhoneCode") - .IsRequired() - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .IsRequired() - .HasColumnType("text"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("RegistrationType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("users", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.Business", "Business") - .WithMany() - .HasForeignKey("BusinessId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Business"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", null) - .WithMany("Slots") - .HasForeignKey("BusinessAvailabilityId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", "BusinessAvailability") - .WithMany() - .HasForeignKey("BusinessAvailabilityId1") - .HasConstraintName("FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessA~1"); - - b.Navigation("BusinessAvailability"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Navigation("Slots"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250819082107_AddIndustryDescription.cs b/src/ProjectR.Backend.Persistence/Migrations/20250819082107_AddIndustryDescription.cs deleted file mode 100644 index a89389f..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250819082107_AddIndustryDescription.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - /// - public partial class AddIndustryDescription : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250809114128_AddedWebhookMessageTable.Designer.cs b/src/ProjectR.Backend.Persistence/Migrations/20250930210149_Initial.Designer.cs similarity index 54% rename from src/ProjectR.Backend.Persistence/Migrations/20250809114128_AddedWebhookMessageTable.Designer.cs rename to src/ProjectR.Backend.Persistence/Migrations/20250930210149_Initial.Designer.cs index 5981fcb..326c0c7 100644 --- a/src/ProjectR.Backend.Persistence/Migrations/20250809114128_AddedWebhookMessageTable.Designer.cs +++ b/src/ProjectR.Backend.Persistence/Migrations/20250930210149_Initial.Designer.cs @@ -1,11 +1,10 @@ // using System; -using System.Collections.Generic; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; using ProjectR.Backend.Persistence.DatabaseContext; #nullable disable @@ -13,98 +12,132 @@ namespace ProjectR.Backend.Persistence.Migrations { [DbContext(typeof(AppDbContext))] - [Migration("20250809114128_AddedWebhookMessageTable")] - partial class AddedWebhookMessageTable + [Migration("20250930210149_Initial")] + partial class Initial { /// protected override void BuildTargetModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "9.0.7") - .HasAnnotation("Relational:MaxIdentifierLength", 63); + .HasAnnotation("ProductVersion", "9.0.9") + .HasAnnotation("Relational:MaxIdentifierLength", 128); - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); modelBuilder.Entity("ProjectR.Backend.Domain.Entities.AppTheme", b => { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("Name") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.HasKey("Id"); b.ToTable("AppThemes"); }); + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Break", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("BusinessAvailabilitySlotId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetimeoffset"); + + b.Property("EndTime") + .HasColumnType("datetimeoffset"); + + b.Property("RecordStatus") + .HasColumnType("int"); + + b.Property("StartTime") + .HasColumnType("datetimeoffset"); + + b.Property("UpdatedAt") + .HasColumnType("datetimeoffset"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("BusinessAvailabilitySlotId"); + + b.ToTable("Breaks"); + }); + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("About") .HasMaxLength(1000) - .HasColumnType("character varying(1000)"); + .HasColumnType("nvarchar(1000)"); b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("Industry") .HasMaxLength(100) - .HasColumnType("character varying(100)"); + .HasColumnType("nvarchar(100)"); b.Property("Latitude") .HasMaxLength(10) - .HasColumnType("character varying(10)"); + .HasColumnType("nvarchar(10)"); b.Property("Location") .HasMaxLength(255) - .HasColumnType("character varying(255)"); + .HasColumnType("nvarchar(255)"); b.Property("Logo") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("Longitude") .HasMaxLength(10) - .HasColumnType("character varying(10)"); + .HasColumnType("nvarchar(10)"); b.Property("Name") .HasMaxLength(200) - .HasColumnType("character varying(200)"); + .HasColumnType("nvarchar(200)"); b.Property("PhoneCode") .HasMaxLength(4) - .HasColumnType("character varying(4)"); + .HasColumnType("nvarchar(4)"); b.Property("PhoneNumber") .HasMaxLength(15) - .HasColumnType("character varying(15)"); + .HasColumnType("nvarchar(15)"); b.Property("RecordStatus") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("ServiceType") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("ShortLink") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("Type") .HasMaxLength(100) - .HasColumnType("character varying(100)"); + .HasColumnType("nvarchar(100)"); b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("UpdatedBy") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("UserId") - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.HasKey("Id"); @@ -117,34 +150,28 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("BusinessId") - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); - b.Property("EndDate") - .HasColumnType("date"); + b.Property("EndDate") + .HasColumnType("datetimeoffset"); b.Property("RecordStatus") - .HasColumnType("integer"); + .HasColumnType("int"); - b.Property("StartDate") - .HasColumnType("date"); + b.Property("StartDate") + .HasColumnType("datetimeoffset"); b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("UpdatedBy") - .HasColumnType("text"); - - b.Property("ValidFrom") - .HasColumnType("date"); - - b.Property("ValidTo") - .HasColumnType("date"); + .HasColumnType("nvarchar(max)"); b.HasKey("Id"); @@ -157,85 +184,100 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.PrimitiveCollection>("Breaks") - .HasColumnType("time without time zone[]"); + .HasColumnType("uniqueidentifier"); b.Property("BusinessAvailabilityId") - .HasColumnType("uuid"); - - b.Property("BusinessAvailabilityId1") - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); + + b.Property("Date") + .HasColumnType("datetimeoffset"); b.Property("DayOfWeek") - .HasColumnType("integer"); + .HasColumnType("int"); - b.Property("EndTime") - .HasColumnType("time without time zone"); + b.Property("EndTime") + .HasColumnType("datetimeoffset"); b.Property("RecordStatus") - .HasColumnType("integer"); + .HasColumnType("int"); - b.Property("StartTime") - .HasColumnType("time without time zone"); + b.Property("StartTime") + .HasColumnType("datetimeoffset"); b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("UpdatedBy") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.HasKey("Id"); b.HasIndex("BusinessAvailabilityId"); - b.HasIndex("BusinessAvailabilityId1"); - b.ToTable("BusinessAvailabilitySlots"); }); + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Industry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Description") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("Id"); + + b.ToTable("Industries"); + }); + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Otp", b => { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("Code") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("CountryCode") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("DeliveryMode") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("Email") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("ExpiryDate") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("OtpType") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("PhoneNumber") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("RecordStatus") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("UpdatedBy") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.HasKey("Id"); @@ -246,41 +288,41 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("AccountType") .ValueGeneratedOnAdd() - .HasColumnType("integer") + .HasColumnType("int") .HasDefaultValue(1); b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("Email") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("PhoneCode") .IsRequired() .HasMaxLength(4) - .HasColumnType("character varying(4)"); + .HasColumnType("nvarchar(4)"); b.Property("PhoneNumber") .IsRequired() - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("RecordStatus") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("RegistrationType") .ValueGeneratedOnAdd() - .HasColumnType("integer") + .HasColumnType("int") .HasDefaultValue(1); b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("UpdatedBy") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.HasKey("Id"); @@ -291,40 +333,51 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("IsProcessed") - .HasColumnType("boolean"); + .HasColumnType("bit"); b.Property("LastProcessedDate") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("LastProcessedResult") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("Payload") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("RecordStatus") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("Source") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("UpdatedBy") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.HasKey("Id"); b.ToTable("WebhookMessages"); }); + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Break", b => + { + b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", "BusinessAvailabilitySlot") + .WithMany("Breaks") + .HasForeignKey("BusinessAvailabilitySlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("BusinessAvailabilitySlot"); + }); + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => { b.HasOne("ProjectR.Backend.Domain.Entities.User", "User") @@ -349,17 +402,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => { - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", null) + b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", "BusinessAvailability") .WithMany("Slots") .HasForeignKey("BusinessAvailabilityId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", "BusinessAvailability") - .WithMany() - .HasForeignKey("BusinessAvailabilityId1") - .HasConstraintName("FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessA~1"); - b.Navigation("BusinessAvailability"); }); @@ -367,6 +415,11 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) { b.Navigation("Slots"); }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => + { + b.Navigation("Breaks"); + }); #pragma warning restore 612, 618 } } diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250930210149_Initial.cs b/src/ProjectR.Backend.Persistence/Migrations/20250930210149_Initial.cs new file mode 100644 index 0000000..1411a84 --- /dev/null +++ b/src/ProjectR.Backend.Persistence/Migrations/20250930210149_Initial.cs @@ -0,0 +1,261 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace ProjectR.Backend.Persistence.Migrations +{ + /// + public partial class Initial : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AppThemes", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AppThemes", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Industries", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: false), + Description = table.Column(type: "nvarchar(500)", maxLength: 500, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Industries", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Otps", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + PhoneNumber = table.Column(type: "nvarchar(max)", nullable: true), + CountryCode = table.Column(type: "nvarchar(max)", nullable: true), + Email = table.Column(type: "nvarchar(max)", nullable: true), + Code = table.Column(type: "nvarchar(max)", nullable: true), + ExpiryDate = table.Column(type: "datetimeoffset", nullable: false), + OtpType = table.Column(type: "int", nullable: false), + DeliveryMode = table.Column(type: "int", nullable: false), + CreatedAt = table.Column(type: "datetimeoffset", nullable: false), + UpdatedAt = table.Column(type: "datetimeoffset", nullable: false), + UpdatedBy = table.Column(type: "nvarchar(max)", nullable: true), + RecordStatus = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Otps", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "users", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + PhoneNumber = table.Column(type: "nvarchar(max)", nullable: false), + PhoneCode = table.Column(type: "nvarchar(4)", maxLength: 4, nullable: false), + Email = table.Column(type: "nvarchar(max)", nullable: true), + AccountType = table.Column(type: "int", nullable: false, defaultValue: 1), + RegistrationType = table.Column(type: "int", nullable: false, defaultValue: 1), + CreatedAt = table.Column(type: "datetimeoffset", nullable: false), + UpdatedAt = table.Column(type: "datetimeoffset", nullable: false), + UpdatedBy = table.Column(type: "nvarchar(max)", nullable: true), + RecordStatus = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_users", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "WebhookMessages", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Source = table.Column(type: "int", nullable: false), + Payload = table.Column(type: "nvarchar(max)", nullable: true), + IsProcessed = table.Column(type: "bit", nullable: false), + LastProcessedDate = table.Column(type: "datetimeoffset", nullable: true), + LastProcessedResult = table.Column(type: "nvarchar(max)", nullable: true), + CreatedAt = table.Column(type: "datetimeoffset", nullable: false), + UpdatedAt = table.Column(type: "datetimeoffset", nullable: false), + UpdatedBy = table.Column(type: "nvarchar(max)", nullable: true), + RecordStatus = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_WebhookMessages", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "businesses", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + UserId = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: true), + Type = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: true), + PhoneCode = table.Column(type: "nvarchar(4)", maxLength: 4, nullable: true), + PhoneNumber = table.Column(type: "nvarchar(15)", maxLength: 15, nullable: true), + Industry = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: true), + About = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true), + ServiceType = table.Column(type: "int", nullable: true), + Location = table.Column(type: "nvarchar(255)", maxLength: 255, nullable: true), + Longitude = table.Column(type: "nvarchar(10)", maxLength: 10, nullable: true), + Latitude = table.Column(type: "nvarchar(10)", maxLength: 10, nullable: true), + Logo = table.Column(type: "nvarchar(max)", nullable: true), + ShortLink = table.Column(type: "nvarchar(max)", nullable: true), + CreatedAt = table.Column(type: "datetimeoffset", nullable: false), + UpdatedAt = table.Column(type: "datetimeoffset", nullable: false), + UpdatedBy = table.Column(type: "nvarchar(max)", nullable: true), + RecordStatus = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_businesses", x => x.Id); + table.ForeignKey( + name: "FK_businesses_users_UserId", + column: x => x.UserId, + principalTable: "users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "BusinessAvailabilities", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + BusinessId = table.Column(type: "uniqueidentifier", nullable: false), + StartDate = table.Column(type: "datetimeoffset", nullable: false), + EndDate = table.Column(type: "datetimeoffset", nullable: false), + CreatedAt = table.Column(type: "datetimeoffset", nullable: false), + UpdatedAt = table.Column(type: "datetimeoffset", nullable: false), + UpdatedBy = table.Column(type: "nvarchar(max)", nullable: true), + RecordStatus = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_BusinessAvailabilities", x => x.Id); + table.ForeignKey( + name: "FK_BusinessAvailabilities_businesses_BusinessId", + column: x => x.BusinessId, + principalTable: "businesses", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "BusinessAvailabilitySlots", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + BusinessAvailabilityId = table.Column(type: "uniqueidentifier", nullable: false), + StartTime = table.Column(type: "datetimeoffset", nullable: false), + EndTime = table.Column(type: "datetimeoffset", nullable: false), + DayOfWeek = table.Column(type: "int", nullable: false), + Date = table.Column(type: "datetimeoffset", nullable: false), + CreatedAt = table.Column(type: "datetimeoffset", nullable: false), + UpdatedAt = table.Column(type: "datetimeoffset", nullable: false), + UpdatedBy = table.Column(type: "nvarchar(max)", nullable: true), + RecordStatus = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_BusinessAvailabilitySlots", x => x.Id); + table.ForeignKey( + name: "FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessAvailabilityId", + column: x => x.BusinessAvailabilityId, + principalTable: "BusinessAvailabilities", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Breaks", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + BusinessAvailabilitySlotId = table.Column(type: "uniqueidentifier", nullable: false), + StartTime = table.Column(type: "datetimeoffset", nullable: false), + EndTime = table.Column(type: "datetimeoffset", nullable: false), + CreatedAt = table.Column(type: "datetimeoffset", nullable: false), + UpdatedAt = table.Column(type: "datetimeoffset", nullable: false), + UpdatedBy = table.Column(type: "nvarchar(max)", nullable: true), + RecordStatus = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Breaks", x => x.Id); + table.ForeignKey( + name: "FK_Breaks_BusinessAvailabilitySlots_BusinessAvailabilitySlotId", + column: x => x.BusinessAvailabilitySlotId, + principalTable: "BusinessAvailabilitySlots", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_Breaks_BusinessAvailabilitySlotId", + table: "Breaks", + column: "BusinessAvailabilitySlotId"); + + migrationBuilder.CreateIndex( + name: "IX_BusinessAvailabilities_BusinessId", + table: "BusinessAvailabilities", + column: "BusinessId"); + + migrationBuilder.CreateIndex( + name: "IX_BusinessAvailabilitySlots_BusinessAvailabilityId", + table: "BusinessAvailabilitySlots", + column: "BusinessAvailabilityId"); + + migrationBuilder.CreateIndex( + name: "IX_businesses_UserId", + table: "businesses", + column: "UserId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AppThemes"); + + migrationBuilder.DropTable( + name: "Breaks"); + + migrationBuilder.DropTable( + name: "Industries"); + + migrationBuilder.DropTable( + name: "Otps"); + + migrationBuilder.DropTable( + name: "WebhookMessages"); + + migrationBuilder.DropTable( + name: "BusinessAvailabilitySlots"); + + migrationBuilder.DropTable( + name: "BusinessAvailabilities"); + + migrationBuilder.DropTable( + name: "businesses"); + + migrationBuilder.DropTable( + name: "users"); + } + } +} diff --git a/src/ProjectR.Backend.Persistence/Migrations/AppDbContextModelSnapshot.cs b/src/ProjectR.Backend.Persistence/Migrations/AppDbContextModelSnapshot.cs index c3b05c1..c3a72b7 100644 --- a/src/ProjectR.Backend.Persistence/Migrations/AppDbContextModelSnapshot.cs +++ b/src/ProjectR.Backend.Persistence/Migrations/AppDbContextModelSnapshot.cs @@ -1,10 +1,9 @@ // using System; -using System.Collections.Generic; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; using ProjectR.Backend.Persistence.DatabaseContext; #nullable disable @@ -18,90 +17,124 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "9.0.7") - .HasAnnotation("Relational:MaxIdentifierLength", 63); + .HasAnnotation("ProductVersion", "9.0.9") + .HasAnnotation("Relational:MaxIdentifierLength", 128); - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); modelBuilder.Entity("ProjectR.Backend.Domain.Entities.AppTheme", b => { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("Name") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.HasKey("Id"); b.ToTable("AppThemes"); }); + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Break", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("BusinessAvailabilitySlotId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetimeoffset"); + + b.Property("EndTime") + .HasColumnType("datetimeoffset"); + + b.Property("RecordStatus") + .HasColumnType("int"); + + b.Property("StartTime") + .HasColumnType("datetimeoffset"); + + b.Property("UpdatedAt") + .HasColumnType("datetimeoffset"); + + b.Property("UpdatedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("BusinessAvailabilitySlotId"); + + b.ToTable("Breaks"); + }); + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("About") .HasMaxLength(1000) - .HasColumnType("character varying(1000)"); + .HasColumnType("nvarchar(1000)"); b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("Industry") .HasMaxLength(100) - .HasColumnType("character varying(100)"); + .HasColumnType("nvarchar(100)"); b.Property("Latitude") .HasMaxLength(10) - .HasColumnType("character varying(10)"); + .HasColumnType("nvarchar(10)"); b.Property("Location") .HasMaxLength(255) - .HasColumnType("character varying(255)"); + .HasColumnType("nvarchar(255)"); b.Property("Logo") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("Longitude") .HasMaxLength(10) - .HasColumnType("character varying(10)"); + .HasColumnType("nvarchar(10)"); b.Property("Name") .HasMaxLength(200) - .HasColumnType("character varying(200)"); + .HasColumnType("nvarchar(200)"); b.Property("PhoneCode") .HasMaxLength(4) - .HasColumnType("character varying(4)"); + .HasColumnType("nvarchar(4)"); b.Property("PhoneNumber") .HasMaxLength(15) - .HasColumnType("character varying(15)"); + .HasColumnType("nvarchar(15)"); b.Property("RecordStatus") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("ServiceType") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("ShortLink") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("Type") .HasMaxLength(100) - .HasColumnType("character varying(100)"); + .HasColumnType("nvarchar(100)"); b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("UpdatedBy") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("UserId") - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.HasKey("Id"); @@ -114,34 +147,28 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("BusinessId") - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); - b.Property("EndDate") - .HasColumnType("date"); + b.Property("EndDate") + .HasColumnType("datetimeoffset"); b.Property("RecordStatus") - .HasColumnType("integer"); + .HasColumnType("int"); - b.Property("StartDate") - .HasColumnType("date"); + b.Property("StartDate") + .HasColumnType("datetimeoffset"); b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("UpdatedBy") - .HasColumnType("text"); - - b.Property("ValidFrom") - .HasColumnType("date"); - - b.Property("ValidTo") - .HasColumnType("date"); + .HasColumnType("nvarchar(max)"); b.HasKey("Id"); @@ -154,44 +181,39 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.PrimitiveCollection>("Breaks") - .HasColumnType("time without time zone[]"); + .HasColumnType("uniqueidentifier"); b.Property("BusinessAvailabilityId") - .HasColumnType("uuid"); - - b.Property("BusinessAvailabilityId1") - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); + + b.Property("Date") + .HasColumnType("datetimeoffset"); b.Property("DayOfWeek") - .HasColumnType("integer"); + .HasColumnType("int"); - b.Property("EndTime") - .HasColumnType("time without time zone"); + b.Property("EndTime") + .HasColumnType("datetimeoffset"); b.Property("RecordStatus") - .HasColumnType("integer"); + .HasColumnType("int"); - b.Property("StartTime") - .HasColumnType("time without time zone"); + b.Property("StartTime") + .HasColumnType("datetimeoffset"); b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("UpdatedBy") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.HasKey("Id"); b.HasIndex("BusinessAvailabilityId"); - b.HasIndex("BusinessAvailabilityId1"); - b.ToTable("BusinessAvailabilitySlots"); }); @@ -199,16 +221,16 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("Description") .HasMaxLength(500) - .HasColumnType("character varying(500)"); + .HasColumnType("nvarchar(500)"); b.Property("Name") .IsRequired() .HasMaxLength(100) - .HasColumnType("character varying(100)"); + .HasColumnType("nvarchar(100)"); b.HasKey("Id"); @@ -219,40 +241,40 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("Code") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("CountryCode") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("DeliveryMode") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("Email") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("ExpiryDate") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("OtpType") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("PhoneNumber") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("RecordStatus") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("UpdatedBy") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.HasKey("Id"); @@ -263,41 +285,41 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("AccountType") .ValueGeneratedOnAdd() - .HasColumnType("integer") + .HasColumnType("int") .HasDefaultValue(1); b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("Email") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("PhoneCode") .IsRequired() .HasMaxLength(4) - .HasColumnType("character varying(4)"); + .HasColumnType("nvarchar(4)"); b.Property("PhoneNumber") .IsRequired() - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("RecordStatus") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("RegistrationType") .ValueGeneratedOnAdd() - .HasColumnType("integer") + .HasColumnType("int") .HasDefaultValue(1); b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("UpdatedBy") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.HasKey("Id"); @@ -308,40 +330,51 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("IsProcessed") - .HasColumnType("boolean"); + .HasColumnType("bit"); b.Property("LastProcessedDate") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("LastProcessedResult") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("Payload") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("RecordStatus") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("Source") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("UpdatedBy") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.HasKey("Id"); b.ToTable("WebhookMessages"); }); + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Break", b => + { + b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", "BusinessAvailabilitySlot") + .WithMany("Breaks") + .HasForeignKey("BusinessAvailabilitySlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("BusinessAvailabilitySlot"); + }); + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => { b.HasOne("ProjectR.Backend.Domain.Entities.User", "User") @@ -366,17 +399,12 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => { - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", null) + b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", "BusinessAvailability") .WithMany("Slots") .HasForeignKey("BusinessAvailabilityId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", "BusinessAvailability") - .WithMany() - .HasForeignKey("BusinessAvailabilityId1") - .HasConstraintName("FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessA~1"); - b.Navigation("BusinessAvailability"); }); @@ -384,6 +412,11 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Navigation("Slots"); }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => + { + b.Navigation("Breaks"); + }); #pragma warning restore 612, 618 } } diff --git a/src/ProjectR.Backend.Persistence/ProjectR.Backend.Persistence.csproj b/src/ProjectR.Backend.Persistence/ProjectR.Backend.Persistence.csproj index 6109399..6a1d09e 100644 --- a/src/ProjectR.Backend.Persistence/ProjectR.Backend.Persistence.csproj +++ b/src/ProjectR.Backend.Persistence/ProjectR.Backend.Persistence.csproj @@ -3,15 +3,16 @@ net8.0 enable + false enable + all runtime; build; native; contentfiles; analyzers; buildtransitive - diff --git a/src/ProjectR.Backend.Persistence/Repository/BusinessAvailabilityRepository.cs b/src/ProjectR.Backend.Persistence/Repository/BusinessAvailabilityRepository.cs new file mode 100644 index 0000000..3146ecc --- /dev/null +++ b/src/ProjectR.Backend.Persistence/Repository/BusinessAvailabilityRepository.cs @@ -0,0 +1,119 @@ +using Microsoft.EntityFrameworkCore; +using ProjectR.Backend.Domain.Entities; +using ProjectR.Backend.Application.Interfaces.Repository; +using ProjectR.Backend.Persistence.DatabaseContext; +using ProjectR.Backend.Application.Models; +using ProjectR.Backend.Shared.Mappers; +using Microsoft.EntityFrameworkCore.ChangeTracking; +using ProjectR.Backend.Shared; + +namespace ProjectR.Backend.Persistence.Repository +{ + public class BusinessAvailabilityRepository : IBusinessAvailabilityRepository + { + private readonly AppDbContext _appDbContext; + + public BusinessAvailabilityRepository(AppDbContext appDbContext) + { + _appDbContext = appDbContext; + } + + public async Task GetByIdAsync(Guid id) + { + BusinessAvailability? availability = await _appDbContext.BusinessAvailabilities + .Include(x => x.Slots)! + .ThenInclude(s => s.Breaks) + .FirstOrDefaultAsync(x => x.Id == id && x.RecordStatus == RecordStatus.Active); + + if (availability == null) + { + return null; + } + + BusinessAvailabilityModel result = Mapper.Map(availability); + return result; + } + + public async Task AddAsync(BusinessAvailabilityModel model) + { + // Create new availability + BusinessAvailability newAvailability = Mapper.Map(model); + EntityEntry result = await _appDbContext.BusinessAvailabilities.AddAsync(newAvailability); + await _appDbContext.SaveChangesAsync(); + model.Id = result.Entity.Id; + return model; + } + + public async Task UpdateAsync(Guid id, UpdateBusinessAvailabilityModel model) + { + BusinessAvailability? availability = await _appDbContext.BusinessAvailabilities + .Include(x => x.Slots)! + .ThenInclude(s => s.Breaks) + .FirstOrDefaultAsync(x => x.Id == id); + + if (availability == null) + { + return null!; + } + + if (availability.Slots != null && availability.Slots.Any()) + { + _appDbContext.BusinessAvailabilitySlots.RemoveRange(availability.Slots); + } + + List newSlots = model.Slots?.Select(s => Mapper.Map(s)).ToList() + ?? new List(); + + foreach (BusinessAvailabilitySlot slot in newSlots) + { + slot.BusinessAvailabilityId = availability.Id; + } + + if (newSlots.Any()) + { + await _appDbContext.BusinessAvailabilitySlots.AddRangeAsync(newSlots); + } + + await _appDbContext.SaveChangesAsync(); + + BusinessAvailability updatedAvailability = await _appDbContext.BusinessAvailabilities + .Include(x => x.Slots)! + .ThenInclude(s => s.Breaks) + .FirstAsync(x => x.Id == id); + + return Mapper.Map(updatedAvailability); + } + + public async Task GetAllByBusinessIdAsync(Guid id, bool includeAll = false) + { + IQueryable query = _appDbContext.BusinessAvailabilities; + + if (includeAll) + { + query = query.Where(x => x.BusinessId == id); + } + else + { + query = query.Where(x => x.BusinessId == id && x.RecordStatus == RecordStatus.Active); + } + + if (includeAll) + { + query = query.Include(x => x.Slots!) + .ThenInclude(s => s.Breaks); + } + + List availabilities = await query.ToListAsync(); + return availabilities.Select(c => Mapper.Map(c)).ToArray(); + } + + public async Task HasActiveAvailabilityAsync(Guid businessId, DateTime startDate, DateTime endDate) + { + return await _appDbContext.BusinessAvailabilities + .AnyAsync(x => x.BusinessId == businessId + && x.RecordStatus == RecordStatus.Active + && x.StartDate!.Value.Date <= endDate + && x.EndDate!.Value.Date >= startDate); + } + } +} \ No newline at end of file diff --git a/src/ProjectR.Backend.Persistence/Repository/BusinessRepository.cs b/src/ProjectR.Backend.Persistence/Repository/BusinessRepository.cs index 2f86a86..4048dfa 100644 --- a/src/ProjectR.Backend.Persistence/Repository/BusinessRepository.cs +++ b/src/ProjectR.Backend.Persistence/Repository/BusinessRepository.cs @@ -1,4 +1,5 @@ using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.ChangeTracking; using ProjectR.Backend.Application.Interfaces.Repository; using ProjectR.Backend.Application.Models; using ProjectR.Backend.Domain.Entities; @@ -69,7 +70,8 @@ public async Task AddAsync(BusinessModel businessModel) Logo = businessModel.Logo }; - await _context.Businesses.AddAsync(entity); + EntityEntry result = await _context.Businesses.AddAsync(entity); + result.Entity.Id = entity.Id; await _context.SaveChangesAsync(); return businessModel; } @@ -191,29 +193,36 @@ public async Task UpdateAsync(BusinessModel businessModel) return businessModel; } - public async Task GetByUserId(Guid userId) - { - Business? result = await _context.Businesses.SingleOrDefaultAsync(c => c.UserId == userId); - return result == null ? null : new BusinessModel - { - UserId = result!.UserId, - Id = result.Id, - Name = result?.Name, - Type = result?.Type, - PhoneCode = result?.PhoneCode, - PhoneNumber = result?.PhoneNumber, - Industry = result?.Industry, - About = result?.About, - Location = result?.Location, - Longitude = result?.Longitude, - Latitude = result?.Latitude, - Logo = result?.Logo - }; - } public async Task IsBusinessExist(Guid userId) { return await _context.Businesses.AnyAsync(c => c.UserId == userId); } + + public async Task IsBusinessExist(Guid userId, Guid BusinessId) + { + return await _context.Businesses.AnyAsync(c => c.UserId == userId && c.Id == BusinessId) ; + } + + public async Task GetBusinessByUserAsync(Guid UserId) + { + List entities = await _context.Businesses.Where(b => b.UserId == UserId).ToListAsync(); + return entities.Select(e => new BusinessModel + { + UserId = e.UserId, + Id = e.Id, + Name = e.Name, + Type = e.Type, + PhoneCode = e.PhoneCode, + PhoneNumber = e.PhoneNumber, + Industry = e.Industry, + About = e.About, + Location = e.Location, + Longitude = e.Longitude, + Latitude = e.Latitude, + ShortLink = e.ShortLink, + Logo = e.Logo + }).ToArray(); + } } } diff --git a/src/ProjectR.Backend.Persistence/Repository/IndustryRepository.cs b/src/ProjectR.Backend.Persistence/Repository/IndustryRepository.cs index 09de79e..e74bdc5 100644 --- a/src/ProjectR.Backend.Persistence/Repository/IndustryRepository.cs +++ b/src/ProjectR.Backend.Persistence/Repository/IndustryRepository.cs @@ -1,43 +1,76 @@ using Microsoft.EntityFrameworkCore; -using ProjectR.Backend.Domain.Entities; +using Microsoft.EntityFrameworkCore.ChangeTracking; using ProjectR.Backend.Application.Interfaces.Repository; +using ProjectR.Backend.Application.Models; +using ProjectR.Backend.Domain.Entities; using ProjectR.Backend.Persistence.DatabaseContext; namespace ProjectR.Backend.Persistence.Repository { public class IndustryRepository : IIndustryRepository { - private readonly AppDbContext _appDbContext; + private readonly AppDbContext _context; public IndustryRepository(AppDbContext appDbContext) { - _appDbContext = appDbContext; + _context = appDbContext; } - public async Task CreateAsync(Industry industry) + public async Task AddAsync(IndustryModel industryModel) { - await _appDbContext.Industries.AddAsync(industry); - await _appDbContext.SaveChangesAsync(); - return industry.Id; + Industry entity = new() + { + Name = industryModel.Name, + Description = industryModel.Description + }; + + EntityEntry result = await _context.Industries.AddAsync(entity); + result.Entity.Id = entity.Id; + await _context.SaveChangesAsync(); + return industryModel; + } - public async Task GetByIdAsync(Guid id) => await _appDbContext.Industries.FindAsync(id); + public async Task GetByIdAsync(Guid id) + { + Industry? entity = await _context.Industries.SingleOrDefaultAsync(i => i.Id.Equals(id)); + return entity == null ? null : new IndustryModel + { + Id = entity.Id, + Name = entity?.Name, + Description = entity?.Description, + }; + + } - public async Task> GetAllAsync() => await _appDbContext.Industries.ToListAsync(); + public async Task GetAllAsync() + { + List entities = await _context.Industries.ToListAsync(); + return entities.Select(i => new IndustryModel + { + Id = i.Id, + Name = i.Name, + Description = i.Description, + }).ToArray(); + } - public async Task UpdateAsync(Industry industry) + public async Task UpdateAsync(IndustryModel industry) { - _appDbContext.Industries.Update(industry); - await _appDbContext.SaveChangesAsync(); + Industry? entity = await _context.Industries.SingleOrDefaultAsync(i => i.Id.Equals(industry.Id)); + entity!.Name = industry.Name; + entity!.Description = industry.Description; + _context.Industries.Update(entity); + await _context.SaveChangesAsync(); + return industry; } - public async Task DeleteAsync(Guid id) + public async Task DeleteAsync(IndustryModel model) { - var industry = await _appDbContext.Industries.FindAsync(id); + Industry? industry = await _context.Industries.FindAsync(model.Id); if (industry != null) { - _appDbContext.Industries.Remove(industry); - await _appDbContext.SaveChangesAsync(); + _context.Industries.Remove(industry); + await _context.SaveChangesAsync(); } } } diff --git a/src/ProjectR.Backend.Shared/Helpers/DateTimeHelper.cs b/src/ProjectR.Backend.Shared/Helpers/DateTimeHelper.cs new file mode 100644 index 0000000..4b01ad5 --- /dev/null +++ b/src/ProjectR.Backend.Shared/Helpers/DateTimeHelper.cs @@ -0,0 +1,11 @@ +using System.Globalization; +using System.Text; +using System.Text.RegularExpressions; + +namespace ProjectR.Backend.Shared.Helpers +{ + public static class DateTimeHelper + { + + } +} diff --git a/src/ProjectR.Backend.Shared/Mappers/Mapper.cs b/src/ProjectR.Backend.Shared/Mappers/Mapper.cs new file mode 100644 index 0000000..8fd64e2 --- /dev/null +++ b/src/ProjectR.Backend.Shared/Mappers/Mapper.cs @@ -0,0 +1,32 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; + +namespace ProjectR.Backend.Shared.Mappers +{ + public static class Mapper + { + private static readonly JsonSerializerSettings _settings = new JsonSerializerSettings + { + // Prevent self-referencing loop exceptions by ignoring back-references + ReferenceLoopHandling = ReferenceLoopHandling.Ignore, + // Keep property names predictable when mapping between domain and DTOs + ContractResolver = new DefaultContractResolver + { + NamingStrategy = new CamelCaseNamingStrategy() + }, + // Ignore nulls to reduce noise during mapping + NullValueHandling = NullValueHandling.Ignore + }; + + public static TDestination Map(TSource source) + { + if (source == null) + { + return default!; + } + + string serialized = JsonConvert.SerializeObject(source, _settings); + return JsonConvert.DeserializeObject(serialized, _settings)!; + } + } +} \ No newline at end of file diff --git a/src/ProjectR.Backend.Tests/ProjectR.Backend.Tests.csproj b/src/ProjectR.Backend.Tests/ProjectR.Backend.Tests.csproj index a5d5125..546d109 100644 --- a/src/ProjectR.Backend.Tests/ProjectR.Backend.Tests.csproj +++ b/src/ProjectR.Backend.Tests/ProjectR.Backend.Tests.csproj @@ -4,6 +4,7 @@ net8.0 enable enable + false @@ -20,4 +21,4 @@ - + \ No newline at end of file diff --git a/src/ProjectR.Backend.csproj b/src/ProjectR.Backend.csproj index 0a341ec..8838ad2 100644 --- a/src/ProjectR.Backend.csproj +++ b/src/ProjectR.Backend.csproj @@ -4,7 +4,7 @@ net8.0 enable enable - true + false false false e32f2d32-f168-4966-a5ff-3117e6c9adb4 @@ -48,7 +48,9 @@ + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Properties/serviceDependencies.json b/src/Properties/serviceDependencies.json new file mode 100644 index 0000000..33703d5 --- /dev/null +++ b/src/Properties/serviceDependencies.json @@ -0,0 +1,3 @@ +{ + "dependencies": {} +} \ No newline at end of file diff --git a/src/Properties/serviceDependencies.local.json b/src/Properties/serviceDependencies.local.json new file mode 100644 index 0000000..33703d5 --- /dev/null +++ b/src/Properties/serviceDependencies.local.json @@ -0,0 +1,3 @@ +{ + "dependencies": {} +} \ No newline at end of file diff --git a/src/Properties/serviceDependencies.local.json.user b/src/Properties/serviceDependencies.local.json.user new file mode 100644 index 0000000..1b0e055 --- /dev/null +++ b/src/Properties/serviceDependencies.local.json.user @@ -0,0 +1,4 @@ +{ + "dependencies": {}, + "parameters": {} +} \ No newline at end of file diff --git a/src/appsettings.json b/src/appsettings.json index 3aba6a9..ef06def 100644 --- a/src/appsettings.json +++ b/src/appsettings.json @@ -1,32 +1,38 @@ { "ConnectionStrings": { - "DefaultConnection": "Host=host.docker.internal;Port=5432;Database=projectr;Username=postgres;Password=postgres" + //"DefaultConnection": "Server=(localdb)\\MSSQLLocalDB;Database=projectr;MultipleActiveResultSets=true", + //"DefaultConnection": "Server=localhost\\SQLEXPRESS;Database=projectr-db;User Id=sa1;Password=StrongPassword123!;TrustServerCertificate=true;MultipleActiveResultSets=true", + "DefaultConnection": "Data Source=localhost\\SQLEXPRESS;Initial Catalog=projectr;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False" + }, - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "Jwt": { + "Issuer": "https://projectr.dev.com", + "Audience": "https://projectr.dev.com", + "Key": "FakeDevelopmentKeyForOurProjectRApp@12345", + "ValidityInMinutes": 43200 + }, + "Twilio": { + "AccountSID": "tEST", + "AuthToken": "tEST", + "UseMock": true, + "OtpContentSid": "tEST" + }, + "Otp": { + "UseMock": true, + "ExpiryInMin": 10 + }, + "Cloudinary": { + "CloudName": "", + "ApiKey": "", + "ApiSecret": "" + }, + "BusinessAvailability": { + "MaxAdvanceBookingInDays": 7 } - }, - "Jwt": { - "Issuer": "https://projectr.dev.com", - "Audience": "https://projectr.dev.com", - "Key": "FakeDevelopmentKeyForOurProjectRApp@12345", - "ValidityInMinutes": 43200 - }, - "Twilio": { - "AccountSID": "tEST", - "AuthToken": "tEST", - "UseMock": true, - "OtpContentSid": "tEST" - }, - "Otp": { - "UseMock": false, - "ExpiryInMin": 10 - }, - "Cloudinary": { - "CloudName": "dowypvotw", - "ApiKey": "717696641265335", - "ApiSecret": "GQfLtDOeRdeM7dl4sYpjorgy0_8" } -}