diff --git a/Map.Api/Controllers/StepController.cs b/Map.Api/Controllers/StepController.cs index dc5b2be..9583729 100644 --- a/Map.Api/Controllers/StepController.cs +++ b/Map.Api/Controllers/StepController.cs @@ -26,6 +26,7 @@ public class StepController : ControllerBase private readonly IValidator _updateStepDescriptionValidator; private readonly IValidator _updateStepDateValidator; private readonly IValidator _updateStepLocationValidator; + private readonly IValidator _updateStepTransportModeValidator; private readonly ITripPlatform _tripPlatform; private readonly IStepPlatform _stepPlatform; @@ -39,7 +40,8 @@ public StepController(IMapper mapper, IValidator updateStepDescriptionValidator, IValidator updateStepDateValidator, IValidator updateStepLocationValidator, - IValidator updateStepNameValidator) + IValidator updateStepNameValidator, + IValidator updateStepTransportModeValidator) { _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); _addStepValidator = addStepValidator ?? throw new ArgumentNullException(nameof(addStepValidator)); @@ -49,6 +51,7 @@ public StepController(IMapper mapper, _updateStepDescriptionValidator = updateStepDescriptionValidator ?? throw new ArgumentNullException(nameof(updateStepDescriptionValidator)); _updateStepDateValidator = updateStepDateValidator ?? throw new ArgumentNullException(nameof(updateStepDateValidator)); _updateStepLocationValidator = updateStepLocationValidator ?? throw new ArgumentNullException(nameof(updateStepLocationValidator)); + _updateStepTransportModeValidator = updateStepTransportModeValidator ?? throw new ArgumentNullException(nameof(updateStepTransportModeValidator)); } #endregion @@ -101,7 +104,7 @@ public async Task> AddStepAsync([FromRoute] Guid tripId, [ [ProducesResponseType(typeof(Error), StatusCodes.Status403Forbidden)] [ProducesResponseType(typeof(Error), StatusCodes.Status404NotFound)] [ProducesResponseType(typeof(Error), StatusCodes.Status500InternalServerError)] - public async Task> AddStepBeforAsync([FromRoute] Guid tripId, [FromRoute] int stepId, [FromBody] AddStepDto addStepDto) + public async Task> AddStepBeforeAsync([FromRoute] Guid tripId, [FromRoute] int stepId, [FromBody] AddStepDto addStepDto) { ValidationResult validationResult = _addStepValidator.Validate(addStepDto); @@ -118,7 +121,7 @@ public async Task> AddStepBeforAsync([FromRoute] Guid trip Step entity = _mapper.Map(addStepDto); - await _stepPlatform.AddStepBeforAsync(trip, nextStep, entity); + await _stepPlatform.AddStepBeforeAsync(trip, nextStep, entity); return CreatedAtAction(nameof(GetStepById), new { stepId = entity.StepId }, _mapper.Map(entity)); } @@ -442,6 +445,37 @@ public async Task> UpdateStepLocationAsync([FromRoute] int return _mapper.Map(step); } + /// + /// Update step location + /// + /// Id of wanted Step + /// updateStepTransportModeDto + /// Step + [HttpPatch] + [Route("{stepId}/transportMode")] + [MapToApiVersion(ApiControllerVersions.V1)] + [ProducesResponseType(typeof(StepDtoList), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(ICollection), StatusCodes.Status400BadRequest)] + [ProducesResponseType(typeof(Error), StatusCodes.Status400BadRequest)] + [ProducesResponseType(typeof(Error), StatusCodes.Status401Unauthorized)] + [ProducesResponseType(typeof(Error), StatusCodes.Status403Forbidden)] + [ProducesResponseType(typeof(Error), StatusCodes.Status404NotFound)] + [ProducesResponseType(typeof(Error), StatusCodes.Status500InternalServerError)] + public async Task> UpdateStepTransportModeAsync([FromRoute] int stepId, [FromBody] UpdateStepTransportModeDto updateStepTransportModeDto) + { + ValidationResult validationResult = _updateStepTransportModeValidator.Validate(updateStepTransportModeDto); + if (!validationResult.IsValid) + return BadRequest(validationResult.Errors.Select(e => new Error(e.ErrorCode, e.ErrorMessage))); + + Step? step = await _stepPlatform.GetStepByIdAsync(stepId); + if (step is null) + return NotFound(new Error(EStepErrorCodes.StepNotFoundById.ToStringValue(), "Etape non trouvé par id")); + + await _stepPlatform.UpdateStepTransportModeAsync(step, updateStepTransportModeDto); + + return _mapper.Map(step); + } + #endregion #region Delete diff --git a/Map.Api/Extension/ServiceCollectionExtensions.cs b/Map.Api/Extension/ServiceCollectionExtensions.cs index 210c19e..f146db4 100644 --- a/Map.Api/Extension/ServiceCollectionExtensions.cs +++ b/Map.Api/Extension/ServiceCollectionExtensions.cs @@ -230,6 +230,7 @@ private static IServiceCollection AddValidators(this IServiceCollection services services.AddScoped, UpdateStepDescriptionValidator>(); services.AddScoped, UpdateStepLocationValidator>(); services.AddScoped, UpdateStepNameValidator>(); + services.AddScoped, UpdateStepTransportModeValidatior>(); #endregion #region TravelValidator diff --git a/Map.Api/Validator/StepValidator/AddStepValidator.cs b/Map.Api/Validator/StepValidator/AddStepValidator.cs index 257394a..0b8c823 100644 --- a/Map.Api/Validator/StepValidator/AddStepValidator.cs +++ b/Map.Api/Validator/StepValidator/AddStepValidator.cs @@ -43,12 +43,18 @@ public AddStepValidator(IValidator addTravelValidator) //check if the latitude is not empty .NotEmpty() .WithErrorCode(EStepErrorCodes.LatitudeNotEmpty.ToStringValue()) - .WithMessage("Latitude is required"); + .WithMessage("La Latitude est requise"); RuleFor(dto => dto.Longitude) //check if the longitude is not empty .NotEmpty() .WithErrorCode(EStepErrorCodes.LongitudeNotEmpty.ToStringValue()) - .WithMessage("Longitude is required"); + .WithMessage("La longitude est requise"); + + RuleFor(dto => dto.TransportMode) + //check if the transport mode is not empty + .NotEmpty() + .WithErrorCode(EStepErrorCodes.TransportModeNotEmpty.ToStringValue()) + .WithMessage("Les Mode de transport est requis"); } } diff --git a/Map.Api/Validator/StepValidator/UpdateStepTransportModeValidatior.cs b/Map.Api/Validator/StepValidator/UpdateStepTransportModeValidatior.cs new file mode 100644 index 0000000..b21096d --- /dev/null +++ b/Map.Api/Validator/StepValidator/UpdateStepTransportModeValidatior.cs @@ -0,0 +1,24 @@ +using FluentValidation; +using Map.API.Extension; +using Map.Domain.ErrorCodes; +using Map.Domain.Models.Step; + +namespace Map.API.Validator.StepValidator; + +internal class UpdateStepTransportModeValidatior : AbstractValidator +{ + public UpdateStepTransportModeValidatior() + { + RuleFor(dto => dto) + //check if the dto is not empty + .NotEmpty() + .WithErrorCode(EStepErrorCodes.DtoNotNull.ToStringValue()) + .WithMessage("Le Dto est requis"); + + RuleFor(dto => dto.TransportMode) + //check if the transport mode is not empty + .NotEmpty() + .WithErrorCode(EStepErrorCodes.TransportModeNotEmpty.ToStringValue()) + .WithMessage("Le mode de transport est requis"); + } +} \ No newline at end of file diff --git a/Map.Api/wwwroot/swagger/swagger.json b/Map.Api/wwwroot/swagger/swagger.json index c0daa73..c425250 100644 --- a/Map.Api/wwwroot/swagger/swagger.json +++ b/Map.Api/wwwroot/swagger/swagger.json @@ -2391,6 +2391,170 @@ } } }, + "/api/v1/Step/{stepId}/transportMode": { + "patch": { + "tags": [ + "Step" + ], + "summary": "Update step location", + "operationId": "UpdateStepTransportModeAsyncPATCH", + "parameters": [ + { + "name": "stepId", + "in": "path", + "description": "Id of wanted Step", + "required": true, + "style": "simple", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "description": "updateStepTransportModeDto", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateStepTransportModeDto" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/UpdateStepTransportModeDto" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/UpdateStepTransportModeDto" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/StepDto" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/StepDto" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/StepDto" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/Error" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/Error" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/Error" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/Error" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "500": { + "description": "Server Error", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/Error" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + } + } + }, "/api/v1/Testimonial/{userId}": { "post": { "tags": [ @@ -4584,6 +4748,10 @@ "longitude": { "type": "number", "format": "double" + }, + "transportMode": { + "type": "string", + "nullable": true } }, "additionalProperties": false @@ -4848,6 +5016,10 @@ "type": "number", "format": "double" }, + "transportMode": { + "type": "string", + "nullable": true + }, "travelBefore": { "$ref": "#/components/schemas/TravelDto" }, @@ -4897,6 +5069,10 @@ "longitude": { "type": "number", "format": "double" + }, + "transportMode": { + "type": "string", + "nullable": true } }, "additionalProperties": false @@ -5124,6 +5300,16 @@ }, "additionalProperties": false }, + "UpdateStepTransportModeDto": { + "type": "object", + "properties": { + "transportMode": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, "UpdateTripDto": { "type": "object", "properties": { diff --git a/Map.Domain/Entities/Step.cs b/Map.Domain/Entities/Step.cs index c1e734f..5bc0dce 100644 --- a/Map.Domain/Entities/Step.cs +++ b/Map.Domain/Entities/Step.cs @@ -16,6 +16,8 @@ public class Step public DateTime? StartDate { get; set; } public DateTime? EndDate { get; set; } + public string TransportMode { get; set; } + public virtual Travel? TravelBefore { get; set; } public virtual Travel? TravelAfter { get; set; } diff --git a/Map.Domain/ErrorCodes/EStepErrorCodes.cs b/Map.Domain/ErrorCodes/EStepErrorCodes.cs index 1126280..63c153f 100644 --- a/Map.Domain/ErrorCodes/EStepErrorCodes.cs +++ b/Map.Domain/ErrorCodes/EStepErrorCodes.cs @@ -16,4 +16,5 @@ public enum EStepErrorCodes EndDateNotEmpty = 312, StartDateNotEmpty = 313, OrderNotInOrder = 314, + TransportModeNotEmpty = 315, } diff --git a/Map.Domain/Models/Step/AddStepDto.cs b/Map.Domain/Models/Step/AddStepDto.cs index 3069832..ba2a4d9 100644 --- a/Map.Domain/Models/Step/AddStepDto.cs +++ b/Map.Domain/Models/Step/AddStepDto.cs @@ -7,4 +7,5 @@ public class AddStepDto public DateTime? EndDate { get; set; } public decimal Latitude { get; set; } public decimal Longitude { get; set; } + public string TransportMode { get; set; } } diff --git a/Map.Domain/Models/Step/StepDto.cs b/Map.Domain/Models/Step/StepDto.cs index bc64a39..ea1259a 100644 --- a/Map.Domain/Models/Step/StepDto.cs +++ b/Map.Domain/Models/Step/StepDto.cs @@ -16,6 +16,7 @@ public class StepDto public DateTime? EndDate { get; set; } public decimal Latitude { get; set; } public decimal Longitude { get; set; } + public string TransportMode { get; set; } public virtual TravelDto? TravelBefore { get; set; } public virtual TravelDto? TravelAfter { get; set; } diff --git a/Map.Domain/Models/Step/StepDtoList.cs b/Map.Domain/Models/Step/StepDtoList.cs index 63f2864..29f46e9 100644 --- a/Map.Domain/Models/Step/StepDtoList.cs +++ b/Map.Domain/Models/Step/StepDtoList.cs @@ -11,4 +11,5 @@ public class StepDtoList public DateTime? EndDate { get; set; } public decimal Latitude { get; set; } public decimal Longitude { get; set; } + public string TransportMode { get; set; } } diff --git a/Map.Domain/Models/Step/UpdateStepTransportModeDto.cs b/Map.Domain/Models/Step/UpdateStepTransportModeDto.cs new file mode 100644 index 0000000..b02306a --- /dev/null +++ b/Map.Domain/Models/Step/UpdateStepTransportModeDto.cs @@ -0,0 +1,5 @@ +namespace Map.Domain.Models.Step; +public class UpdateStepTransportModeDto +{ + public string TransportMode { get; set; } +} diff --git a/Map.EFCore/Data/DBInitializer.cs b/Map.EFCore/Data/DBInitializer.cs index d9a6174..e188941 100644 --- a/Map.EFCore/Data/DBInitializer.cs +++ b/Map.EFCore/Data/DBInitializer.cs @@ -225,7 +225,8 @@ private async Task AddTripsAsync() Latitude = (decimal)(_random.NextDouble() * 180 - 90), Description = $"Description for Step {j + 1} for Trip {i + 1}", StartDate = DateTime.Now.AddDays(j), - EndDate = DateTime.Now.AddDays(j + 1) + EndDate = DateTime.Now.AddDays(j + 1), + TransportMode = "plane", }; steps.Add(step); @@ -241,7 +242,7 @@ private async Task AddTripsAsync() TripId = trip.TripId, OriginStep = steps[k], DestinationStep = steps[k + 1], - TransportMode = "Mode of Transport", + TransportMode = "plane", Distance = (decimal)_random.NextDouble() * 1000, Duration = (decimal)_random.NextDouble() * 24 }; diff --git a/Map.EFCore/Interfaces/IStepRepository.cs b/Map.EFCore/Interfaces/IStepRepository.cs index 6ab304f..345b2a0 100644 --- a/Map.EFCore/Interfaces/IStepRepository.cs +++ b/Map.EFCore/Interfaces/IStepRepository.cs @@ -16,7 +16,7 @@ public interface IStepRepository : IGenericRepository /// trip where add step /// Step before where to add a new step /// new step to add - public Task AddStepBeforAsync(Trip trip, Step nextStep, Step step); + public Task AddStepBeforeAsync(Trip trip, Step nextStep, Step step); /// /// Add a step to a trip after a step diff --git a/Map.EFCore/MapContext.cs b/Map.EFCore/MapContext.cs index f07b079..d0c696c 100644 --- a/Map.EFCore/MapContext.cs +++ b/Map.EFCore/MapContext.cs @@ -79,12 +79,15 @@ protected override void OnModelCreating(ModelBuilder builder) s.Property(s => s.Name).IsRequired(); s.Property(s => s.Latitude).HasPrecision(18, 12).IsRequired(); s.Property(s => s.Longitude).HasPrecision(18, 12).IsRequired(); + s.Property(s => s.Order).IsRequired(); + s.Property(s => s.TransportMode).IsRequired(); s.Property(s => s.Description).HasMaxLength(500); s.Property(s => s.StartDate).IsRequired(false); s.Property(s => s.EndDate).IsRequired(false); + s.HasOne(s => s.Trip) .WithMany(t => t.Steps) .HasForeignKey(s => s.TripId) diff --git a/Map.EFCore/Migrations/20240329222859_addTransportModeToStep.Designer.cs b/Map.EFCore/Migrations/20240329222859_addTransportModeToStep.Designer.cs new file mode 100644 index 0000000..2d40e4a --- /dev/null +++ b/Map.EFCore/Migrations/20240329222859_addTransportModeToStep.Designer.cs @@ -0,0 +1,542 @@ +// +using System; +using Map.EFCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Map.EFCore.Migrations +{ + [DbContext(typeof(MapContext))] + [Migration("20240329222859_addTransportModeToStep")] + partial class addTransportModeToStep + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.2") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Map.Domain.Entities.MapUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("NormalizedEmail") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedUserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("MapUsers", (string)null); + }); + + modelBuilder.Entity("Map.Domain.Entities.Step", b => + { + b.Property("StepId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("StepId")); + + b.Property("Description") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("Latitude") + .HasPrecision(18, 12) + .HasColumnType("decimal(18,12)"); + + b.Property("Longitude") + .HasPrecision(18, 12) + .HasColumnType("decimal(18,12)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Order") + .HasColumnType("int"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("TransportMode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TripId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("StepId"); + + b.HasIndex("TripId"); + + b.ToTable("Steps", (string)null); + }); + + modelBuilder.Entity("Map.Domain.Entities.Testimonial", b => + { + b.Property("TestimonialId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("TestimonialId")); + + b.Property("FeedBack") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("Rate") + .HasColumnType("int"); + + b.Property("TestimonialDate") + .HasColumnType("date"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("TestimonialId"); + + b.HasIndex("UserId"); + + b.ToTable("Testimonials", (string)null); + }); + + modelBuilder.Entity("Map.Domain.Entities.Travel", b => + { + b.Property("TravelId") + .HasColumnType("int"); + + b.Property("DestinationStepId") + .HasColumnType("int"); + + b.Property("Distance") + .HasPrecision(18, 12) + .HasColumnType("decimal(18,12)"); + + b.Property("Duration") + .HasPrecision(18, 12) + .HasColumnType("decimal(18,12)"); + + b.Property("OriginStepId") + .HasColumnType("int"); + + b.Property("TransportMode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TripId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("TravelId"); + + b.HasIndex("DestinationStepId") + .IsUnique(); + + b.HasIndex("OriginStepId") + .IsUnique(); + + b.HasIndex("TripId"); + + b.ToTable("Travels", (string)null); + }); + + modelBuilder.Entity("Map.Domain.Entities.TravelRoad", b => + { + b.Property("TravelId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("TravelId")); + + b.Property("RoadCoordinates") + .IsRequired() + .HasMaxLength(-1) + .HasColumnType("nvarchar(max)"); + + b.HasKey("TravelId"); + + b.ToTable("TravelRoads", (string)null); + }); + + modelBuilder.Entity("Map.Domain.Entities.Trip", b => + { + b.Property("TripId") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("BackgroundPicturePath") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("EndDate") + .HasColumnType("date"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartDate") + .HasColumnType("date"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("TripId"); + + b.HasIndex("UserId"); + + b.ToTable("Trips", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderKey") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("Name") + .HasColumnType("nvarchar(450)"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("Map.Domain.Entities.Step", b => + { + b.HasOne("Map.Domain.Entities.Trip", "Trip") + .WithMany("Steps") + .HasForeignKey("TripId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Trip"); + }); + + modelBuilder.Entity("Map.Domain.Entities.Testimonial", b => + { + b.HasOne("Map.Domain.Entities.MapUser", "User") + .WithMany("Testimonials") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Map.Domain.Entities.Travel", b => + { + b.HasOne("Map.Domain.Entities.Step", "DestinationStep") + .WithOne("TravelBefore") + .HasForeignKey("Map.Domain.Entities.Travel", "DestinationStepId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Map.Domain.Entities.Step", "OriginStep") + .WithOne("TravelAfter") + .HasForeignKey("Map.Domain.Entities.Travel", "OriginStepId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Map.Domain.Entities.TravelRoad", "TravelRoad") + .WithOne("Travel") + .HasForeignKey("Map.Domain.Entities.Travel", "TravelId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Map.Domain.Entities.Trip", "Trip") + .WithMany("Travels") + .HasForeignKey("TripId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("DestinationStep"); + + b.Navigation("OriginStep"); + + b.Navigation("TravelRoad"); + + b.Navigation("Trip"); + }); + + modelBuilder.Entity("Map.Domain.Entities.Trip", b => + { + b.HasOne("Map.Domain.Entities.MapUser", "User") + .WithMany("Trips") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Map.Domain.Entities.MapUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Map.Domain.Entities.MapUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Map.Domain.Entities.MapUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Map.Domain.Entities.MapUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Map.Domain.Entities.MapUser", b => + { + b.Navigation("Testimonials"); + + b.Navigation("Trips"); + }); + + modelBuilder.Entity("Map.Domain.Entities.Step", b => + { + b.Navigation("TravelAfter"); + + b.Navigation("TravelBefore"); + }); + + modelBuilder.Entity("Map.Domain.Entities.TravelRoad", b => + { + b.Navigation("Travel"); + }); + + modelBuilder.Entity("Map.Domain.Entities.Trip", b => + { + b.Navigation("Steps"); + + b.Navigation("Travels"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Map.EFCore/Migrations/20240329222859_addTransportModeToStep.cs b/Map.EFCore/Migrations/20240329222859_addTransportModeToStep.cs new file mode 100644 index 0000000..cfa4707 --- /dev/null +++ b/Map.EFCore/Migrations/20240329222859_addTransportModeToStep.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Map.EFCore.Migrations +{ + /// + public partial class addTransportModeToStep : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "TransportMode", + table: "Steps", + type: "nvarchar(max)", + nullable: false, + defaultValue: ""); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "TransportMode", + table: "Steps"); + } + } +} diff --git a/Map.EFCore/Migrations/MapContextModelSnapshot.cs b/Map.EFCore/Migrations/MapContextModelSnapshot.cs index d148317..ed32fbd 100644 --- a/Map.EFCore/Migrations/MapContextModelSnapshot.cs +++ b/Map.EFCore/Migrations/MapContextModelSnapshot.cs @@ -124,6 +124,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("StartDate") .HasColumnType("datetime2"); + b.Property("TransportMode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + b.Property("TripId") .HasColumnType("uniqueidentifier"); diff --git a/Map.EFCore/Repositories/StepRepository.cs b/Map.EFCore/Repositories/StepRepository.cs index 82c804f..3e65206 100644 --- a/Map.EFCore/Repositories/StepRepository.cs +++ b/Map.EFCore/Repositories/StepRepository.cs @@ -40,7 +40,7 @@ public async Task AddStepAfterAsync(Trip trip, Step nextStep, Step step) } /// - public async Task AddStepBeforAsync(Trip trip, Step previousStep, Step step) + public async Task AddStepBeforeAsync(Trip trip, Step previousStep, Step step) { trip.Steps = trip.Steps.OrderBy(step => step.Order).ToList(); int previousStepIndex = trip.Steps.ToList().FindIndex(s => s.Order == previousStep.Order); diff --git a/Map.EFCore/Repositories/TravelRepository.cs b/Map.EFCore/Repositories/TravelRepository.cs index 749b34e..df08576 100644 --- a/Map.EFCore/Repositories/TravelRepository.cs +++ b/Map.EFCore/Repositories/TravelRepository.cs @@ -9,62 +9,56 @@ public TravelRepository(MapContext context) : base(context) } /// - public Task AddLinkedTravelAsync(Step step, Travel travelBefore, Travel travelAfter) + public async Task AddLinkedTravelAsync(Step step, Travel travelBefore, Travel travelAfter) { step.TravelBefore = travelBefore; step.TravelAfter = travelAfter; - return _context.SaveChangesAsync(); + await _context.SaveChangesAsync(); } /// - public Task AddTravelBeforeAsync(Step step, Travel travel) + public async Task AddTravelBeforeAsync(Step step, Travel travel) { step.TravelBefore = travel; - return _context.SaveChangesAsync(); + await _context.SaveChangesAsync(); } /// - public Task RemoveLinkedTravelAsync(Step step) + public async Task RemoveLinkedTravelAsync(Step step) { if (step.TravelBefore is not null) { _context.Travel.Remove(step.TravelBefore); - _context.TravelRoad.Remove(step.TravelBefore.TravelRoad); + await _context.SaveChangesAsync(); } if (step.TravelAfter is not null) { _context.Travel.Remove(step.TravelAfter); - _context.TravelRoad.Remove(step.TravelAfter.TravelRoad); + await _context.SaveChangesAsync(); } - - return _context.SaveChangesAsync(); - } /// - public Task RemoveTravelAfterStepAsync(Step step) + public async Task RemoveTravelAfterStepAsync(Step step) { if (step.TravelAfter is null) - return Task.CompletedTask; + return; _context.Travel.Remove(step.TravelAfter); - _context.TravelRoad.Remove(step.TravelAfter.TravelRoad); - - return _context.SaveChangesAsync(); + await _context.SaveChangesAsync(); } /// - public Task RemoveTravelBeforeStepAsync(Step step) + public async Task RemoveTravelBeforeStepAsync(Step step) { if (step.TravelBefore is null) - return Task.CompletedTask; + return; _context.Travel.Remove(step.TravelBefore); - _context.TravelRoad.Remove(step.TravelBefore.TravelRoad); - return _context.SaveChangesAsync(); + await _context.SaveChangesAsync(); } } diff --git a/Map.EFCore/Repositories/TripRepository.cs b/Map.EFCore/Repositories/TripRepository.cs index 7fda1b5..1fbba0a 100644 --- a/Map.EFCore/Repositories/TripRepository.cs +++ b/Map.EFCore/Repositories/TripRepository.cs @@ -15,9 +15,9 @@ public TripRepository(MapContext context) : base(context) /// public async Task GetTripByIdAsync(Guid TripId) => await _context.Trip.Include(t => t.Steps) - .Include(t => t.Travels) - .ThenInclude(t => t.TravelRoad) - .FirstOrDefaultAsync(t => t.TripId == TripId); + .Include(t => t.Travels) + .ThenInclude(t => t.TravelRoad) + .FirstOrDefaultAsync(t => t.TripId == TripId); /// public async Task UpdateAsync(Trip trip, UpdateTripDto update) diff --git a/Map.Platform/AuthPlatform.cs b/Map.Platform/AuthPlatform.cs index 62ab36e..08dc328 100644 --- a/Map.Platform/AuthPlatform.cs +++ b/Map.Platform/AuthPlatform.cs @@ -57,6 +57,7 @@ public async Task CreateTokenAsync(MapUser user) { Subject = new ClaimsIdentity(authClaims), Expires = DateTime.UtcNow.AddHours(_jwtSettings.DurationTime), + IssuedAt = DateTime.UtcNow, Issuer = _jwtSettings.ValidIssuer, Audience = _jwtSettings.ValidAudience, diff --git a/Map.Platform/Interfaces/IStepPlatform.cs b/Map.Platform/Interfaces/IStepPlatform.cs index d1625f3..51ed988 100644 --- a/Map.Platform/Interfaces/IStepPlatform.cs +++ b/Map.Platform/Interfaces/IStepPlatform.cs @@ -18,7 +18,7 @@ public interface IStepPlatform /// trip where add step /// step where add new step /// dto of new - Task AddStepBeforAsync(Trip trip, Step nextStep, Step entity); + Task AddStepBeforeAsync(Trip trip, Step nextStep, Step entity); /// /// Add a step to a trip after a step @@ -108,4 +108,12 @@ public interface IStepPlatform /// new location /// updated step Task UpdateStepLocationAsync(Step step, UpdateStepLocationDto updateStepLocationDto); + + /// + /// Update a step transport mode + /// + /// step to update + /// new transport mode + /// updated step + Task UpdateStepTransportModeAsync(Step step, UpdateStepTransportModeDto updateStepTransportModeDto); } diff --git a/Map.Platform/StepPlatform.cs b/Map.Platform/StepPlatform.cs index 0d7556a..a09684a 100644 --- a/Map.Platform/StepPlatform.cs +++ b/Map.Platform/StepPlatform.cs @@ -26,10 +26,10 @@ public async Task AddStepAsync(Trip trip, Step entity) } /// - public async Task AddStepBeforAsync(Trip trip, Step previousStep, Step entity) + public async Task AddStepBeforeAsync(Trip trip, Step previousStep, Step entity) { await _unitOfWork.Travel.RemoveTravelBeforeStepAsync(previousStep); - await _unitOfWork.Step.AddStepBeforAsync(trip, previousStep, entity); + await _unitOfWork.Step.AddStepBeforeAsync(trip, previousStep, entity); await _unitOfWork.CompleteAsync(); } @@ -116,4 +116,12 @@ public async Task UpdateStepLocationAsync(Step step, UpdateStepLocationDto updat await _unitOfWork.Step.UpdateStepAsync(step); await _unitOfWork.CompleteAsync(); } + + /// + public async Task UpdateStepTransportModeAsync(Step step, UpdateStepTransportModeDto updateStepTransportModeDto) + { + step.TransportMode = updateStepTransportModeDto.TransportMode; + await _unitOfWork.Step.UpdateStepAsync(step); + await _unitOfWork.CompleteAsync(); + } }