From a714e291469be3e98e70f75519664fc20f63adb7 Mon Sep 17 00:00:00 2001 From: giarreh Date: Tue, 28 Jan 2025 09:00:53 +0100 Subject: [PATCH 1/6] gitignore --- .gitignore | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitignore b/.gitignore index cf332414..4aae0028 100644 --- a/.gitignore +++ b/.gitignore @@ -368,3 +368,9 @@ FodyWeavers.xsd */**/bin/Release */**/obj/Debug */**/obj/Release +**/**/appsettings.json +**/**/appsettings.Development.json +**/**/bin/Debug +**/**/bin/Release +**/**/obj/Debug +**/**/obj/Release \ No newline at end of file From e6c951ca8a388ed8121913791999727e036d98c7 Mon Sep 17 00:00:00 2001 From: giarreh Date: Tue, 28 Jan 2025 09:43:02 +0100 Subject: [PATCH 2/6] ERD diagram + Models --- ERD.png | Bin 0 -> 45228 bytes .../api-cinema-challenge/Models/Customer.cs | 29 +++++++++++++++++ .../api-cinema-challenge/Models/Movie.cs | 24 ++++++++++++++ .../api-cinema-challenge/Models/Screening.cs | 30 ++++++++++++++++++ .../api-cinema-challenge/Models/Ticket.cs | 29 +++++++++++++++++ .../api-cinema-challenge.csproj | 5 ++- 6 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 ERD.png create mode 100644 api-cinema-challenge/api-cinema-challenge/Models/Customer.cs create mode 100644 api-cinema-challenge/api-cinema-challenge/Models/Movie.cs create mode 100644 api-cinema-challenge/api-cinema-challenge/Models/Screening.cs create mode 100644 api-cinema-challenge/api-cinema-challenge/Models/Ticket.cs diff --git a/ERD.png b/ERD.png new file mode 100644 index 0000000000000000000000000000000000000000..b26fa5e589fb2f2a5a98036ea6f9670ff513d227 GIT binary patch literal 45228 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 - + + + + From 7f1a7038f4c3aa772ff6b25952ffe89bf8766504 Mon Sep 17 00:00:00 2001 From: giarreh Date: Tue, 28 Jan 2025 10:32:51 +0100 Subject: [PATCH 3/6] Database + endpoints setup --- .gitignore | 3 +- .../Data/CinemaContext.cs | 210 +++++++++++++++++- .../Endpoints/CinemaEndpoints.cs | 23 ++ .../api-cinema-challenge/Models/Movie.cs | 7 + .../api-cinema-challenge/Models/Screening.cs | 10 +- .../api-cinema-challenge/Program.cs | 4 + .../Repository/IRepository.cs | 37 +++ .../Repository/Repository.cs | 116 ++++++++++ .../api-cinema-challenge/ViewModel/Payload.cs | 6 + .../api-cinema-challenge.csproj | 10 +- 10 files changed, 416 insertions(+), 10 deletions(-) create mode 100644 api-cinema-challenge/api-cinema-challenge/Endpoints/CinemaEndpoints.cs create mode 100644 api-cinema-challenge/api-cinema-challenge/Repository/IRepository.cs create mode 100644 api-cinema-challenge/api-cinema-challenge/Repository/Repository.cs create mode 100644 api-cinema-challenge/api-cinema-challenge/ViewModel/Payload.cs diff --git a/.gitignore b/.gitignore index 4aae0028..bc1605f1 100644 --- a/.gitignore +++ b/.gitignore @@ -373,4 +373,5 @@ FodyWeavers.xsd **/**/bin/Debug **/**/bin/Release **/**/obj/Debug -**/**/obj/Release \ No newline at end of file +**/**/obj/Release +/api-cinema-challenge/api-cinema-challenge/Migrations diff --git a/api-cinema-challenge/api-cinema-challenge/Data/CinemaContext.cs b/api-cinema-challenge/api-cinema-challenge/Data/CinemaContext.cs index ad4fe854..5b13de6d 100644 --- a/api-cinema-challenge/api-cinema-challenge/Data/CinemaContext.cs +++ b/api-cinema-challenge/api-cinema-challenge/Data/CinemaContext.cs @@ -1,5 +1,7 @@ -using Microsoft.EntityFrameworkCore; +using api_cinema_challenge.Models; +using Microsoft.EntityFrameworkCore; using Newtonsoft.Json.Linq; +using System.Diagnostics; namespace api_cinema_challenge.Data { @@ -16,11 +18,217 @@ public CinemaContext(DbContextOptions options) : base(options) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseNpgsql(_connectionString); + optionsBuilder.LogTo(message => Debug.WriteLine(message)); } protected override void OnModelCreating(ModelBuilder modelBuilder) { + var now = new DateTime(2025, 01, 01, 0, 0, 0, DateTimeKind.Utc); + modelBuilder.Entity().HasData( + new Movie + { + Id = 1, + Title = "Inception", + Rating = "PG-13", + Description = "A thief who steals corporate secrets through the use of dream-sharing technology is tasked with planting an idea into the mind of a C.E.O.", + RuntimeMins = 148, + CreatedAt = now, + UpdatedAt = now + }, + new Movie + { + Id = 2, + Title = "The Dark Knight", + Rating = "PG-13", + Description = "When the menace known as The Joker emerges from his mysterious past, he wreaks havoc and chaos on the people of Gotham.", + RuntimeMins = 152, + CreatedAt = now, + UpdatedAt = now + }, + new Movie + { + Id = 3, + Title = "Interstellar", + Rating = "PG-13", + Description = "A team of explorers travel through a wormhole in space in an attempt to ensure humanity's survival.", + RuntimeMins = 169, + CreatedAt = now, + UpdatedAt = now + }, + new Movie + { + Id = 4, + Title = "The Shawshank Redemption", + Rating = "R", + Description = "Two imprisoned men bond over a number of years, finding solace and eventual redemption through acts of common decency.", + RuntimeMins = 142, + CreatedAt = now, + UpdatedAt = now + }, + new Movie + { + Id = 5, + Title = "Dunkirk", + Rating = "PG-13", + Description = "Allied soldiers from Belgium, the British Empire, and France are surrounded by the German Army and evacuated during a fierce battle in World War II.", + RuntimeMins = 106, + CreatedAt = now, + UpdatedAt = now + } + ); + modelBuilder.Entity().HasData( + new Customer + { + Id = 1, + Name = "John Doe", + Email = "john.doe@example.com", + Phone = "123-456-7890", + CreatedAt = now, + UpdatedAt = now + }, + new Customer + { + Id = 2, + Name = "Jane Smith", + Email = "jane.smith@example.com", + Phone = "098-765-4321", + CreatedAt = now, + UpdatedAt = now + }, + new Customer + { + Id = 3, + Name = "Emily Davis", + Email = "emily.davis@example.com", + Phone = "555-123-4567", + CreatedAt = now, + UpdatedAt = now + }, + new Customer + { + Id = 4, + Name = "Michael Brown", + Email = "michael.brown@example.com", + Phone = "444-567-8901", + CreatedAt = now, + UpdatedAt = now + }, + new Customer + { + Id = 5, + Name = "Sarah Johnson", + Email = "sarah.johnson@example.com", + Phone = "222-345-6789", + CreatedAt = now, + UpdatedAt = now + } + ); + modelBuilder.Entity().HasData( + new Screening + { + Id = 1, + MovieId = 1, + ScreenNumber = 1, + Capacity = 100, + StartsAt = now.AddHours(2), + CreatedAt = now, + UpdatedAt = now + }, + new Screening + { + Id = 2, + MovieId = 4, + ScreenNumber = 2, + Capacity = 80, + StartsAt = now.AddHours(3), + CreatedAt = now, + UpdatedAt = now + }, + new Screening + { + Id = 3, + MovieId = 5, + ScreenNumber = 3, + Capacity = 120, + StartsAt = now.AddDays(1).AddHours(2), + CreatedAt = now, + UpdatedAt = now + }, + new Screening + { + Id = 4, + MovieId = 3, + ScreenNumber = 1, + Capacity = 90, + StartsAt = now.AddDays(1).AddHours(5), + CreatedAt = now, + UpdatedAt = now + }, + new Screening + { + Id = 5, + MovieId = 3, + ScreenNumber = 2, + Capacity = 110, + StartsAt = now.AddHours(6), + CreatedAt = now, + UpdatedAt = now + } + ); + modelBuilder.Entity().HasData( + new Ticket + { + Id = 1, + ScreeningId = 1, + CustomerId = 1, + NumSeats = 2, + CreatedAt = now, + UpdatedAt = now + }, + new Ticket + { + Id = 2, + ScreeningId = 2, + CustomerId = 2, + NumSeats = 1, + CreatedAt = now, + UpdatedAt = now + }, + new Ticket + { + Id = 3, + ScreeningId = 3, + CustomerId = 3, + NumSeats = 4, + CreatedAt = now, + UpdatedAt = now + }, + new Ticket + { + Id = 4, + ScreeningId = 4, + CustomerId = 4, + NumSeats = 3, + CreatedAt = now, + UpdatedAt = now + }, + new Ticket + { + Id = 5, + ScreeningId = 5, + CustomerId = 5, + NumSeats = 2, + CreatedAt = now, + UpdatedAt = now } + ); + } + + public DbSet Customers { get; set; } + public DbSet Movies { get; set; } + public DbSet Screenings { get; set; } + public DbSet Tickets { get; set; } + } } diff --git a/api-cinema-challenge/api-cinema-challenge/Endpoints/CinemaEndpoints.cs b/api-cinema-challenge/api-cinema-challenge/Endpoints/CinemaEndpoints.cs new file mode 100644 index 00000000..3557cb7f --- /dev/null +++ b/api-cinema-challenge/api-cinema-challenge/Endpoints/CinemaEndpoints.cs @@ -0,0 +1,23 @@ +using api_cinema_challenge.Repository; +using Microsoft.AspNetCore.Mvc; + +namespace api_cinema_challenge.Endpoints +{ + public static class CinemaEndpoints + { + public static void ConfigureCinemaEndpoint(this WebApplication app) + { + var cinemaGroup = app.MapGroup("cinema"); + + cinemaGroup.MapGet("/movies", GetMovies); + } + + [ProducesResponseType(StatusCodes.Status200OK)] + public static async Task GetMovies(IRepository repository) + { + var movies = await repository.GetMovies(); + return Results.Ok(movies); + } + + } +} diff --git a/api-cinema-challenge/api-cinema-challenge/Models/Movie.cs b/api-cinema-challenge/api-cinema-challenge/Models/Movie.cs index 417c0fee..87fca615 100644 --- a/api-cinema-challenge/api-cinema-challenge/Models/Movie.cs +++ b/api-cinema-challenge/api-cinema-challenge/Models/Movie.cs @@ -20,5 +20,12 @@ public class Movie [Required] [Column("RuntimeMins")] public int RuntimeMins { get; set; } + [Required] + [Column("CreatedAt")] + public DateTime CreatedAt { get; set; } + [Required] + [Column("UpdatedAt")] + public DateTime UpdatedAt { get; set; } + } } diff --git a/api-cinema-challenge/api-cinema-challenge/Models/Screening.cs b/api-cinema-challenge/api-cinema-challenge/Models/Screening.cs index 5368f4db..939e4514 100644 --- a/api-cinema-challenge/api-cinema-challenge/Models/Screening.cs +++ b/api-cinema-challenge/api-cinema-challenge/Models/Screening.cs @@ -13,18 +13,18 @@ public class Screening public int MovieId { get; set; } [Required] [Column("ScreenNumber")] - public int screenNumber { get; set; } + public int ScreenNumber { get; set; } [Required] [Column("Capacity")] - public int capacity { get; set; } + public int Capacity { get; set; } [Required] [Column("StartsAt")] - public DateTime startsAt { get; set; } + public DateTime StartsAt { get; set; } [Required] [Column("EndsAt")] - public DateTime createdAt { get; set; } + public DateTime CreatedAt { get; set; } [Required] [Column("CreatedAt")] - public DateTime updatedAt { get; set; } + public DateTime UpdatedAt { get; set; } } } diff --git a/api-cinema-challenge/api-cinema-challenge/Program.cs b/api-cinema-challenge/api-cinema-challenge/Program.cs index e55d9d54..ebee0238 100644 --- a/api-cinema-challenge/api-cinema-challenge/Program.cs +++ b/api-cinema-challenge/api-cinema-challenge/Program.cs @@ -1,4 +1,6 @@ using api_cinema_challenge.Data; +using api_cinema_challenge.Endpoints; +using api_cinema_challenge.Repository; var builder = WebApplication.CreateBuilder(args); @@ -6,6 +8,7 @@ builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); builder.Services.AddDbContext(); +builder.Services.AddScoped(); var app = builder.Build(); @@ -17,4 +20,5 @@ } app.UseHttpsRedirection(); +app.ConfigureCinemaEndpoint(); app.Run(); diff --git a/api-cinema-challenge/api-cinema-challenge/Repository/IRepository.cs b/api-cinema-challenge/api-cinema-challenge/Repository/IRepository.cs new file mode 100644 index 00000000..85b8effc --- /dev/null +++ b/api-cinema-challenge/api-cinema-challenge/Repository/IRepository.cs @@ -0,0 +1,37 @@ +using api_cinema_challenge.Models; + +namespace api_cinema_challenge.Repository +{ + public interface IRepository + { + // Customers + Task> GetCustomers(); + Task GetCustomer(int id); + Task CreateCustomer(Customer customer); + Task UpdateCustomer(int id, Customer customer); + Task DeleteCustomer(int id); + + // Movies + Task> GetMovies(); + Task GetMovie(int id); + Task CreateMovie(Movie movie); + Task UpdateMovie(int id, Movie movie); + Task DeleteMovie(int id); + + // Screenings + Task> GetScreenings(); + Task GetScreening(int id); + Task CreateScreening(Screening screening); + Task UpdateScreening(int id, Screening screening); + Task DeleteScreening(int id); + + // Tickets + Task> GetTickets(); + Task GetTicket(int id); + Task CreateTicket(Ticket ticket); + Task UpdateTicket(int id, Ticket ticket); + Task DeleteTicket(int id); + + + } +} diff --git a/api-cinema-challenge/api-cinema-challenge/Repository/Repository.cs b/api-cinema-challenge/api-cinema-challenge/Repository/Repository.cs new file mode 100644 index 00000000..3a0a7301 --- /dev/null +++ b/api-cinema-challenge/api-cinema-challenge/Repository/Repository.cs @@ -0,0 +1,116 @@ +using api_cinema_challenge.Data; +using api_cinema_challenge.Models; +using Microsoft.EntityFrameworkCore; + +namespace api_cinema_challenge.Repository +{ + public class Repository : IRepository + { + private CinemaContext _db; + + public Repository(CinemaContext db) + { + _db = db; + } + + + // CUSTOMERS _______________________________________________________ + public Task> GetCustomers() + { + throw new NotImplementedException(); + } + public Task GetCustomer(int id) + { + throw new NotImplementedException(); + } + + public Task CreateCustomer(Customer customer) + { + throw new NotImplementedException(); + } + public Task UpdateCustomer(int id, Customer customer) + { + throw new NotImplementedException(); + } + + public Task DeleteCustomer(int id) + { + throw new NotImplementedException(); + } + + // MOVIES _______________________________________________________ + + + public async Task> GetMovies() + { + return await _db.Movies.ToListAsync(); + } + public Task GetMovie(int id) + { + throw new NotImplementedException(); + } + public Task CreateMovie(Movie movie) + { + throw new NotImplementedException(); + } + public Task UpdateMovie(int id, Movie movie) + { + throw new NotImplementedException(); + } + public Task DeleteMovie(int id) + { + throw new NotImplementedException(); + } + + // SCREENINGS _______________________________________________________ + public Task> GetScreenings() + { + throw new NotImplementedException(); + } + public Task GetScreening(int id) + { + throw new NotImplementedException(); + } + public Task CreateScreening(Screening screening) + { + throw new NotImplementedException(); + } + public Task UpdateScreening(int id, Screening screening) + { + throw new NotImplementedException(); + } + + public Task DeleteScreening(int id) + { + throw new NotImplementedException(); + } + + // TICKETS _______________________________________________________ + + + public Task> GetTickets() + { + throw new NotImplementedException(); + } + + public Task GetTicket(int id) + { + throw new NotImplementedException(); + } + + public Task CreateTicket(Ticket ticket) + { + throw new NotImplementedException(); + } + public Task UpdateTicket(int id, Ticket ticket) + { + throw new NotImplementedException(); + } + public Task DeleteTicket(int id) + { + throw new NotImplementedException(); + } + + + } +} diff --git a/api-cinema-challenge/api-cinema-challenge/ViewModel/Payload.cs b/api-cinema-challenge/api-cinema-challenge/ViewModel/Payload.cs new file mode 100644 index 00000000..074f9700 --- /dev/null +++ b/api-cinema-challenge/api-cinema-challenge/ViewModel/Payload.cs @@ -0,0 +1,6 @@ +namespace api_cinema_challenge.ViewModel +{ + public class Payload + { + } +} diff --git a/api-cinema-challenge/api-cinema-challenge/api-cinema-challenge.csproj b/api-cinema-challenge/api-cinema-challenge/api-cinema-challenge.csproj index c86c399a..f1ad9610 100644 --- a/api-cinema-challenge/api-cinema-challenge/api-cinema-challenge.csproj +++ b/api-cinema-challenge/api-cinema-challenge/api-cinema-challenge.csproj @@ -17,6 +17,11 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + all @@ -24,14 +29,13 @@ + - - - + From 1eeeda1d4a1d64fa543d5ea024c25eddd5caadca Mon Sep 17 00:00:00 2001 From: giarreh Date: Tue, 28 Jan 2025 22:56:34 +0100 Subject: [PATCH 4/6] dont remember what ive done, but need to commit --- .../api-cinema-challenge/DTOs/MovieDTO.cs | 13 ++++ .../Endpoints/CinemaEndpoints.cs | 54 ++++++++++++++- .../api-cinema-challenge/Payload/Payload.cs | 8 +++ .../Repository/IRepository.cs | 18 +++-- .../Repository/Repository.cs | 67 ++++++++++++++++--- .../api-cinema-challenge/ViewModel/Payload.cs | 6 -- .../api-cinema-challenge.csproj | 2 +- 7 files changed, 143 insertions(+), 25 deletions(-) create mode 100644 api-cinema-challenge/api-cinema-challenge/DTOs/MovieDTO.cs create mode 100644 api-cinema-challenge/api-cinema-challenge/Payload/Payload.cs delete mode 100644 api-cinema-challenge/api-cinema-challenge/ViewModel/Payload.cs diff --git a/api-cinema-challenge/api-cinema-challenge/DTOs/MovieDTO.cs b/api-cinema-challenge/api-cinema-challenge/DTOs/MovieDTO.cs new file mode 100644 index 00000000..a4e530ee --- /dev/null +++ b/api-cinema-challenge/api-cinema-challenge/DTOs/MovieDTO.cs @@ -0,0 +1,13 @@ +namespace api_cinema_challenge.DTOs +{ + public class MovieDTO + { + public string Title { get; set; } + + public string Rating { get; set; } + + public string Description { get; set; } + + public int RuntimeMins { get; set; } + } +} diff --git a/api-cinema-challenge/api-cinema-challenge/Endpoints/CinemaEndpoints.cs b/api-cinema-challenge/api-cinema-challenge/Endpoints/CinemaEndpoints.cs index 3557cb7f..54a954d9 100644 --- a/api-cinema-challenge/api-cinema-challenge/Endpoints/CinemaEndpoints.cs +++ b/api-cinema-challenge/api-cinema-challenge/Endpoints/CinemaEndpoints.cs @@ -1,4 +1,7 @@ -using api_cinema_challenge.Repository; +using api_cinema_challenge.DTOs; +using api_cinema_challenge.Models; +using api_cinema_challenge.Payload; +using api_cinema_challenge.Repository; using Microsoft.AspNetCore.Mvc; namespace api_cinema_challenge.Endpoints @@ -8,16 +11,61 @@ public static class CinemaEndpoints public static void ConfigureCinemaEndpoint(this WebApplication app) { var cinemaGroup = app.MapGroup("cinema"); - cinemaGroup.MapGet("/movies", GetMovies); + cinemaGroup.MapGet("/movies/{id}", GetMovie); + cinemaGroup.MapPost("/movies", CreateMovie); + cinemaGroup.MapPut("/movies/{id}", UpdateMovie); + cinemaGroup.MapDelete("/movies/{id}", DeleteMovie); } + [ProducesResponseType(StatusCodes.Status200OK)] public static async Task GetMovies(IRepository repository) { var movies = await repository.GetMovies(); - return Results.Ok(movies); + return Results.Ok(await repository.GeneratePayload(movies)); + } + + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public static async Task GetMovie(IRepository repository, int id) + { + var movie = await repository.GetMovie(id); + if(movie == null) + { + return TypedResults.NotFound(await repository.GenerateErrorPayload(movie, $"Movie with id {id} was not found")); + } + + var resp = await repository.GeneratePayload(movie); + + return Results.Ok(resp); } + [ProducesResponseType(StatusCodes.Status201Created)] + public static async Task CreateMovie(IRepository repository, MovieDTO? movie) + { + + var movieCreated = await repository.CreateMovie(movie); + return Results.Created($"/cinema/movies/{movieCreated.Id}", await repository.GeneratePayload(movieCreated)); + } + [ProducesResponseType(StatusCodes.Status201Created)] + public static async Task UpdateMovie(IRepository repository, int id, MovieDTO? movie) + { + var updatedMovie = await repository.UpdateMovie(id, movie); + return Results.Created($"/cinema/movies/{updatedMovie.Id}", await repository.GeneratePayload(updatedMovie)); + + } + [ProducesResponseType(StatusCodes.Status200OK)] + public static async Task DeleteMovie(IRepository repository, int id) + { + var deletedMovie = await repository.DeleteMovie(id); + if (deletedMovie == null) + { + return Results.BadRequest(await repository.GenerateErrorPayload(deletedMovie, $"Movie with id {id} was not found")); + } + + return Results.Ok(await repository.GeneratePayload(deletedMovie)); + + } } } diff --git a/api-cinema-challenge/api-cinema-challenge/Payload/Payload.cs b/api-cinema-challenge/api-cinema-challenge/Payload/Payload.cs new file mode 100644 index 00000000..b30423cc --- /dev/null +++ b/api-cinema-challenge/api-cinema-challenge/Payload/Payload.cs @@ -0,0 +1,8 @@ +namespace api_cinema_challenge.Payload +{ + public class ApiResponse + { + public string Status { get; set; } + public T Data { get; set; } + } +} \ No newline at end of file diff --git a/api-cinema-challenge/api-cinema-challenge/Repository/IRepository.cs b/api-cinema-challenge/api-cinema-challenge/Repository/IRepository.cs index 85b8effc..fe9b65cf 100644 --- a/api-cinema-challenge/api-cinema-challenge/Repository/IRepository.cs +++ b/api-cinema-challenge/api-cinema-challenge/Repository/IRepository.cs @@ -1,4 +1,6 @@ -using api_cinema_challenge.Models; +using api_cinema_challenge.DTOs; +using api_cinema_challenge.Models; +using api_cinema_challenge.Payload; namespace api_cinema_challenge.Repository { @@ -12,11 +14,11 @@ public interface IRepository Task DeleteCustomer(int id); // Movies - Task> GetMovies(); - Task GetMovie(int id); - Task CreateMovie(Movie movie); - Task UpdateMovie(int id, Movie movie); - Task DeleteMovie(int id); + Task> GetMovies(); // + Task GetMovie(int id); // + Task CreateMovie(MovieDTO movie); + Task UpdateMovie(int id, MovieDTO movie); + Task DeleteMovie(int id); // Screenings Task> GetScreenings(); @@ -32,6 +34,10 @@ public interface IRepository Task UpdateTicket(int id, Ticket ticket); Task DeleteTicket(int id); + // MISC + Task> GeneratePayload(T data); + Task> GenerateErrorPayload(T data, string message); + } } diff --git a/api-cinema-challenge/api-cinema-challenge/Repository/Repository.cs b/api-cinema-challenge/api-cinema-challenge/Repository/Repository.cs index 3a0a7301..4c8e2281 100644 --- a/api-cinema-challenge/api-cinema-challenge/Repository/Repository.cs +++ b/api-cinema-challenge/api-cinema-challenge/Repository/Repository.cs @@ -1,5 +1,7 @@ using api_cinema_challenge.Data; +using api_cinema_challenge.DTOs; using api_cinema_challenge.Models; +using api_cinema_challenge.Payload; using Microsoft.EntityFrameworkCore; namespace api_cinema_challenge.Repository @@ -45,21 +47,52 @@ public async Task> GetMovies() { return await _db.Movies.ToListAsync(); } - public Task GetMovie(int id) + public async Task GetMovie(int id) { - throw new NotImplementedException(); + return await _db.Movies.FirstOrDefaultAsync(m => m.Id == id); } - public Task CreateMovie(Movie movie) + public async Task CreateMovie(MovieDTO movieDTO) { - throw new NotImplementedException(); + Movie movie = new Movie() + { + Title = movieDTO.Title, + Rating = movieDTO.Rating, + RuntimeMins = movieDTO.RuntimeMins, + Description = movieDTO.Description, + CreatedAt = DateTime.UtcNow, + UpdatedAt = DateTime.UtcNow + }; + await _db.AddAsync(movie); + await _db.SaveChangesAsync(); + return movie; } - public Task UpdateMovie(int id, Movie movie) + public async Task UpdateMovie(int id, MovieDTO movie) { - throw new NotImplementedException(); + var movieToUpdate = await _db.Movies.FirstOrDefaultAsync(m => m.Id == id); + + if (movieToUpdate == null) + { + return null; + } + movieToUpdate.Title = movie.Title; + movieToUpdate.Rating = movie.Rating; + movieToUpdate.RuntimeMins = movie.RuntimeMins; + movieToUpdate.Description = movie.Description; + movieToUpdate.UpdatedAt = DateTime.UtcNow; + await _db.SaveChangesAsync(); + + return movieToUpdate; } - public Task DeleteMovie(int id) + public async Task DeleteMovie(int id) { - throw new NotImplementedException(); + var movieToDelete = await _db.Movies.FirstOrDefaultAsync(m => m.Id == id); + if(movieToDelete == null) + { + return null; + } + _db.Movies.Remove(movieToDelete); + await _db.SaveChangesAsync(); + return movieToDelete; } // SCREENINGS _______________________________________________________ @@ -111,6 +144,22 @@ public Task DeleteTicket(int id) throw new NotImplementedException(); } - + // MISC _______________________________________________________ + public Task> GeneratePayload(T data) + { + return Task.FromResult(new ApiResponse + { + Status = "success", + Data = data + }); + } + public Task> GenerateErrorPayload(T data, string message) + { + return Task.FromResult(new ApiResponse + { + Status = message, + Data = data + }); + } } } diff --git a/api-cinema-challenge/api-cinema-challenge/ViewModel/Payload.cs b/api-cinema-challenge/api-cinema-challenge/ViewModel/Payload.cs deleted file mode 100644 index 074f9700..00000000 --- a/api-cinema-challenge/api-cinema-challenge/ViewModel/Payload.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace api_cinema_challenge.ViewModel -{ - public class Payload - { - } -} diff --git a/api-cinema-challenge/api-cinema-challenge/api-cinema-challenge.csproj b/api-cinema-challenge/api-cinema-challenge/api-cinema-challenge.csproj index f1ad9610..aa6d5990 100644 --- a/api-cinema-challenge/api-cinema-challenge/api-cinema-challenge.csproj +++ b/api-cinema-challenge/api-cinema-challenge/api-cinema-challenge.csproj @@ -34,8 +34,8 @@ - + From b41f92142f1d6ad5bb65c88364dcd0dab6cc11f8 Mon Sep 17 00:00:00 2001 From: GRehan Date: Wed, 29 Jan 2025 11:52:18 +0100 Subject: [PATCH 5/6] Customer, Movie And Screenings completed --- .../api-cinema-challenge/DTOs/CustomerDTO.cs | 12 ++ .../api-cinema-challenge/DTOs/MovieDTO.cs | 6 +- .../api-cinema-challenge/DTOs/ScreeningDTO.cs | 10 ++ .../Endpoints/CinemaEndpoints.cs | 114 ++++++++++++++++-- .../api-cinema-challenge/Models/Movie.cs | 5 + .../Repository/IRepository.cs | 10 +- .../Repository/Repository.cs | 98 +++++++++++---- .../api-cinema-challenge.csproj | 5 +- 8 files changed, 217 insertions(+), 43 deletions(-) create mode 100644 api-cinema-challenge/api-cinema-challenge/DTOs/CustomerDTO.cs create mode 100644 api-cinema-challenge/api-cinema-challenge/DTOs/ScreeningDTO.cs diff --git a/api-cinema-challenge/api-cinema-challenge/DTOs/CustomerDTO.cs b/api-cinema-challenge/api-cinema-challenge/DTOs/CustomerDTO.cs new file mode 100644 index 00000000..86057d12 --- /dev/null +++ b/api-cinema-challenge/api-cinema-challenge/DTOs/CustomerDTO.cs @@ -0,0 +1,12 @@ +using System.ComponentModel.DataAnnotations.Schema; +using System.ComponentModel.DataAnnotations; + +namespace api_cinema_challenge.DTOs +{ + public class CustomerDTO + { + public string Name { get; set; } + public string Email { get; set; } + public string Phone { get; set; } + } +} diff --git a/api-cinema-challenge/api-cinema-challenge/DTOs/MovieDTO.cs b/api-cinema-challenge/api-cinema-challenge/DTOs/MovieDTO.cs index a4e530ee..6bfdbc19 100644 --- a/api-cinema-challenge/api-cinema-challenge/DTOs/MovieDTO.cs +++ b/api-cinema-challenge/api-cinema-challenge/DTOs/MovieDTO.cs @@ -1,4 +1,6 @@ -namespace api_cinema_challenge.DTOs +using api_cinema_challenge.Models; + +namespace api_cinema_challenge.DTOs { public class MovieDTO { @@ -9,5 +11,7 @@ public class MovieDTO public string Description { get; set; } public int RuntimeMins { get; set; } + + public List? Screenings { get; set; } } } diff --git a/api-cinema-challenge/api-cinema-challenge/DTOs/ScreeningDTO.cs b/api-cinema-challenge/api-cinema-challenge/DTOs/ScreeningDTO.cs new file mode 100644 index 00000000..f03ed1df --- /dev/null +++ b/api-cinema-challenge/api-cinema-challenge/DTOs/ScreeningDTO.cs @@ -0,0 +1,10 @@ +namespace api_cinema_challenge.DTOs +{ + public class ScreeningDTO + { + public int ScreenNumber { get; set; } + public int Capacity { get; set; } + public DateTime StartsAt { get; set; } + + } +} diff --git a/api-cinema-challenge/api-cinema-challenge/Endpoints/CinemaEndpoints.cs b/api-cinema-challenge/api-cinema-challenge/Endpoints/CinemaEndpoints.cs index 54a954d9..e0b2fa48 100644 --- a/api-cinema-challenge/api-cinema-challenge/Endpoints/CinemaEndpoints.cs +++ b/api-cinema-challenge/api-cinema-challenge/Endpoints/CinemaEndpoints.cs @@ -10,12 +10,27 @@ public static class CinemaEndpoints { public static void ConfigureCinemaEndpoint(this WebApplication app) { - var cinemaGroup = app.MapGroup("cinema"); - cinemaGroup.MapGet("/movies", GetMovies); - cinemaGroup.MapGet("/movies/{id}", GetMovie); - cinemaGroup.MapPost("/movies", CreateMovie); - cinemaGroup.MapPut("/movies/{id}", UpdateMovie); - cinemaGroup.MapDelete("/movies/{id}", DeleteMovie); + + + var movieGroup = app.MapGroup("movies"); + movieGroup.MapGet("/", GetMovies); + movieGroup.MapGet("/{id}", GetMovie); + movieGroup.MapPost("/", CreateMovie); + movieGroup.MapPut("/{id}", UpdateMovie); + movieGroup.MapDelete("/{id}", DeleteMovie); + //screenings for movies + movieGroup.MapPost("/{movieId}/screenings", CreateScreening); + movieGroup.MapGet("/{id}/screenings", GetScreenings); + + + + var customerGroup = app.MapGroup("customers"); + customerGroup.MapGet("/", GetCustomers); + customerGroup.MapGet("/{id}", GetCustomer); + customerGroup.MapPost("/", CreateCustomer); + customerGroup.MapPut("/{id}", UpdateCustomer); + customerGroup.MapDelete("/{id}", DeleteCustomer); + } @@ -31,7 +46,7 @@ public static async Task GetMovies(IRepository repository) public static async Task GetMovie(IRepository repository, int id) { var movie = await repository.GetMovie(id); - if(movie == null) + if (movie == null) { return TypedResults.NotFound(await repository.GenerateErrorPayload(movie, $"Movie with id {id} was not found")); } @@ -46,13 +61,13 @@ public static async Task CreateMovie(IRepository repository, MovieDTO? { var movieCreated = await repository.CreateMovie(movie); - return Results.Created($"/cinema/movies/{movieCreated.Id}", await repository.GeneratePayload(movieCreated)); + return Results.Created($"movies/{movieCreated.Id}", await repository.GeneratePayload(movieCreated)); } [ProducesResponseType(StatusCodes.Status201Created)] public static async Task UpdateMovie(IRepository repository, int id, MovieDTO? movie) { var updatedMovie = await repository.UpdateMovie(id, movie); - return Results.Created($"/cinema/movies/{updatedMovie.Id}", await repository.GeneratePayload(updatedMovie)); + return Results.Created($"movies/{updatedMovie.Id}", await repository.GeneratePayload(updatedMovie)); } [ProducesResponseType(StatusCodes.Status200OK)] @@ -61,11 +76,90 @@ public static async Task DeleteMovie(IRepository repository, int id) var deletedMovie = await repository.DeleteMovie(id); if (deletedMovie == null) { - return Results.BadRequest(await repository.GenerateErrorPayload(deletedMovie, $"Movie with id {id} was not found")); + return Results.NotFound(await repository.GenerateErrorPayload(deletedMovie, $"Movie with id {id} was not found")); } return Results.Ok(await repository.GeneratePayload(deletedMovie)); } + + // Screenings for movies + + [ProducesResponseType(StatusCodes.Status201Created)] + public static async Task CreateScreening(IRepository repository, int movieId, ScreeningDTO screeningDTO) + { + var movie = await repository.GetMovie(movieId); + if(movie == null) + { + return Results.NotFound(await repository.GenerateErrorPayload(movie, $"Movie with id {movieId} was not found")); + } + + + var screeningCreated = await repository.CreateScreening(screeningDTO, movieId); + return Results.Created($"/movies/{movieId}/screenings", await repository.GeneratePayload(screeningCreated)); + } + + [ProducesResponseType(StatusCodes.Status200OK)] + public static async Task GetScreenings(IRepository repository, int movieId) + { + var screenings = await repository.GetScreenings(movieId); + return Results.Ok(await repository.GeneratePayload(screenings)); + + } + + + + // Customers + + [ProducesResponseType(StatusCodes.Status200OK)] + public static async Task GetCustomers(IRepository repository) + { + var customers = await repository.GetCustomers(); + return Results.Ok(await repository.GeneratePayload(customers)); + } + + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public static async Task GetCustomer(IRepository repository, int id) + { + var customer = await repository.GetCustomer(id); + if (customer == null) + { + return TypedResults.NotFound(await repository.GenerateErrorPayload(customer, $"Customer with id {id} was not found")); + } + + var resp = await repository.GeneratePayload(customer); + + return Results.Ok(resp); + } + + [ProducesResponseType(StatusCodes.Status201Created)] + public static async Task CreateCustomer(IRepository repository, CustomerDTO? customerDTO) + { + + var customerCreated = await repository.CreateCustomer(customerDTO); + return Results.Created($"/cinema/movies/{customerCreated.Id}", await repository.GeneratePayload(customerCreated)); + } + [ProducesResponseType(StatusCodes.Status201Created)] + public static async Task UpdateCustomer(IRepository repository, int id, CustomerDTO? customer) + { + var updatedCustomer = await repository.UpdateCustomer(id, customer); + return Results.Created($"/cinema/movies/{updatedCustomer.Id}", await repository.GeneratePayload(updatedCustomer)); + + } + [ProducesResponseType(StatusCodes.Status200OK)] + public static async Task DeleteCustomer(IRepository repository, int id) + { + var deletedCustomer = await repository.DeleteCustomer(id); + if (deletedCustomer == null) + { + return Results.BadRequest(await repository.GenerateErrorPayload(deletedCustomer, $"Customer with id {id} was not found")); + } + + return Results.Ok(await repository.GeneratePayload(deletedCustomer)); + } + + + } } diff --git a/api-cinema-challenge/api-cinema-challenge/Models/Movie.cs b/api-cinema-challenge/api-cinema-challenge/Models/Movie.cs index 87fca615..5c47851c 100644 --- a/api-cinema-challenge/api-cinema-challenge/Models/Movie.cs +++ b/api-cinema-challenge/api-cinema-challenge/Models/Movie.cs @@ -1,5 +1,6 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using System.Text.Json.Serialization; namespace api_cinema_challenge.Models { @@ -27,5 +28,9 @@ public class Movie [Column("UpdatedAt")] public DateTime UpdatedAt { get; set; } + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + + public List? Screenings { get; set; } + } } diff --git a/api-cinema-challenge/api-cinema-challenge/Repository/IRepository.cs b/api-cinema-challenge/api-cinema-challenge/Repository/IRepository.cs index fe9b65cf..083c98c5 100644 --- a/api-cinema-challenge/api-cinema-challenge/Repository/IRepository.cs +++ b/api-cinema-challenge/api-cinema-challenge/Repository/IRepository.cs @@ -9,8 +9,8 @@ public interface IRepository // Customers Task> GetCustomers(); Task GetCustomer(int id); - Task CreateCustomer(Customer customer); - Task UpdateCustomer(int id, Customer customer); + Task CreateCustomer(CustomerDTO customer); + Task UpdateCustomer(int id, CustomerDTO customer); Task DeleteCustomer(int id); // Movies @@ -21,11 +21,9 @@ public interface IRepository Task DeleteMovie(int id); // Screenings - Task> GetScreenings(); + Task?> GetScreenings(int id); Task GetScreening(int id); - Task CreateScreening(Screening screening); - Task UpdateScreening(int id, Screening screening); - Task DeleteScreening(int id); + Task CreateScreening(ScreeningDTO? screening, int movieId); // Tickets Task> GetTickets(); diff --git a/api-cinema-challenge/api-cinema-challenge/Repository/Repository.cs b/api-cinema-challenge/api-cinema-challenge/Repository/Repository.cs index 4c8e2281..a7266196 100644 --- a/api-cinema-challenge/api-cinema-challenge/Repository/Repository.cs +++ b/api-cinema-challenge/api-cinema-challenge/Repository/Repository.cs @@ -17,27 +17,57 @@ public Repository(CinemaContext db) // CUSTOMERS _______________________________________________________ - public Task> GetCustomers() + public async Task> GetCustomers() { - throw new NotImplementedException(); + return await _db.Customers.ToListAsync(); } - public Task GetCustomer(int id) + public async Task GetCustomer(int id) { - throw new NotImplementedException(); + return await _db.Customers.FirstOrDefaultAsync(c => c.Id == id); } - public Task CreateCustomer(Customer customer) + public async Task CreateCustomer(CustomerDTO customerDTO) { - throw new NotImplementedException(); + Customer customer = new Customer() + { + Name = customerDTO.Name, + Email = customerDTO.Email, + Phone = customerDTO.Phone, + CreatedAt = DateTime.UtcNow, + UpdatedAt = DateTime.UtcNow + }; + + await _db.AddAsync(customer); + await _db.SaveChangesAsync(); + return customer; } - public Task UpdateCustomer(int id, Customer customer) + public async Task UpdateCustomer(int id, CustomerDTO customer) { - throw new NotImplementedException(); + var customerToUpdate = await _db.Customers.FirstOrDefaultAsync(m => m.Id == id); + + if (customerToUpdate == null) + { + return null; + } + customerToUpdate.Name = customer.Name; + customerToUpdate.Email = customer.Email; + customerToUpdate.Phone = customer.Phone; + customerToUpdate.UpdatedAt = DateTime.UtcNow; + await _db.SaveChangesAsync(); + + return customerToUpdate; } - public Task DeleteCustomer(int id) + public async Task DeleteCustomer(int id) { - throw new NotImplementedException(); + var customerToDelete = await _db.Customers.FirstOrDefaultAsync(m => m.Id == id); + if (customerToDelete == null) + { + return null; + } + _db.Customers.Remove(customerToDelete); + await _db.SaveChangesAsync(); + return customerToDelete; } // MOVIES _______________________________________________________ @@ -62,8 +92,18 @@ public async Task CreateMovie(MovieDTO movieDTO) CreatedAt = DateTime.UtcNow, UpdatedAt = DateTime.UtcNow }; + + await _db.AddAsync(movie); await _db.SaveChangesAsync(); + + if (movieDTO.Screenings != null) + { + foreach (var s in movieDTO.Screenings) + { + await this.CreateScreening(s, movie.Id); + } + } return movie; } public async Task UpdateMovie(int id, MovieDTO movie) @@ -96,26 +136,34 @@ public async Task CreateMovie(MovieDTO movieDTO) } // SCREENINGS _______________________________________________________ - public Task> GetScreenings() - { - throw new NotImplementedException(); - } - public Task GetScreening(int id) + public async Task?> GetScreenings(int movieId) { - throw new NotImplementedException(); - } - public Task CreateScreening(Screening screening) - { - throw new NotImplementedException(); + var movie = await this.GetMovie(movieId); + if(movie == null) + { + return null; + } + + return await _db.Screenings.Where(s => s.MovieId == movieId).ToListAsync(); } - public Task UpdateScreening(int id, Screening screening) + public async Task GetScreening(int id) { - throw new NotImplementedException(); + return await _db.Screenings.FirstOrDefaultAsync(s => s.Id == id); } - - public Task DeleteScreening(int id) + public async Task CreateScreening(ScreeningDTO screeningDTO, int movieId) { - throw new NotImplementedException(); + Screening screening = new Screening() + { + ScreenNumber = screeningDTO.ScreenNumber, + Capacity = screeningDTO.Capacity, + StartsAt = screeningDTO.StartsAt, + MovieId = movieId, + CreatedAt = DateTime.UtcNow, + UpdatedAt = DateTime.UtcNow + }; + await _db.AddAsync(screening); + await _db.SaveChangesAsync(); + return screening; } // TICKETS _______________________________________________________ diff --git a/api-cinema-challenge/api-cinema-challenge/api-cinema-challenge.csproj b/api-cinema-challenge/api-cinema-challenge/api-cinema-challenge.csproj index aa6d5990..f10a597e 100644 --- a/api-cinema-challenge/api-cinema-challenge/api-cinema-challenge.csproj +++ b/api-cinema-challenge/api-cinema-challenge/api-cinema-challenge.csproj @@ -9,9 +9,13 @@ + + + + @@ -34,7 +38,6 @@ - From b049b3cef5a1673081ac7ea4f6e4cc160eba504c Mon Sep 17 00:00:00 2001 From: GRehan Date: Wed, 29 Jan 2025 12:37:13 +0100 Subject: [PATCH 6/6] Finished Core & Extension --- .../api-cinema-challenge/DTOs/TicketDTO.cs | 8 + .../Data/CinemaContext.cs | 192 +++++++++--------- .../Endpoints/CinemaEndpoints.cs | 38 +++- .../api-cinema-challenge/Models/Ticket.cs | 3 +- .../Repository/IRepository.cs | 7 +- .../Repository/Repository.cs | 35 ++-- 6 files changed, 160 insertions(+), 123 deletions(-) create mode 100644 api-cinema-challenge/api-cinema-challenge/DTOs/TicketDTO.cs diff --git a/api-cinema-challenge/api-cinema-challenge/DTOs/TicketDTO.cs b/api-cinema-challenge/api-cinema-challenge/DTOs/TicketDTO.cs new file mode 100644 index 00000000..948b0f22 --- /dev/null +++ b/api-cinema-challenge/api-cinema-challenge/DTOs/TicketDTO.cs @@ -0,0 +1,8 @@ +namespace api_cinema_challenge.DTOs +{ + public class TicketDTO + { + public int NumSeats { get; set; } + + } +} diff --git a/api-cinema-challenge/api-cinema-challenge/Data/CinemaContext.cs b/api-cinema-challenge/api-cinema-challenge/Data/CinemaContext.cs index 5b13de6d..a217886a 100644 --- a/api-cinema-challenge/api-cinema-challenge/Data/CinemaContext.cs +++ b/api-cinema-challenge/api-cinema-challenge/Data/CinemaContext.cs @@ -125,104 +125,104 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) } ); modelBuilder.Entity().HasData( - new Screening - { - Id = 1, - MovieId = 1, - ScreenNumber = 1, - Capacity = 100, - StartsAt = now.AddHours(2), - CreatedAt = now, - UpdatedAt = now - }, - new Screening - { - Id = 2, - MovieId = 4, - ScreenNumber = 2, - Capacity = 80, - StartsAt = now.AddHours(3), - CreatedAt = now, - UpdatedAt = now - }, - new Screening - { - Id = 3, - MovieId = 5, - ScreenNumber = 3, - Capacity = 120, - StartsAt = now.AddDays(1).AddHours(2), - CreatedAt = now, - UpdatedAt = now - }, - new Screening - { - Id = 4, - MovieId = 3, - ScreenNumber = 1, - Capacity = 90, - StartsAt = now.AddDays(1).AddHours(5), - CreatedAt = now, - UpdatedAt = now - }, - new Screening - { - Id = 5, - MovieId = 3, - ScreenNumber = 2, - Capacity = 110, - StartsAt = now.AddHours(6), - CreatedAt = now, - UpdatedAt = now - } + new Screening + { + Id = 1, + MovieId = 1, + ScreenNumber = 1, + Capacity = 100, + StartsAt = now.AddHours(2), + CreatedAt = now, + UpdatedAt = now + }, + new Screening + { + Id = 2, + MovieId = 4, + ScreenNumber = 2, + Capacity = 80, + StartsAt = now.AddHours(3), + CreatedAt = now, + UpdatedAt = now + }, + new Screening + { + Id = 3, + MovieId = 5, + ScreenNumber = 3, + Capacity = 120, + StartsAt = now.AddDays(1).AddHours(2), + CreatedAt = now, + UpdatedAt = now + }, + new Screening + { + Id = 4, + MovieId = 3, + ScreenNumber = 1, + Capacity = 90, + StartsAt = now.AddDays(1).AddHours(5), + CreatedAt = now, + UpdatedAt = now + }, + new Screening + { + Id = 5, + MovieId = 3, + ScreenNumber = 2, + Capacity = 110, + StartsAt = now.AddHours(6), + CreatedAt = now, + UpdatedAt = now + } ); modelBuilder.Entity().HasData( - new Ticket - { - Id = 1, - ScreeningId = 1, - CustomerId = 1, - NumSeats = 2, - CreatedAt = now, - UpdatedAt = now - }, - new Ticket - { - Id = 2, - ScreeningId = 2, - CustomerId = 2, - NumSeats = 1, - CreatedAt = now, - UpdatedAt = now - }, - new Ticket - { - Id = 3, - ScreeningId = 3, - CustomerId = 3, - NumSeats = 4, - CreatedAt = now, - UpdatedAt = now - }, - new Ticket - { - Id = 4, - ScreeningId = 4, - CustomerId = 4, - NumSeats = 3, - CreatedAt = now, - UpdatedAt = now - }, - new Ticket - { - Id = 5, - ScreeningId = 5, - CustomerId = 5, - NumSeats = 2, - CreatedAt = now, - UpdatedAt = now - } - ); + new Ticket + { + Id = 1, + ScreeningId = 1, + CustomerId = 1, + NumSeats = 2, + CreatedAt = now, + UpdatedAt = now + }, + new Ticket + { + Id = 2, + ScreeningId = 2, + CustomerId = 2, + NumSeats = 1, + CreatedAt = now, + UpdatedAt = now + }, + new Ticket + { + Id = 3, + ScreeningId = 3, + CustomerId = 3, + NumSeats = 4, + CreatedAt = now, + UpdatedAt = now + }, + new Ticket + { + Id = 4, + ScreeningId = 4, + CustomerId = 4, + NumSeats = 3, + CreatedAt = now, + UpdatedAt = now + }, + new Ticket + { + Id = 5, + ScreeningId = 5, + CustomerId = 5, + NumSeats = 2, + CreatedAt = now, + UpdatedAt = now + } + ); } public DbSet Customers { get; set; } diff --git a/api-cinema-challenge/api-cinema-challenge/Endpoints/CinemaEndpoints.cs b/api-cinema-challenge/api-cinema-challenge/Endpoints/CinemaEndpoints.cs index e0b2fa48..4b1dc079 100644 --- a/api-cinema-challenge/api-cinema-challenge/Endpoints/CinemaEndpoints.cs +++ b/api-cinema-challenge/api-cinema-challenge/Endpoints/CinemaEndpoints.cs @@ -10,8 +10,6 @@ public static class CinemaEndpoints { public static void ConfigureCinemaEndpoint(this WebApplication app) { - - var movieGroup = app.MapGroup("movies"); movieGroup.MapGet("/", GetMovies); movieGroup.MapGet("/{id}", GetMovie); @@ -20,7 +18,7 @@ public static void ConfigureCinemaEndpoint(this WebApplication app) movieGroup.MapDelete("/{id}", DeleteMovie); //screenings for movies movieGroup.MapPost("/{movieId}/screenings", CreateScreening); - movieGroup.MapGet("/{id}/screenings", GetScreenings); + movieGroup.MapGet("/{movieId}/screenings", GetScreenings); @@ -30,6 +28,10 @@ public static void ConfigureCinemaEndpoint(this WebApplication app) customerGroup.MapPost("/", CreateCustomer); customerGroup.MapPut("/{id}", UpdateCustomer); customerGroup.MapDelete("/{id}", DeleteCustomer); + // tickets + customerGroup.MapPost("/{customerId}/screenings/{screeningId}", CreateTicket); + customerGroup.MapGet("/{customerId}/screenings/{screeningId}", GetTickets); + } @@ -153,13 +155,41 @@ public static async Task DeleteCustomer(IRepository repository, int id) var deletedCustomer = await repository.DeleteCustomer(id); if (deletedCustomer == null) { - return Results.BadRequest(await repository.GenerateErrorPayload(deletedCustomer, $"Customer with id {id} was not found")); + return Results.NotFound(await repository.GenerateErrorPayload(deletedCustomer, $"Customer with id {id} was not found")); } return Results.Ok(await repository.GeneratePayload(deletedCustomer)); } + // tickets for customers + [ProducesResponseType(StatusCodes.Status201Created)] + public static async Task CreateTicket(IRepository repository, int customerId, int screeningId, TicketDTO ticketDTO) + { + var customer = await repository.GetCustomer(customerId); + if (customer == null) + { + return Results.NotFound(await repository.GenerateErrorPayload(customer, $"Customer with id {customerId} was not found")); + } + + var screening = await repository.GetScreening(screeningId); + if (screening == null) + { + return Results.NotFound(await repository.GenerateErrorPayload(screening, $"Screening with id {screeningId} was not found")); + } + + var ticket = await repository.CreateTicket(customer.Id, screening.Id, ticketDTO); + + return Results.Created($"/customers/{customerId}/screenings/{screeningId}", await repository.GeneratePayload(ticket)); + } + + [ProducesResponseType(StatusCodes.Status200OK)] + public static async Task GetTickets(IRepository repository, int customerId, int screeningId) + { + var tickets = await repository.GetTickets(customerId, screeningId); + return Results.Ok(await repository.GeneratePayload(tickets)); + + } } } diff --git a/api-cinema-challenge/api-cinema-challenge/Models/Ticket.cs b/api-cinema-challenge/api-cinema-challenge/Models/Ticket.cs index 29ff5d0b..ecdf0651 100644 --- a/api-cinema-challenge/api-cinema-challenge/Models/Ticket.cs +++ b/api-cinema-challenge/api-cinema-challenge/Models/Ticket.cs @@ -24,6 +24,7 @@ public class Ticket [Column("UpdatedAt")] public DateTime UpdatedAt { get; set; } - + public Customer customer { get; set; } + public Screening screening { get; set; } } } diff --git a/api-cinema-challenge/api-cinema-challenge/Repository/IRepository.cs b/api-cinema-challenge/api-cinema-challenge/Repository/IRepository.cs index 083c98c5..b3a937b1 100644 --- a/api-cinema-challenge/api-cinema-challenge/Repository/IRepository.cs +++ b/api-cinema-challenge/api-cinema-challenge/Repository/IRepository.cs @@ -26,11 +26,8 @@ public interface IRepository Task CreateScreening(ScreeningDTO? screening, int movieId); // Tickets - Task> GetTickets(); - Task GetTicket(int id); - Task CreateTicket(Ticket ticket); - Task UpdateTicket(int id, Ticket ticket); - Task DeleteTicket(int id); + Task> GetTickets(int customerId, int screeningId); + Task CreateTicket(int customerId, int screeningId, TicketDTO ticketDTO); // MISC Task> GeneratePayload(T data); diff --git a/api-cinema-challenge/api-cinema-challenge/Repository/Repository.cs b/api-cinema-challenge/api-cinema-challenge/Repository/Repository.cs index a7266196..e4f412d9 100644 --- a/api-cinema-challenge/api-cinema-challenge/Repository/Repository.cs +++ b/api-cinema-challenge/api-cinema-challenge/Repository/Repository.cs @@ -146,10 +146,12 @@ public async Task CreateMovie(MovieDTO movieDTO) return await _db.Screenings.Where(s => s.MovieId == movieId).ToListAsync(); } + public async Task GetScreening(int id) { return await _db.Screenings.FirstOrDefaultAsync(s => s.Id == id); } + public async Task CreateScreening(ScreeningDTO screeningDTO, int movieId) { Screening screening = new Screening() @@ -169,30 +171,29 @@ public async Task CreateScreening(ScreeningDTO screeningDTO, int movi // TICKETS _______________________________________________________ - public Task> GetTickets() + public async Task> GetTickets(int customerId, int screeningId) { - throw new NotImplementedException(); + return await _db.Tickets.Where(t => t.CustomerId == customerId && t.ScreeningId == screeningId).ToListAsync(); } - public Task GetTicket(int id) + public async Task CreateTicket(int customerId, int screeningId, TicketDTO ticketDTO) { - throw new NotImplementedException(); - } + Ticket ticket = new Ticket() + { + CustomerId = customerId, + ScreeningId = screeningId, + NumSeats = ticketDTO.NumSeats, + CreatedAt = DateTime.UtcNow, + UpdatedAt= DateTime.UtcNow, + }; - public Task CreateTicket(Ticket ticket) - { - throw new NotImplementedException(); - } - public Task UpdateTicket(int id, Ticket ticket) - { - throw new NotImplementedException(); - } - public Task DeleteTicket(int id) - { - throw new NotImplementedException(); + await _db.AddAsync(ticket); + await _db.SaveChangesAsync(); + + return ticket; } - // MISC _______________________________________________________ + // Payload _______________________________________________________ public Task> GeneratePayload(T data) { return Task.FromResult(new ApiResponse