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
10 changes: 10 additions & 0 deletions exercise.pizzashopapi/DTO/CustomerDTO.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using exercise.pizzashopapi.Models;

namespace exercise.pizzashopapi.DTO
{
public class CustomerDTO
{
public string Name { get; set; }
public List<OrderDTO> Orders { get; set; } = new List<OrderDTO>();
}
}
15 changes: 15 additions & 0 deletions exercise.pizzashopapi/DTO/OrderDTO.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using exercise.pizzashopapi.Models;

namespace exercise.pizzashopapi.DTO
{
public class OrderDTO
{
public int Id { get; set; }
public int CustomerId { get; set; }
public int PizzaId { get; set; }
public string PizzaName { get; set; }
public List<ToppingsDTO> Toppings { get; set; }
public DateTime CreatedAt { get; set; }
public string Status { get; set; }
}
}
10 changes: 10 additions & 0 deletions exercise.pizzashopapi/DTO/OrderPost.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.ComponentModel.DataAnnotations.Schema;

namespace exercise.pizzashopapi.DTO
{
public class OrderPost
{
public int CustomerId { get; set; }
public int PizzaId { get; set; }
}
}
8 changes: 8 additions & 0 deletions exercise.pizzashopapi/DTO/OrderToppingsDTO.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace exercise.pizzashopapi.DTO
{
public class OrderToppingsDTO
{
public int OrderId { get; set; }
public int ToppingsId { get; set; }
}
}
8 changes: 8 additions & 0 deletions exercise.pizzashopapi/DTO/OrderToppingsPost.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace exercise.pizzashopapi.DTO
{
public class OrderToppingsPost
{
public int OrderId { get; set; }
public int ToppingsId { get; set; }
}
}
9 changes: 9 additions & 0 deletions exercise.pizzashopapi/DTO/PizzaDTO.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace exercise.pizzashopapi.DTO
{
public class PizzaDTO
{
public int Id { get; set; }
public string Name { get; set; }
public int Price { get; set; }
}
}
8 changes: 8 additions & 0 deletions exercise.pizzashopapi/DTO/PizzaPost.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace exercise.pizzashopapi.DTO
{
public class PizzaPost
{
public string Name { get; set; }
public int Price { get; set; }
}
}
8 changes: 8 additions & 0 deletions exercise.pizzashopapi/DTO/ToppingsDTO.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace exercise.pizzashopapi.DTO
{
public class ToppingsDTO
{
public int Id { get; set; }
public string Name { get; set; }
}
}
16 changes: 16 additions & 0 deletions exercise.pizzashopapi/Data/DataContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,20 @@ public DataContext()
var configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
connectionString = configuration.GetValue<string>("ConnectionStrings:DefaultConnectionString");

}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);

modelBuilder.Entity<OrderToppings>()
.HasKey(o => new { o.OrderId, o.ToppingsId });

modelBuilder.Entity<Order>()
.HasMany(o => o.Toppings)
.WithMany(t => t.Order)
.UsingEntity<OrderToppings>();


}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
Expand All @@ -24,5 +38,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
public DbSet<Pizza> Pizzas { get; set; }
public DbSet<Customer> Customers { get; set; }
public DbSet<Order> Orders { get; set; }
public DbSet<Toppings> Toppings { get; set; }
public DbSet<OrderToppings> OrderToppings { get; set; }
}
}
24 changes: 20 additions & 4 deletions exercise.pizzashopapi/Data/Seeder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,34 @@ public async static void SeedPizzaShopApi(this WebApplication app)
{
if(!db.Customers.Any())
{
db.Add(new Customer() { Name="Nigel" });
db.Add(new Customer() { Name = "Nigel" });
db.Add(new Customer() { Name = "Dave" });
db.Add(new Customer() { Name = "Martin" });
await db.SaveChangesAsync();
}
if(!db.Pizzas.Any())
{
db.Add(new Pizza() { Name = "Cheese & Pineapple" });
db.Add(new Pizza() { Name = "Vegan Cheese Tastic" });
db.Add(new Pizza() { Name = "Cheese & Pineapple", Price = 10 });
db.Add(new Pizza() { Name = "Vegan Cheese Tastic", Price = 10 });
db.Add(new Pizza() { Name = "Vegan Supreme", Price = 11});
await db.SaveChangesAsync();

}

if(!db.Orders.Any())
{
db.Add(new Order() { CustomerId = 1, PizzaId = 2, CreatedAt = new DateTime(2025, 1, 27, 12, 0, 0, DateTimeKind.Utc), Status = OrderStatus.Preparing });
db.Add(new Order() { CustomerId = 2, PizzaId = 1, CreatedAt = new DateTime(2025, 1, 27, 12, 0, 0, DateTimeKind.Utc), Status = OrderStatus.Preparing });
db.Add(new Order() { CustomerId = 3, PizzaId = 3, CreatedAt = new DateTime(2025, 1, 26, 12, 0, 0, DateTimeKind.Utc), Status = OrderStatus.Delivered });
await db.SaveChangesAsync();
}
if(!db.Toppings.Any())
{
db.Add(new Toppings() { Name = "Mushrooms"});
db.Add(new Toppings() { Name = "Onions" });
db.Add(new Toppings() { Name = "Green Peppers" });
db.Add(new Toppings() { Name = "Pineapple" });
await db.SaveChangesAsync();
}
//order data
if(1==1)
{
Expand Down
187 changes: 184 additions & 3 deletions exercise.pizzashopapi/EndPoints/PizzaShopApi.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,196 @@
using exercise.pizzashopapi.Repository;
using AutoMapper;
using exercise.pizzashopapi.DTO;
using exercise.pizzashopapi.Models;
using exercise.pizzashopapi.Repository;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace exercise.pizzashopapi.EndPoints
{
public static class PizzaShopApi
{
public static void ConfigurePizzaShopApi(this WebApplication app)
{



app.MapGet("/orders", GetOrders);
app.MapGet("/orders/customer/{id}",GetOrdersByCustomerId);
app.MapPost("/orders/toppings", AddToppingToOrder);
app.MapPost("/orders", CreateOrder);
app.MapGet("/orders/{id}", GetOrderById);
app.MapPut("/orders/delivered/{id}", SetOrderDelivered);

app.MapGet("/customers", GetCustomers);

app.MapGet("/pizzas", GetPizzas);
app.MapPost("/pizzas", CreatePizza);


app.MapGet("/toppings", GetToppings);

}
[ProducesResponseType(StatusCodes.Status200OK)]
public static async Task<IResult> GetOrders(IRepository<Order> repo, IMapper mapper)
{
var orders = await repo.GetWithNestedIncludes(
query => query
.Include(o => o.Pizza)
.Include(o => o.Customer)
.Include(o => o.OrderToppings).ThenInclude(ot => ot.Toppings)
);
var orderDTOs = mapper.Map<List<OrderDTO>>(orders);
return TypedResults.Ok(orderDTOs);
}
[ProducesResponseType(StatusCodes.Status200OK)]
public static async Task<IResult> GetCustomers(IRepository<Customer> repo, IMapper mapper)
{
var customers = await repo.GetWithNestedIncludes(
query => query
.Include(c => c.Orders)
.ThenInclude(o => o.Pizza)
);
var dtos = mapper.Map<List<CustomerDTO>>(customers);
return TypedResults.Ok(dtos);

}
[ProducesResponseType(StatusCodes.Status200OK)]
public static async Task<IResult> GetOrdersByCustomerId(IRepository<Customer> repo, int id, IMapper mapper)
{
var orders = await repo.GetByIdWithNestedIncludes(c => c.Id == id,
query => query
.Include(c => c.Orders)
.ThenInclude(o => o.Pizza)
);
var customerDTO = mapper.Map<CustomerDTO>(orders);
return TypedResults.Ok(customerDTO);
}

[ProducesResponseType(StatusCodes.Status200OK)]
public static async Task<IResult> GetPizzas(IRepository<Pizza> repo, IMapper mapper)
{
var pizzas = await repo.Get();
var pizzaDTOs = mapper.Map<List<PizzaDTO>>(pizzas);
return TypedResults.Ok(pizzaDTOs);
}
[ProducesResponseType(StatusCodes.Status201Created)]
public static async Task<IResult> CreatePizza(IRepository<Pizza> repo, IMapper mapper, PizzaPost model)
{
try
{
var newPizza = new Pizza()
{
Name = model.Name,
Price = model.Price
};

var create = await repo.Insert(newPizza);
var dto = mapper.Map<PizzaDTO>(newPizza);
return TypedResults.Created($"/{create.Id}", dto);
}
catch (Exception ex)
{
return TypedResults.Problem(ex.Message);
}
}


[ProducesResponseType(StatusCodes.Status201Created)]
public static async Task<IResult> CreateOrder(IRepository<Order> repo, IMapper mapper, OrderPost model)
{
try
{
var newOrder = new Order()
{
CustomerId = model.CustomerId,
PizzaId = model.PizzaId,
CreatedAt = DateTime.UtcNow,
};

var create = await repo.Insert(newOrder);
var result = await repo.GetByIdWithNestedIncludes(o => o.Id == create.Id,
query => query
.Include(o => o.Pizza));
var dto = mapper.Map<OrderDTO>(newOrder);
return TypedResults.Created($"/{create.Id}", dto);
}
catch (Exception ex)
{
return TypedResults.Problem(ex.Message);
}
}

[ProducesResponseType(StatusCodes.Status200OK)]
public static async Task<IResult> AddToppingToOrder(
IRepository<OrderToppings> repo,
IMapper mapper,
OrderToppingsPost model)
{
try
{
var newOt = new OrderToppings()
{
OrderId = model.OrderId,
ToppingsId = model.ToppingsId
};

await repo.Insert(newOt);
var dto = mapper.Map<OrderToppingsDTO>(newOt);
return TypedResults.Ok(dto);
}
catch (Exception ex)
{
return TypedResults.Problem(ex.Message);
}
}

[ProducesResponseType(StatusCodes.Status200OK)]
public static async Task<IResult> GetToppings(IRepository<Toppings> repo, IMapper mapper)
{
var toppings = await repo.Get();
var dto = mapper.Map<List<ToppingsDTO>>(toppings);
return TypedResults.Ok(dto);
}

[ProducesResponseType(StatusCodes.Status200OK)]
public static async Task<IResult> GetOrderById(IRepository<Order> repo, IMapper mapper, int id)
{
try
{
var order = await repo.GetByIdWithNestedIncludes(o => o.Id == id,
query => query
.Include(o => o.Pizza)
.Include(o => o.Customer)
.Include(o => o.OrderToppings).ThenInclude(ot => ot.Toppings)
);

var currentStatus = Order.GetOrderStatus(order.CreatedAt, DateTime.UtcNow);
if (order.Status != currentStatus || order.Status != OrderStatus.Delivered)
{
order.Status = currentStatus;
await repo.Update(order);
}

var dto = mapper.Map<OrderDTO>(order);
return TypedResults.Ok(dto);
}
catch (Exception ex)
{
return TypedResults.Problem(ex.Message);
}
}
[ProducesResponseType(StatusCodes.Status200OK)]
public static async Task<IResult> SetOrderDelivered(IRepository<Order> repo, IMapper mapper, int id)
{

var order = await repo.GetById(id);

if (order.Status == OrderStatus.Delivered) return TypedResults.Ok("Order already delivered");
order.Status = OrderStatus.Delivered;
await repo.Update(order);
return TypedResults.Ok(new
{
Order = order.Id,
Status = OrderStatus.Delivered.ToString()
});
}
}
}
8 changes: 7 additions & 1 deletion exercise.pizzashopapi/Models/Customer.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace exercise.pizzashopapi.Models
{
[Table("customers")]
public class Customer
{
[Key]
[Column("id")]
public int Id { get; set; }
[Column("name")]
public string Name { get; set; }
public List<Order> Orders { get; set; } = new List<Order>();
}
}
6 changes: 6 additions & 0 deletions exercise.pizzashopapi/Models/DeliveryDrivers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace exercise.pizzashopapi.Models
{
public class DeliveryDrivers
{
}
}
Loading