Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -482,3 +482,4 @@ $RECYCLE.BIN/
*/**/obj/Release
/exercise.pizzashopapi/appsettings.json
/exercise.pizzashopapi/appsettings.Development.json
*/**/Migrations
6 changes: 6 additions & 0 deletions exercise.pizzashopapi/DTO/Customer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace exercise.pizzashopapi.DTO
{
public record CustomerPost(string Name);
public record CustomerView(int Id, string Name, IEnumerable<OrderProductToppings> Orders);
public record CustomerInternal(int Id, string Name);
}
25 changes: 25 additions & 0 deletions exercise.pizzashopapi/DTO/Order.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
namespace exercise.pizzashopapi.DTO
{
public record OrderPost(int ProductId, int CustomerId);
public record OrderPostAddTopping(int ToppingId);
public record OrderView(
int Id, decimal TotalPrice, bool IsDelivered, string PreparationStage,
DateTime CreatedAt, DateTime StartedAt, DateTime CompletedAt,
CustomerInternal Customer, ProductView Product, IEnumerable<ToppingInternal> Toppings
);
public record OrderProduct(
int Id, decimal TotalPrice, bool IsDelivered, string PreparationStage,
DateTime CreatedAt, DateTime StartedAt, DateTime CompletedAt,
ProductView Product
);
public record OrderProductToppings(
int Id, decimal TotalPrice, bool IsDelivered, string PreparationStage,
DateTime CreatedAt, DateTime StartedAt, DateTime CompletedAt,
ProductView Product, IEnumerable<ToppingInternal> Toppings
);
public record OrderCustomerProduct(
int Id, decimal TotalPrice, bool IsDelivered, string PreparationStage,
DateTime CreatedAt, DateTime StartedAt, DateTime CompletedAt,
CustomerInternal Customer, ProductView Product
);
}
4 changes: 4 additions & 0 deletions exercise.pizzashopapi/DTO/Product.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
namespace exercise.pizzashopapi.DTO
{
public record ProductView(int Id, string ProductType, string Name, decimal Price);
}
5 changes: 5 additions & 0 deletions exercise.pizzashopapi/DTO/Topping.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace exercise.pizzashopapi.DTO
{
public record ToppingView(int Id, string Name, decimal Price, IEnumerable<OrderCustomerProduct> Orders);
public record ToppingInternal(int Id, string Name, decimal Price);
}
39 changes: 25 additions & 14 deletions exercise.pizzashopapi/Data/DataContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,37 @@

namespace exercise.pizzashopapi.Data
{
public class DataContext : DbContext
public class DataContext(DbContextOptions<DataContext> options) : DbContext(options)
{
private string connectionString;
public DataContext()
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
connectionString = configuration.GetValue<string>("ConnectionStrings:DefaultConnectionString");
modelBuilder.Entity<OrderTopping>().HasKey(ot => new { ot.OrderId, ot.ToppingId });
modelBuilder.Entity<Order>()
.HasMany(o => o.Toppings)
.WithMany(t => t.Orders)
.UsingEntity<OrderTopping>();
modelBuilder.Entity<Order>()
.HasOne(o => o.Product)
.WithMany(p => p.Orders)
.HasForeignKey(o => o.ProductId)
.OnDelete(DeleteBehavior.SetNull);
modelBuilder.Entity<Order>()
.HasOne(o => o.Customer)
.WithMany(c => c.Orders)
.HasForeignKey(o => o.CustomerId)
.OnDelete(DeleteBehavior.SetNull);

Seeder seeder = new Seeder();
modelBuilder.Entity<Customer>().HasData(seeder.Customers);
modelBuilder.Entity<Product>().HasData(seeder.Products);
modelBuilder.Entity<Order>().HasData(seeder.Orders);
modelBuilder.Entity<Topping>().HasData(seeder.Toppings);
modelBuilder.Entity<OrderTopping>().HasData(seeder.OrderToppings);
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseNpgsql(connectionString);

//set primary of order?

//seed data?

}
public DbSet<Pizza> Pizzas { get; set; }
public DbSet<Product> Products { get; set; }
public DbSet<Customer> Customers { get; set; }
public DbSet<Order> Orders { get; set; }
public DbSet<Topping> Toppings { get; set; }
}
}
72 changes: 48 additions & 24 deletions exercise.pizzashopapi/Data/Seeder.cs
Original file line number Diff line number Diff line change
@@ -1,34 +1,58 @@
using exercise.pizzashopapi.Models;
using exercise.pizzashopapi.Enums;

namespace exercise.pizzashopapi.Data
{
public static class Seeder
public class Seeder
{
public async static void SeedPizzaShopApi(this WebApplication app)
{
using(var db = new DataContext())
{
if(!db.Customers.Any())
{
db.Add(new Customer() { Name="Nigel" });
db.Add(new Customer() { Name = "Dave" });
await db.SaveChangesAsync();
}
if(!db.Pizzas.Any())
{
db.Add(new Pizza() { Name = "Cheese & Pineapple" });
db.Add(new Pizza() { Name = "Vegan Cheese Tastic" });
await db.SaveChangesAsync();
private List<Customer> _customers = [
new Customer { Id = 1, Name = "Nigel"},
new Customer { Id = 2, Name = "Dave"},
new Customer { Id = 3, Name = "Nikolai"}
];

}
private List<Product> _products = [
new Product { Id = 1, ProductType = ProductType.Pizza, Name = "Hawaiian Pizza", Price = 200 },
new Product { Id = 2, ProductType = ProductType.Pizza, Name = "Vegan Cheese Tastic", Price = 165 },
new Product { Id = 3, ProductType = ProductType.Pizza, Name = "Pizza Vendetta", Price = 210 },
new Product { Id = 4, ProductType = ProductType.Burger, Name = "Bacon Cheese Burger", Price = 195 },
new Product { Id = 5, ProductType = ProductType.Fries, Name = "Regular Fries", Price = 110 },
new Product { Id = 6, ProductType = ProductType.Drinks, Name = "Coca Cola 0.4L", Price = 65 },
new Product { Id = 7, ProductType = ProductType.Drinks, Name = "Fanta Orange 0.4L", Price = 65 },
];

//order data
if(1==1)
{
private List<Order> _orders = [
new Order {
Id = 1, CustomerId = 1, ProductId = 2, IsDelivered = true,
CreatedAt = DateTime.UtcNow.AddDays(-1), StartedAt = DateTime.UtcNow.AddDays(-1).AddMinutes(4),
CompletedAt = DateTime.UtcNow.AddDays(-1).AddMinutes(12),
PreparationStage = PreparationStage.Finished },
new Order { Id = 2, CustomerId = 2, ProductId = 1, IsDelivered = false },
new Order { Id = 3, CustomerId = 3, ProductId = 3, IsDelivered = true,
CreatedAt = DateTime.UtcNow.AddDays(-1), StartedAt = DateTime.UtcNow.AddDays(-1).AddMinutes(4),
CompletedAt = DateTime.UtcNow.AddDays(-1).AddMinutes(12),
PreparationStage = PreparationStage.Finished},
new Order { Id = 4, CustomerId = 3, ProductId = 7, IsDelivered = true,
CreatedAt = DateTime.UtcNow.AddDays(-1), StartedAt = DateTime.UtcNow.AddDays(-1).AddMinutes(4),
CompletedAt = DateTime.UtcNow.AddDays(-1).AddMinutes(12),
PreparationStage = PreparationStage.Finished},
];

await db.SaveChangesAsync();
}
}
}
private List<Topping> _toppings = [
new Topping {Id = 1, Name = "Bacon", Price = 20 },
new Topping {Id = 2, Name = "Onion Rings", Price = 15 },
new Topping {Id = 3, Name = "Hot Sauce", Price = 12 },
];

private List<OrderTopping> _orderToppings = [
new OrderTopping { OrderId = 3, ToppingId = 3 },
new OrderTopping { OrderId = 1, ToppingId = 1 }
];

public List<Customer> Customers { get { return _customers; } }
public List<Product> Products { get { return _products; } }
public List<Order> Orders { get { return _orders; } }
public List<Topping> Toppings { get { return _toppings; } }
public List<OrderTopping> OrderToppings { get { return _orderToppings; } }
}
}
15 changes: 0 additions & 15 deletions exercise.pizzashopapi/EndPoints/PizzaShopApi.cs

This file was deleted.

94 changes: 94 additions & 0 deletions exercise.pizzashopapi/Endpoints/CustomerEndpoints.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
using AutoMapper;
using exercise.pizzashopapi.DTO;
using exercise.pizzashopapi.Exceptions;
using exercise.pizzashopapi.Models;
using exercise.pizzashopapi.Repository;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace exercise.pizzashopapi.Endpoints
{
public static class CustomerEndpoints
{
public static string Path { get; private set; } = "customers";
public static void ConfigureCustomersEndpoints(this WebApplication app)
{
var group = app.MapGroup(Path);

group.MapGet("/", GetCustomers);
group.MapPost("/", CreateCustomer);
group.MapGet("/{id}", GetCustomer);
}

[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public static async Task<IResult> GetCustomers(IRepository<Customer, int> repository, IMapper mapper)
{
try
{
IEnumerable<Customer> customers = await repository.GetAll(
q => q.Include(x => x.Orders).ThenInclude(x => x.Toppings),
q => q.Include(x => x.Orders).ThenInclude(x => x.Product)
);
return TypedResults.Ok(mapper.Map<List<CustomerView>>(customers));
}
catch (Exception ex)
{
return TypedResults.Problem(ex.Message);
}
}

[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public static async Task<IResult> GetCustomer(IRepository<Customer, int> repository, IMapper mapper, int id)
{
try
{
Customer customer = await repository.Get(id,
q => q.Include(x => x.Orders).ThenInclude(x => x.Toppings),
q => q.Include(x => x.Orders).ThenInclude(x => x.Product)
);
return TypedResults.Ok(mapper.Map<CustomerView>(customer));
}
catch (IdNotFoundException ex)
{
return TypedResults.NotFound(new { ex.Message });
}
catch (Exception ex)
{
return TypedResults.Problem(ex.Message);
}
}

[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public static async Task<IResult> CreateCustomer(
IRepository<Customer, int> repository,
IRepository<Customer, int> customerRepository,
IRepository<Product, int> productRepository,
IMapper mapper,
CustomerPost entity)
{
try
{
Customer customer = await repository.Add(new Customer
{
Name = entity.Name
});
customer = await customerRepository.Add(customer);
return TypedResults.Created($"{Path}/{customer.Id}", mapper.Map<CustomerView>(customer));
}
catch (IdNotFoundException ex)
{
return TypedResults.NotFound(new { ex.Message });
}
catch (Exception ex)
{
return TypedResults.Problem(ex.Message);
}
}
}
}
Loading