diff --git a/Contracts/Dtos.cs b/Contracts/Dtos.cs index ea83a13..6f6438c 100644 --- a/Contracts/Dtos.cs +++ b/Contracts/Dtos.cs @@ -1,7 +1,7 @@ namespace GameList.Contracts; public record SetNameRequest(string Name); -public record SuggestionRequest(string Name, string? Genre, string? Description, string? ScreenshotUrl, string? YoutubeUrl); -public record SuggestionDto(int Id, string Name, string? Genre, string? Description, string? ScreenshotUrl, string? YoutubeUrl); +public record SuggestionRequest(string Name, string? Genre, string? Description, string? ScreenshotUrl, string? YoutubeUrl, string? GameUrl); +public record SuggestionDto(int Id, string Name, string? Genre, string? Description, string? ScreenshotUrl, string? YoutubeUrl, string? GameUrl); public record VoteRequest(int SuggestionId, int Score); public record PhaseRequest(GameList.Domain.Phase Phase); diff --git a/Data/AppDbContext.cs b/Data/AppDbContext.cs index a9d9e1a..27fbdc9 100644 --- a/Data/AppDbContext.cs +++ b/Data/AppDbContext.cs @@ -38,6 +38,7 @@ public class AppDbContext : DbContext builder.Property(s => s.Description).HasMaxLength(500); builder.Property(s => s.ScreenshotUrl).HasMaxLength(2048); builder.Property(s => s.YoutubeUrl).HasMaxLength(2048); + builder.Property(s => s.GameUrl).HasMaxLength(2048); }); modelBuilder.Entity(builder => diff --git a/Data/Migrations/20260128192420_AddGameUrlToSuggestion.Designer.cs b/Data/Migrations/20260128192420_AddGameUrlToSuggestion.Designer.cs new file mode 100644 index 0000000..849b007 --- /dev/null +++ b/Data/Migrations/20260128192420_AddGameUrlToSuggestion.Designer.cs @@ -0,0 +1,182 @@ +// +using System; +using GameList.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace GameList.Data.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20260128192420_AddGameUrlToSuggestion")] + partial class AddGameUrlToSuggestion + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "10.0.2"); + + modelBuilder.Entity("GameList.Domain.AppState", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CurrentPhase") + .HasColumnType("INTEGER"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("AppState"); + + b.HasData( + new + { + Id = 1, + CurrentPhase = 0, + UpdatedAt = new DateTimeOffset(new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)) + }); + }); + + modelBuilder.Entity("GameList.Domain.Player", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("DisplayName") + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Players"); + }); + + modelBuilder.Entity("GameList.Domain.Suggestion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("Description") + .HasMaxLength(500) + .HasColumnType("TEXT"); + + b.Property("GameUrl") + .HasMaxLength(2048) + .HasColumnType("TEXT"); + + b.Property("Genre") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("PlayerId") + .HasColumnType("TEXT"); + + b.Property("ScreenshotUrl") + .HasMaxLength(2048) + .HasColumnType("TEXT"); + + b.Property("YoutubeUrl") + .HasMaxLength(2048) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("PlayerId"); + + b.ToTable("Suggestions"); + }); + + modelBuilder.Entity("GameList.Domain.Vote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("PlayerId") + .HasColumnType("TEXT"); + + b.Property("Score") + .HasColumnType("INTEGER"); + + b.Property("SuggestionId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SuggestionId"); + + b.HasIndex("PlayerId", "SuggestionId") + .IsUnique(); + + b.ToTable("Votes"); + }); + + modelBuilder.Entity("GameList.Domain.Suggestion", b => + { + b.HasOne("GameList.Domain.Player", "Player") + .WithMany("Suggestions") + .HasForeignKey("PlayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Player"); + }); + + modelBuilder.Entity("GameList.Domain.Vote", b => + { + b.HasOne("GameList.Domain.Player", "Player") + .WithMany("Votes") + .HasForeignKey("PlayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GameList.Domain.Suggestion", "Suggestion") + .WithMany("Votes") + .HasForeignKey("SuggestionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Player"); + + b.Navigation("Suggestion"); + }); + + modelBuilder.Entity("GameList.Domain.Player", b => + { + b.Navigation("Suggestions"); + + b.Navigation("Votes"); + }); + + modelBuilder.Entity("GameList.Domain.Suggestion", b => + { + b.Navigation("Votes"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Data/Migrations/20260128192420_AddGameUrlToSuggestion.cs b/Data/Migrations/20260128192420_AddGameUrlToSuggestion.cs new file mode 100644 index 0000000..837f4cb --- /dev/null +++ b/Data/Migrations/20260128192420_AddGameUrlToSuggestion.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace GameList.Data.Migrations +{ + /// + public partial class AddGameUrlToSuggestion : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "GameUrl", + table: "Suggestions", + type: "TEXT", + maxLength: 2048, + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "GameUrl", + table: "Suggestions"); + } + } +} diff --git a/Data/Migrations/AppDbContextModelSnapshot.cs b/Data/Migrations/AppDbContextModelSnapshot.cs index bfdea47..1b135a9 100644 --- a/Data/Migrations/AppDbContextModelSnapshot.cs +++ b/Data/Migrations/AppDbContextModelSnapshot.cs @@ -73,6 +73,10 @@ namespace GameList.Data.Migrations .HasMaxLength(500) .HasColumnType("TEXT"); + b.Property("GameUrl") + .HasMaxLength(2048) + .HasColumnType("TEXT"); + b.Property("Genre") .HasMaxLength(50) .HasColumnType("TEXT"); diff --git a/Domain/Suggestion.cs b/Domain/Suggestion.cs index 4d3f925..c3f3831 100644 --- a/Domain/Suggestion.cs +++ b/Domain/Suggestion.cs @@ -26,6 +26,9 @@ public class Suggestion [MaxLength(2048)] public string? YoutubeUrl { get; set; } + [MaxLength(2048)] + public string? GameUrl { get; set; } + public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow; public ICollection Votes { get; set; } = new List(); diff --git a/Endpoints/ResultsEndpoints.cs b/Endpoints/ResultsEndpoints.cs index 7caed52..e96191c 100644 --- a/Endpoints/ResultsEndpoints.cs +++ b/Endpoints/ResultsEndpoints.cs @@ -27,6 +27,7 @@ public static class ResultsEndpoints Average = s.Votes.Count == 0 ? 0 : s.Votes.Average(v => v.Score), s.ScreenshotUrl, s.YoutubeUrl, + s.GameUrl, s.Description, s.Genre }) diff --git a/Endpoints/SuggestEndpoints.cs b/Endpoints/SuggestEndpoints.cs index 2d977ab..07e992c 100644 --- a/Endpoints/SuggestEndpoints.cs +++ b/Endpoints/SuggestEndpoints.cs @@ -27,13 +27,14 @@ public static class SuggestEndpoints s.Description, s.ScreenshotUrl, s.YoutubeUrl, + s.GameUrl, s.CreatedAt }) .ToListAsync(); var ordered = mine .OrderBy(s => s.CreatedAt) - .Select(s => new SuggestionDto(s.Id, s.Name, s.Genre, s.Description, s.ScreenshotUrl, s.YoutubeUrl)); + .Select(s => new SuggestionDto(s.Id, s.Name, s.Genre, s.Description, s.ScreenshotUrl, s.YoutubeUrl, s.GameUrl)); return Results.Ok(ordered); }); @@ -69,7 +70,8 @@ public static class SuggestEndpoints Genre = EndpointHelpers.TrimTo(request.Genre, 50), Description = EndpointHelpers.TrimTo(request.Description, 500), ScreenshotUrl = EndpointHelpers.TrimTo(request.ScreenshotUrl, 2048), - YoutubeUrl = EndpointHelpers.TrimTo(request.YoutubeUrl, 2048) + YoutubeUrl = EndpointHelpers.TrimTo(request.YoutubeUrl, 2048), + GameUrl = EndpointHelpers.TrimTo(request.GameUrl, 2048) }; db.Suggestions.Add(suggestion); @@ -110,6 +112,7 @@ public static class SuggestEndpoints s.Description, s.ScreenshotUrl, s.YoutubeUrl, + s.GameUrl, Author = s.Player!.DisplayName, s.CreatedAt }) @@ -125,6 +128,7 @@ public static class SuggestEndpoints s.Description, s.ScreenshotUrl, s.YoutubeUrl, + s.GameUrl, s.Author });