diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml
index 217f7cb..415bdca 100644
--- a/.github/workflows/dotnet.yml
+++ b/.github/workflows/dotnet.yml
@@ -1,6 +1,3 @@
-# This workflow will build a .NET project
-# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net
-
name: .NET
on:
@@ -11,18 +8,48 @@ on:
jobs:
build:
-
+ env:
+ ConnectionStrings__DefaultConnection: "Host=localhost;Port=5432;Database=movie;Username=postgres;Password="
+
runs-on: ubuntu-latest
-
+
steps:
- - uses: actions/checkout@v4
- - name: Setup .NET
- uses: actions/setup-dotnet@v4
- with:
- dotnet-version: 8.0.x
- - name: Restore dependencies
- run: dotnet restore
- - name: Build
- run: dotnet build --no-restore
- - name: Test
- run: dotnet test --no-build --verbosity normal
+ - uses: actions/checkout@v4
+
+ - name: Start PostgreSQL via Docker Compose
+ run: |
+ docker compose up -d --build
+ until docker compose exec -T postgres pg_isready -U postgres -d movie; do
+ if [ -z "$(docker compose ps --status running -q postgres)" ]; then
+ echo "Le conteneur postgres s'est arrêté inopinément. Logs :"
+ docker compose logs postgres
+ exit 1
+ fi
+ echo "En attente de PostgreSQL (initialisation en cours)..."
+ sleep 2
+ done
+ echo "PostgreSQL est prêt !"
+
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 8.0.x
+
+ - name: Restore dependencies
+ run: dotnet restore
+
+ - name: Build
+ run: dotnet build --no-restore
+
+ - name: Install dotnet-ef tool
+ run: dotnet tool install --global dotnet-ef
+
+ - name: Update database
+ run: dotnet ef database update --project API
+
+ - name: Test
+ run: dotnet test API.Tests/API.Tests.csproj --no-build --verbosity normal
+
+ - name: Stop Containers
+ if: always()
+ run: docker compose down -v
\ No newline at end of file
diff --git a/API.Tests/API.Tests.csproj b/API.Tests/API.Tests.csproj
new file mode 100644
index 0000000..b0d96df
--- /dev/null
+++ b/API.Tests/API.Tests.csproj
@@ -0,0 +1,20 @@
+
+
+
+ net8.0
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/API.Tests/Controller/ProductControllerTest.cs b/API.Tests/Controller/ProductControllerTest.cs
new file mode 100644
index 0000000..9b7a1d6
--- /dev/null
+++ b/API.Tests/Controller/ProductControllerTest.cs
@@ -0,0 +1,30 @@
+using API.Controller;
+using JetBrains.Annotations;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace API.Tests.Controller;
+
+[TestClass]
+[TestSubject(typeof(ProductController))]
+public class ProductControllerTest
+{
+ private readonly ProductController _controller;
+
+ [TestInitialize]
+ public void Init()
+ {
+
+ }
+
+ [TestMethod]
+ public void ShouldCreateProduct()
+ {
+ // Given
+
+ // When
+
+ // Then
+ Assert.AreEqual(1, 1);
+ }
+}
\ No newline at end of file
diff --git a/API/Controller/ProductController.cs b/API/Controller/ProductController.cs
index aad6da4..b2321fa 100644
--- a/API/Controller/ProductController.cs
+++ b/API/Controller/ProductController.cs
@@ -5,20 +5,24 @@ namespace API.Controller;
[ApiController]
[Route("api/product")]
-public class ProductController : ControllerBase
+public class ProductController(AppDbContext context) : ControllerBase
{
// GET api/product
[HttpGet]
- public ActionResult GetProduct(int id)
+ public ActionResult GetProduct( int id)
{
- return Ok();
+ var products = context.Products.ToList();
+ return Ok(products);
}
// POST api/product
[HttpPost]
public ActionResult CreateProduct([FromBody] Product product)
{
- return Ok();
+ context.Products.Add(product);
+ context.SaveChanges();
+
+ return Ok(product);
}
// PATCH api/product
diff --git a/API/Models/AppDbContext.cs b/API/Models/AppDbContext.cs
index e581d6f..4342a09 100644
--- a/API/Models/AppDbContext.cs
+++ b/API/Models/AppDbContext.cs
@@ -4,9 +4,9 @@ namespace API.Models;
public partial class AppDbContext(DbContextOptions options) : DbContext(options)
{
- private DbSet Brands { get; set; }
- private DbSet Products { get; set; }
- private DbSet ProductTypes { get; set; }
+ public DbSet Brands { get; set; }
+ public DbSet Products { get; set; }
+ public DbSet ProductTypes { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
diff --git a/API/Program.cs b/API/Program.cs
index ee00eca..3ac8bf6 100644
--- a/API/Program.cs
+++ b/API/Program.cs
@@ -9,9 +9,8 @@
builder.Services.AddSwaggerGen();
builder.Services.AddControllers();
builder.Services.AddDbContext(options =>
- options.UseNpgsql("Host=localhost;Port=5432;Database=movie;Username=postgres;Password=")
+ options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection"))
);
-
var app = builder.Build();
// Configure the HTTP request pipeline.
@@ -22,4 +21,5 @@
}
app.UseHttpsRedirection();
+app.MapControllers();
app.Run();
\ No newline at end of file
diff --git a/API/appsettings.json b/API/appsettings.json
index 10f68b8..3e9e333 100644
--- a/API/appsettings.json
+++ b/API/appsettings.json
@@ -5,5 +5,9 @@
"Microsoft.AspNetCore": "Warning"
}
},
- "AllowedHosts": "*"
+ "AllowedHosts": "*",
+ "ConnectionStrings": {
+ "DefaultConnection": "Host=localhost;Port=5432;Database=movie;Username=postgres;Password="
+ }
}
+
diff --git a/Dockerfile-postgres b/Dockerfile-postgres
new file mode 100644
index 0000000..e9abea8
--- /dev/null
+++ b/Dockerfile-postgres
@@ -0,0 +1 @@
+FROM postgres:16-alpine
diff --git a/R508.sln b/R508.sln
index 8fb4245..c226a56 100644
--- a/R508.sln
+++ b/R508.sln
@@ -2,6 +2,8 @@
Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "API", "API\API.csproj", "{C3B38DC2-9752-4DE7-B514-13E5D7C5C4A3}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "API.Tests", "API.Tests\API.Tests.csproj", "{78E9942E-3C56-47E4-A41A-95F32FD47256}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -12,5 +14,9 @@ Global
{C3B38DC2-9752-4DE7-B514-13E5D7C5C4A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C3B38DC2-9752-4DE7-B514-13E5D7C5C4A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C3B38DC2-9752-4DE7-B514-13E5D7C5C4A3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {78E9942E-3C56-47E4-A41A-95F32FD47256}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {78E9942E-3C56-47E4-A41A-95F32FD47256}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {78E9942E-3C56-47E4-A41A-95F32FD47256}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {78E9942E-3C56-47E4-A41A-95F32FD47256}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
diff --git a/README.md b/README.md
index 8ec7669..b7fa6bc 100644
--- a/README.md
+++ b/README.md
@@ -10,6 +10,7 @@ docker run -d \
-e POSTGRES_USER=postgres \
-e POSTGRES_HOST_AUTH_METHOD=trust \
-v pgdata_movie:/var/lib/postgresql/data \
+ -v ./init.sql:/docker-entrypoint-initdb.d/init.sql \
postgres:16
```
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..f74c360
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,17 @@
+services:
+ postgres:
+ build:
+ context: .
+ dockerfile: Dockerfile-postgres
+ container_name: postgres_db
+ environment:
+ POSTGRES_HOST_AUTH_METHOD: "trust"
+ POSTGRES_DB: movie
+ POSTGRES_USER: postgres
+ ports:
+ - "5432:5432"
+ volumes:
+ - pgdata:/var/lib/postgresql/data
+
+volumes:
+ pgdata:
\ No newline at end of file
diff --git a/init.sql b/init.sql
new file mode 100644
index 0000000..815634e
--- /dev/null
+++ b/init.sql
@@ -0,0 +1,275 @@
+INSERT INTO public.brand (brand_name) VALUES
+ ('Apple'),
+ ('Samsung'),
+ ('Sony'),
+ ('Nike'),
+ ('Adidas'),
+ ('Puma'),
+ ('Zara'),
+ ('H&M'),
+ ('IKEA'),
+ ('Bose'),
+ ('Dell'),
+ ('Lenovo'),
+ ('Logitech'),
+ ('Canon'),
+ ('Philips'),
+ ('Dyson'),
+ ('Levi''s'),
+ ('The North Face'),
+ ('Xiaomi'),
+ ('Sennheiser');
+
+INSERT INTO public.product_type (product_type_name) VALUES
+ ('Smartphone'),
+ ('Laptop'),
+ ('Headphones'),
+ ('Wireless Earbuds'),
+ ('Television'),
+ ('Tablet'),
+ ('Smartwatch'),
+ ('Running Shoes'),
+ ('Sneakers'),
+ ('T-Shirt'),
+ ('Pants'),
+ ('Jacket'),
+ ('Backpack'),
+ ('Camera'),
+ ('Mechanical Keyboard'),
+ ('Wireless Mouse'),
+ ('Bluetooth Speaker'),
+ ('Stick Vacuum Cleaner'),
+ ('Desk Lamp'),
+ ('PC Monitor');
+
+INSERT INTO public.product (
+ product_name,
+ description,
+ photo_name,
+ photo_uri,
+ brand_id,
+ product_type_id,
+ actual_stock,
+ min_stock,
+ max_stock
+)
+VALUES
+ -- 1. iPhone 15 Pro (Apple / Smartphone)
+ (
+ 'iPhone 15 Pro 128 GB',
+ 'Smartphone powered by the A17 Pro chip with a titanium frame.',
+ 'iphone_15_pro.webp',
+ 'https://assets.example.com/products/apple/iphone-15-pro.webp',
+ (SELECT brand_id FROM public.brand WHERE brand_name = 'Apple'),
+ (SELECT product_type_id FROM public.product_type WHERE product_type_name = 'Smartphone'),
+ 45, 10, 100
+ ),
+
+ -- 2. Galaxy S24 Ultra (Samsung / Smartphone)
+ (
+ 'Galaxy S24 Ultra 256 GB',
+ 'Dynamic AMOLED 2X display with integrated S-Pen.',
+ 'galaxy_s24_ultra.webp',
+ 'https://assets.example.com/products/samsung/s24-ultra.webp',
+ (SELECT brand_id FROM public.brand WHERE brand_name = 'Samsung'),
+ (SELECT product_type_id FROM public.product_type WHERE product_type_name = 'Smartphone'),
+ 30, 8, 80
+ ),
+
+ -- 3. WH-1000XM5 (Sony / Headphones)
+ (
+ 'WH-1000XM5 Headphones',
+ 'Wireless over-ear headphones with industry-leading active noise cancellation.',
+ 'sony_wh1000xm5.webp',
+ 'https://assets.example.com/products/sony/wh-1000xm5.webp',
+ (SELECT brand_id FROM public.brand WHERE brand_name = 'Sony'),
+ (SELECT product_type_id FROM public.product_type WHERE product_type_name = 'Headphones'),
+ 18, 5, 50
+ ),
+
+ -- 4. Air Zoom Pegasus (Nike / Running Shoes)
+ (
+ 'Air Zoom Pegasus 40',
+ 'Versatile running shoes designed for daily training.',
+ 'nike_pegasus_40.webp',
+ 'https://assets.example.com/products/nike/pegasus-40.webp',
+ (SELECT brand_id FROM public.brand WHERE brand_name = 'Nike'),
+ (SELECT product_type_id FROM public.product_type WHERE product_type_name = 'Running Shoes'),
+ 65, 15, 120
+ ),
+
+ -- 5. Ultraboost Light (Adidas / Sneakers)
+ (
+ 'Ultraboost Light',
+ 'Responsive Boost cushioning featuring a supportive Primeknit upper.',
+ 'adidas_ultraboost.webp',
+ 'https://assets.example.com/products/adidas/ultraboost-light.webp',
+ (SELECT brand_id FROM public.brand WHERE brand_name = 'Adidas'),
+ (SELECT product_type_id FROM public.product_type WHERE product_type_name = 'Sneakers'),
+ 40, 10, 90
+ ),
+
+ -- 6. QuietComfort Ultra (Bose / Wireless Earbuds)
+ (
+ 'QuietComfort Ultra Earbuds',
+ 'True wireless earbuds delivering immersive spatial audio.',
+ 'bose_qc_ultra.webp',
+ 'https://assets.example.com/products/bose/qc-ultra-earbuds.webp',
+ (SELECT brand_id FROM public.brand WHERE brand_name = 'Bose'),
+ (SELECT product_type_id FROM public.product_type WHERE product_type_name = 'Wireless Earbuds'),
+ 25, 5, 60
+ ),
+
+ -- 7. XPS 15 (Dell / Laptop)
+ (
+ 'XPS 15 9530',
+ 'High-performance laptop featuring a 3.5K OLED display and Intel Core i7.',
+ 'dell_xps_15.webp',
+ 'https://assets.example.com/products/dell/xps-15.webp',
+ (SELECT brand_id FROM public.brand WHERE brand_name = 'Dell'),
+ (SELECT product_type_id FROM public.product_type WHERE product_type_name = 'Laptop'),
+ 12, 3, 30
+ ),
+
+ -- 8. ThinkPad X1 Carbon (Lenovo / Laptop)
+ (
+ 'ThinkPad X1 Carbon Gen 11',
+ 'Ultra-lightweight professional ultrabook built from carbon fiber.',
+ 'lenovo_x1_carbon.webp',
+ 'https://assets.example.com/products/lenovo/thinkpad-x1.webp',
+ (SELECT brand_id FROM public.brand WHERE brand_name = 'Lenovo'),
+ (SELECT product_type_id FROM public.product_type WHERE product_type_name = 'Laptop'),
+ 15, 4, 35
+ ),
+
+ -- 9. MX Master 3S (Logitech / Wireless Mouse)
+ (
+ 'MX Master 3S Performance',
+ 'Ergonomic wireless mouse with MagSpeed scrolling and quiet clicks.',
+ 'logitech_mx_master_3s.webp',
+ 'https://assets.example.com/products/logitech/mx-master-3s.webp',
+ (SELECT brand_id FROM public.brand WHERE brand_name = 'Logitech'),
+ (SELECT product_type_id FROM public.product_type WHERE product_type_name = 'Wireless Mouse'),
+ 85, 20, 150
+ ),
+
+ -- 10. EOS R6 Mark II (Canon / Camera)
+ (
+ 'EOS R6 Mark II Body Only',
+ 'Full-frame mirrorless camera with 24.2 MP and 4K 60p video.',
+ 'canon_eos_r6_mk2.webp',
+ 'https://assets.example.com/products/canon/eos-r6-mk2.webp',
+ (SELECT brand_id FROM public.brand WHERE brand_name = 'Canon'),
+ (SELECT product_type_id FROM public.product_type WHERE product_type_name = 'Camera'),
+ 8, 2, 20
+ ),
+
+ -- 11. V15 Detect (Dyson / Stick Vacuum Cleaner)
+ (
+ 'V15 Detect Total Clean',
+ 'Cordless vacuum cleaner with illumination laser and HEPA filtration.',
+ 'dyson_v15_detect.webp',
+ 'https://assets.example.com/products/dyson/v15-detect.webp',
+ (SELECT brand_id FROM public.brand WHERE brand_name = 'Dyson'),
+ (SELECT product_type_id FROM public.product_type WHERE product_type_name = 'Stick Vacuum Cleaner'),
+ 22, 5, 50
+ ),
+
+ -- 12. 501 Original Jeans (Levi's / Pants)
+ (
+ '501 Original Fit Jeans',
+ 'Iconic straight fit in 100% cotton denim with button fly.',
+ 'levis_501_original.webp',
+ 'https://assets.example.com/products/levis/501-original.webp',
+ (SELECT brand_id FROM public.brand WHERE brand_name = 'Levi''s'),
+ (SELECT product_type_id FROM public.product_type WHERE product_type_name = 'Pants'),
+ 110, 25, 200
+ ),
+
+ -- 13. Nuptse 1996 Jacket (The North Face / Jacket)
+ (
+ '1996 Retro Nuptse Jacket',
+ 'Packable down jacket filled with 700-fill goose down.',
+ 'tnf_nuptse_1996.webp',
+ 'https://assets.example.com/products/northface/nuptse-1996.webp',
+ (SELECT brand_id FROM public.brand WHERE brand_name = 'The North Face'),
+ (SELECT product_type_id FROM public.product_type WHERE product_type_name = 'Jacket'),
+ 19, 5, 45
+ ),
+
+ -- 14. Borealis Backpack (The North Face / Backpack)
+ (
+ 'Borealis Classic Backpack',
+ '28-liter volume with FlexVent suspension system and laptop compartment.',
+ 'tnf_borealis.webp',
+ 'https://assets.example.com/products/northface/borealis.webp',
+ (SELECT brand_id FROM public.brand WHERE brand_name = 'The North Face'),
+ (SELECT product_type_id FROM public.product_type WHERE product_type_name = 'Backpack'),
+ 50, 10, 100
+ ),
+
+ -- 15. Tertial Lamp (IKEA / Desk Lamp)
+ (
+ 'TERTIAL Work Lamp',
+ 'Articulated steel architect lamp with desk clamp.',
+ 'ikea_tertial.webp',
+ 'https://assets.example.com/products/ikea/tertial.webp',
+ (SELECT brand_id FROM public.brand WHERE brand_name = 'IKEA'),
+ (SELECT product_type_id FROM public.product_type WHERE product_type_name = 'Desk Lamp'),
+ 140, 30, 250
+ ),
+
+ -- 16. Bravia XR A80L (Sony / Television)
+ (
+ 'Bravia XR 55A80L OLED TV',
+ '55-inch 4K 120Hz OLED TV with Cognitive Processor XR and Google TV.',
+ 'sony_bravia_a80l.webp',
+ 'https://assets.example.com/products/sony/bravia-a80l.webp',
+ (SELECT brand_id FROM public.brand WHERE brand_name = 'Sony'),
+ (SELECT product_type_id FROM public.product_type WHERE product_type_name = 'Television'),
+ 7, 2, 20
+ ),
+
+ -- 17. Hue Go (Philips / Desk Lamp)
+ (
+ 'Hue Go V2 Portable Smart Lamp',
+ 'Portable White & Color Ambiance smart light compatible with Zigbee/Bluetooth.',
+ 'philips_hue_go.webp',
+ 'https://assets.example.com/products/philips/hue-go-v2.webp',
+ (SELECT brand_id FROM public.brand WHERE brand_name = 'Philips'),
+ (SELECT product_type_id FROM public.product_type WHERE product_type_name = 'Desk Lamp'),
+ 35, 8, 70
+ ),
+
+ -- 18. Redmi Note 13 (Xiaomi / Smartphone)
+ (
+ 'Redmi Note 13 4G',
+ '120Hz AMOLED display, 108 MP main camera, and 33W fast charging.',
+ 'xiaomi_redmi_note_13.webp',
+ 'https://assets.example.com/products/xiaomi/redmi-note-13.webp',
+ (SELECT brand_id FROM public.brand WHERE brand_name = 'Xiaomi'),
+ (SELECT product_type_id FROM public.product_type WHERE product_type_name = 'Smartphone'),
+ 75, 15, 150
+ ),
+
+ -- 19. Momentum 4 (Sennheiser / Headphones)
+ (
+ 'Momentum 4 Wireless',
+ 'Audiophile-inspired circum-aural headphones with up to 60-hour battery life.',
+ 'sennheiser_momentum_4.webp',
+ 'https://assets.example.com/products/sennheiser/momentum-4.webp',
+ (SELECT brand_id FROM public.brand WHERE brand_name = 'Sennheiser'),
+ (SELECT product_type_id FROM public.product_type WHERE product_type_name = 'Headphones'),
+ 14, 4, 30
+ ),
+
+ -- 20. Galaxy Tab S9 (Samsung / Tablet)
+ (
+ 'Galaxy Tab S9 Wi-Fi 128 GB',
+ '11-inch Dynamic AMOLED 2X IP68-rated tablet with included S-Pen.',
+ 'samsung_tab_s9.webp',
+ 'https://assets.example.com/products/samsung/tab-s9.webp',
+ (SELECT brand_id FROM public.brand WHERE brand_name = 'Samsung'),
+ (SELECT product_type_id FROM public.product_type WHERE product_type_name = 'Tablet'),
+ 20, 5, 40
+ );