diff --git a/FU.API/.editorconfig b/FU.API/.editorconfig index e4be8d55..6426f465 100644 --- a/FU.API/.editorconfig +++ b/FU.API/.editorconfig @@ -3,6 +3,14 @@ # SA1633: File should have header dotnet_diagnostic.SA1633.severity = none +# Xml Comment Analysis Disabled warning +dotnet_diagnostic.SA0001.severity = none + +# KeywordsMustBeSpacedCorrectly +# disabled because conflicts with formatter +# should never happed if using a formatter anyways +dotnet_diagnostic.SA1000.severity = none + # SA1201: Elements should appear in the correct order dotnet_diagnostic.SA1201.severity = none @@ -13,21 +21,23 @@ dotnet_diagnostic.SA1600.severity = none # SA1413: Use trailing comma in multi-line initializers dotnet_diagnostic.SA1413.severity = none csharp_indent_labels = one_less_than_current -csharp_using_directive_placement = outside_namespace:silent +csharp_using_directive_placement = inside_namespace csharp_prefer_simple_using_statement = true:suggestion -csharp_prefer_braces = true:silent -csharp_style_namespace_declarations = block_scoped:silent -csharp_style_prefer_method_group_conversion = true:silent -csharp_style_prefer_top_level_statements = true:silent +csharp_prefer_braces = true +csharp_style_namespace_declarations = file_scoped +csharp_style_prefer_method_group_conversion = true +csharp_style_prefer_top_level_statements = true csharp_style_prefer_primary_constructors = true:suggestion -csharp_style_expression_bodied_methods = false:silent -csharp_style_expression_bodied_constructors = false:silent -csharp_style_expression_bodied_operators = false:silent -csharp_style_expression_bodied_properties = true:silent -csharp_style_expression_bodied_indexers = true:silent -csharp_style_expression_bodied_accessors = true:silent -csharp_style_expression_bodied_lambdas = true:silent -csharp_style_expression_bodied_local_functions = false:silent +csharp_style_expression_bodied_methods = false +csharp_style_expression_bodied_constructors = false +csharp_style_expression_bodied_operators = false +csharp_style_expression_bodied_properties = true +csharp_style_expression_bodied_indexers = true +csharp_style_expression_bodied_accessors = true +csharp_style_expression_bodied_lambdas = true +csharp_style_expression_bodied_local_functions = false +dotnet_diagnostic.IDE0007.severity = none +dotnet_diagnostic.IDE0008.severity = none csharp_space_around_binary_operators = before_and_after [*.{cs,vb}] @@ -84,10 +94,19 @@ end_of_line = crlf dotnet_style_coalesce_expression = true:suggestion dotnet_style_null_propagation = true:suggestion dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion -dotnet_style_prefer_auto_properties = true:silent +dotnet_style_prefer_auto_properties = true dotnet_style_object_initializer = true:suggestion dotnet_style_collection_initializer = true:suggestion dotnet_style_prefer_simplified_boolean_expressions = true:suggestion # SA:1602 Disable enumeration documentation -dotnet_diagnostic.SA1602.severity = none \ No newline at end of file +dotnet_diagnostic.SA1602.severity = none + +# Disable langauge rules +dotnet_diagnostic.CA1303.severity = none +dotnet_diagnostic.CA1304.severity = none +dotnet_diagnostic.CA1311.severity = none +dotnet_diagnostic.CA1305.severity = none + +# disable style rules so they don't overlap with stylecop +dotnet_analyzer_diagnostic.category-Style.severity = none diff --git a/FU.API/FU.API/Controllers/SearchController.cs b/FU.API/FU.API/Controllers/SearchController.cs index 23f58858..a06e2fdd 100644 --- a/FU.API/FU.API/Controllers/SearchController.cs +++ b/FU.API/FU.API/Controllers/SearchController.cs @@ -2,10 +2,8 @@ namespace FU.API.Controllers; using FU.API.DTOs.Post; using FU.API.DTOs.Search; -using FU.API.Exceptions; using FU.API.Helpers; using FU.API.Interfaces; -using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; [ApiController] @@ -24,7 +22,7 @@ public SearchController(ISearchService searchService) public async Task SearchPosts([FromQuery] PostSearchRequestDTO request) { var posts = await _searchService.SearchPosts(request.ToPostQuery()); - var response = new List(posts.Count()); + var response = new List(posts.Count); // Go through each post and check if the user has joined the post var user = await _searchService.GetCurrentUser(User); @@ -44,4 +42,4 @@ public async Task SearchPosts([FromQuery] PostSearchRequestDTO re return Ok(response); } -} \ No newline at end of file +} diff --git a/FU.API/FU.API/DTOs/Group/GroupSimpleDTO.cs b/FU.API/FU.API/DTOs/Group/GroupSimpleDTO.cs index f0d9f637..7db8f6f6 100644 --- a/FU.API/FU.API/DTOs/Group/GroupSimpleDTO.cs +++ b/FU.API/FU.API/DTOs/Group/GroupSimpleDTO.cs @@ -1,14 +1,14 @@ -namespace FU.API.DTOs.Group; - -public class GroupSimpleDTO -{ - public int Id { get; set; } - - public string Name { get; set; } = string.Empty; - - public string? Description { get; set; } - - public int ChatId { get; set; } - - public ICollection Tags { get; set; } = new HashSet(); -} +namespace FU.API.DTOs.Group; + +public class GroupSimpleDTO +{ + public int Id { get; set; } + + public string Name { get; set; } = string.Empty; + + public string? Description { get; set; } + + public int ChatId { get; set; } + + public ICollection Tags { get; set; } = new HashSet(); +} diff --git a/FU.API/FU.API/Data/AppDbContext.cs b/FU.API/FU.API/Data/AppDbContext.cs index 5e3b77e5..f467ec17 100644 --- a/FU.API/FU.API/Data/AppDbContext.cs +++ b/FU.API/FU.API/Data/AppDbContext.cs @@ -20,100 +20,100 @@ public AppDbContext(DbContextOptions options) /// /// Create new models. /// - /// The builder. - protected override void OnModelCreating(ModelBuilder builder) + /// The builder. + protected override void OnModelCreating(ModelBuilder modelBuilder) { // Give 1 foreign key to Chat for LastMessage - builder.Entity() + modelBuilder.Entity() .HasOne(c => c.LastMessage) .WithOne() .HasForeignKey(c => c.LastMessageId); // Make sure the username is unique - builder.Entity() + modelBuilder.Entity() .HasIndex(u => u.Username) .IsUnique(); // Make sure the email is unique - builder.Entity() + modelBuilder.Entity() .HasIndex(u => u.Email) .IsUnique(); // Make sure the name of the tag is unique - builder.Entity() + modelBuilder.Entity() .HasIndex(t => t.Name) .IsUnique(); // Make sure the name of the group is unique - builder.Entity() + modelBuilder.Entity() .HasIndex(g => g.Name) .IsUnique(); // Make sure the name of the game is unique - builder.Entity() + modelBuilder.Entity() .HasIndex(g => g.Name) .IsUnique(); - base.OnModelCreating(builder); + base.OnModelCreating(modelBuilder); } /// /// Gets or sets the users. /// - public DbSet Users { get; set; } + public DbSet Users { get; set; } = null!; /// /// Gets or sets UserRelations. /// - public DbSet UserRelations { get; set; } + public DbSet UserRelations { get; set; } = null!; /// /// Gets or sets chats. /// - public DbSet Chats { get; set; } + public DbSet Chats { get; set; } = null!; /// /// Gets or sets ChatMemberships. /// - public DbSet ChatMemberships { get; set; } + public DbSet ChatMemberships { get; set; } = null!; /// /// Gets or sets Messages. /// - public DbSet Messages { get; set; } + public DbSet Messages { get; set; } = null!; /// /// Gets or sets Games. /// - public DbSet Games { get; set; } + public DbSet Games { get; set; } = null!; /// /// Gets or sets GameRelations. /// - public DbSet GameRelations { get; set; } + public DbSet GameRelations { get; set; } = null!; /// /// Gets or sets Groups. /// - public DbSet Groups { get; set; } + public DbSet Groups { get; set; } = null!; /// /// Gets or sets GroupMemberships. /// - public DbSet GroupMemberships { get; set; } + public DbSet GroupMemberships { get; set; } = null!; /// /// Gets or sets Posts. /// - public DbSet Posts { get; set; } + public DbSet Posts { get; set; } = null!; /// /// Gets or sets Tags. /// - public DbSet Tags { get; set; } + public DbSet Tags { get; set; } = null!; /// /// Gets or sets TagRelations. /// - public DbSet TagRelations { get; set; } + public DbSet TagRelations { get; set; } = null!; } diff --git a/FU.API/FU.API/FU.API.csproj b/FU.API/FU.API/FU.API.csproj index 50df0673..b21f5097 100644 --- a/FU.API/FU.API/FU.API.csproj +++ b/FU.API/FU.API/FU.API.csproj @@ -12,6 +12,7 @@ + diff --git a/FU.API/FU.API/Helpers/Exceptions.cs b/FU.API/FU.API/Helpers/Exceptions.cs index d731938a..476424af 100644 --- a/FU.API/FU.API/Helpers/Exceptions.cs +++ b/FU.API/FU.API/Helpers/Exceptions.cs @@ -13,7 +13,7 @@ public abstract class ExceptionWithResponse : Exception public ProblemDetails GetProblemDetails() { - return new () + return new() { Title = Title, Detail = Description, @@ -116,4 +116,4 @@ public ConflictException(string description) { Description = description; } -} \ No newline at end of file +} diff --git a/FU.API/FU.API/Helpers/IsLoggedInAuthenticationHandler.cs b/FU.API/FU.API/Helpers/IsLoggedInAuthenticationHandler.cs index 2b28a716..1a9a0362 100644 --- a/FU.API/FU.API/Helpers/IsLoggedInAuthenticationHandler.cs +++ b/FU.API/FU.API/Helpers/IsLoggedInAuthenticationHandler.cs @@ -1,4 +1,5 @@ -using FU.API.Helpers; +namespace FU.API.Helpers; + using Microsoft.AspNetCore.Authorization; /// @@ -31,4 +32,4 @@ protected override Task HandleRequirementAsync(AuthorizationHandlerContext conte return Task.CompletedTask; } -} \ No newline at end of file +} diff --git a/FU.API/FU.API/Helpers/IsLoggedInRequirement.cs b/FU.API/FU.API/Helpers/IsLoggedInRequirement.cs index ab6056c7..fb22c545 100644 --- a/FU.API/FU.API/Helpers/IsLoggedInRequirement.cs +++ b/FU.API/FU.API/Helpers/IsLoggedInRequirement.cs @@ -1,3 +1,5 @@ +namespace FU.API.Helpers; + using Microsoft.AspNetCore.Authorization; /// diff --git a/FU.API/FU.API/Helpers/Mapper.cs b/FU.API/FU.API/Helpers/Mapper.cs index 84f1d97f..7d3ed58b 100644 --- a/FU.API/FU.API/Helpers/Mapper.cs +++ b/FU.API/FU.API/Helpers/Mapper.cs @@ -88,12 +88,12 @@ public static PostQuery ToPostQuery(this PostSearchRequestDTO dto) MinimumRequiredPlayers = dto.MinPlayers ?? 0, Limit = dto.Limit ?? 20, Offset = dto.Offset ?? 0, - SortBy = new () + SortBy = new() }; if (dto.Keywords is not null) { - query.DescriptionContains = dto.Keywords.Split(" ").ToList(); + query.Keywords = dto.Keywords.Split(" ").ToList(); } if (dto.Games is not null) @@ -196,4 +196,4 @@ public static GroupSimpleDTO ToSimpleDto(this Group group) public static IEnumerable ToSimpleDtos(this IEnumerable groups) => groups.Select(group => group.ToSimpleDto()); -} \ No newline at end of file +} diff --git a/FU.API/FU.API/Hubs/ChatHub.cs b/FU.API/FU.API/Hubs/ChatHub.cs index 4b187c08..40c7e65d 100644 --- a/FU.API/FU.API/Hubs/ChatHub.cs +++ b/FU.API/FU.API/Hubs/ChatHub.cs @@ -3,7 +3,6 @@ using System; using FU.API.Data; using FU.API.Helpers; -using FU.API.Interfaces; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.SignalR; @@ -16,7 +15,7 @@ public class ChatHub : Hub /// /// List of the connected users names. /// - public static readonly List ConnectedUsers = new (); + public static readonly List ConnectedUsers = new(); /// /// The app db context. diff --git a/FU.API/FU.API/Interfaces/ICommonService.cs b/FU.API/FU.API/Interfaces/ICommonService.cs index bac99cb2..39a73628 100644 --- a/FU.API/FU.API/Interfaces/ICommonService.cs +++ b/FU.API/FU.API/Interfaces/ICommonService.cs @@ -1,13 +1,13 @@ -namespace FU.API.Interfaces; - -using FU.API.Models; -using System.Security.Claims; - -public interface ICommonService -{ - Task GetCurrentUser(ClaimsPrincipal claims); - - Task GetUser(int userId); - - Task HasJoinedPost(int userId, int postId); +namespace FU.API.Interfaces; + +using FU.API.Models; +using System.Security.Claims; + +public interface ICommonService +{ + Task GetCurrentUser(ClaimsPrincipal claims); + + Task GetUser(int userId); + + Task HasJoinedPost(int userId, int postId); } \ No newline at end of file diff --git a/FU.API/FU.API/Interfaces/IPostService.cs b/FU.API/FU.API/Interfaces/IPostService.cs index 19e3d16e..55b48fb3 100644 --- a/FU.API/FU.API/Interfaces/IPostService.cs +++ b/FU.API/FU.API/Interfaces/IPostService.cs @@ -1,14 +1,14 @@ -namespace FU.API.Interfaces; - -using FU.API.Models; - -public interface IPostService : ICommonService -{ - Task CreatePost(Post post); - - Task GetPost(int postId); - - Task JoinPost(int postId, ApplicationUser user); - - Task LeavePost(int postId, ApplicationUser user); -} +namespace FU.API.Interfaces; + +using FU.API.Models; + +public interface IPostService : ICommonService +{ + Task CreatePost(Post post); + + Task GetPost(int postId); + + Task JoinPost(int postId, ApplicationUser user); + + Task LeavePost(int postId, ApplicationUser user); +} diff --git a/FU.API/FU.API/Interfaces/ISearchService.cs b/FU.API/FU.API/Interfaces/ISearchService.cs index 6d09686d..eeb9a137 100644 --- a/FU.API/FU.API/Interfaces/ISearchService.cs +++ b/FU.API/FU.API/Interfaces/ISearchService.cs @@ -1,8 +1,8 @@ -namespace FU.API.Interfaces; - -using FU.API.Models; - -public interface ISearchService : ICommonService -{ - Task> SearchPosts(PostQuery query); -} +namespace FU.API.Interfaces; + +using FU.API.Models; + +public interface ISearchService : ICommonService +{ + Task> SearchPosts(PostQuery query); +} diff --git a/FU.API/FU.API/Interfaces/IUserService.cs b/FU.API/FU.API/Interfaces/IUserService.cs index 75c7aa15..3bfa39e7 100644 --- a/FU.API/FU.API/Interfaces/IUserService.cs +++ b/FU.API/FU.API/Interfaces/IUserService.cs @@ -1,16 +1,16 @@ -namespace FU.API.Interfaces; - -using FU.API.Models; - -public interface IUserService : ICommonService -{ - Task GetUserProfile(int userId); - - Task UpdateUserProfile(UserProfile profileChanges); - - Task> GetUsersAssociatedPosts(int userId, int limit, int offset); - - Task> GetUsersGroups(int userId, int limit, int offset); - - Task> GetUsersPlayers(int userId, int limit, int offset); -} +namespace FU.API.Interfaces; + +using FU.API.Models; + +public interface IUserService : ICommonService +{ + Task GetUserProfile(int userId); + + Task UpdateUserProfile(UserProfile profileChanges); + + Task> GetUsersAssociatedPosts(int userId, int limit, int offset); + + Task> GetUsersGroups(int userId, int limit, int offset); + + Task> GetUsersPlayers(int userId, int limit, int offset); +} diff --git a/FU.API/FU.API/Migrations/20231127022356_InitialDatabase.cs b/FU.API/FU.API/Migrations/20231127022356_InitialDatabase.cs index dbda35bf..3aa64ec1 100644 --- a/FU.API/FU.API/Migrations/20231127022356_InitialDatabase.cs +++ b/FU.API/FU.API/Migrations/20231127022356_InitialDatabase.cs @@ -1,516 +1,516 @@ -#nullable disable - -namespace FU.API.Migrations -{ - using System; - using Microsoft.EntityFrameworkCore.Migrations; - using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - - /// - public partial class InitialDatabase : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "Games", - columns: table => new - { - Id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - Name = table.Column(type: "text", nullable: false), - NormalizedName = table.Column(type: "text", nullable: false), - ImageUrl = table.Column(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Games", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "Tags", - columns: table => new - { - Id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - Name = table.Column(type: "character varying(50)", maxLength: 50, nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Tags", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "Users", - columns: table => new - { - UserId = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - PfpUrl = table.Column(type: "text", nullable: false), - IsOnline = table.Column(type: "boolean", nullable: false), - IsAdmin = table.Column(type: "boolean", nullable: false), - Bio = table.Column(type: "text", nullable: true), - DOB = table.Column(type: "date", nullable: true), - Username = table.Column(type: "text", nullable: false), - NormalizedUsername = table.Column(type: "text", nullable: false), - PasswordHash = table.Column(type: "text", nullable: false), - Email = table.Column(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Users", x => x.UserId); - }); - - migrationBuilder.CreateTable( - name: "GameRelations", - columns: table => new - { - Id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - GameId = table.Column(type: "integer", nullable: false), - ApplicationUserUserId = table.Column(type: "integer", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_GameRelations", x => x.Id); - table.ForeignKey( - name: "FK_GameRelations_Games_GameId", - column: x => x.GameId, - principalTable: "Games", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_GameRelations_Users_ApplicationUserUserId", - column: x => x.ApplicationUserUserId, - principalTable: "Users", - principalColumn: "UserId"); - }); - - migrationBuilder.CreateTable( - name: "UserRelations", - columns: table => new - { - Id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - User1Id = table.Column(type: "integer", nullable: false), - User2Id = table.Column(type: "integer", nullable: false), - Status = table.Column(type: "integer", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_UserRelations", x => x.Id); - table.ForeignKey( - name: "FK_UserRelations_Users_User1Id", - column: x => x.User1Id, - principalTable: "Users", - principalColumn: "UserId", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_UserRelations_Users_User2Id", - column: x => x.User2Id, - principalTable: "Users", - principalColumn: "UserId", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "ChatMemberships", - columns: table => new - { - Id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - UserId = table.Column(type: "integer", nullable: false), - ChatId = table.Column(type: "integer", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_ChatMemberships", x => x.Id); - table.ForeignKey( - name: "FK_ChatMemberships_Users_UserId", - column: x => x.UserId, - principalTable: "Users", - principalColumn: "UserId", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "Chats", - columns: table => new - { - Id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - ChatName = table.Column(type: "text", nullable: true), - ChatType = table.Column(type: "integer", nullable: false), - CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), - LastMessageId = table.Column(type: "integer", nullable: true), - LastMessageAt = table.Column(type: "timestamp with time zone", nullable: true), - CreatorId = table.Column(type: "integer", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Chats", x => x.Id); - table.ForeignKey( - name: "FK_Chats_Users_CreatorId", - column: x => x.CreatorId, - principalTable: "Users", - principalColumn: "UserId"); - }); - - migrationBuilder.CreateTable( - name: "Groups", - columns: table => new - { - Id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - Name = table.Column(type: "text", nullable: false), - NormalizedName = table.Column(type: "text", nullable: false), - ImageUrl = table.Column(type: "text", nullable: true), - Description = table.Column(type: "text", nullable: true), - CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), - CreatorId = table.Column(type: "integer", nullable: true), - ChatId = table.Column(type: "integer", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Groups", x => x.Id); - table.ForeignKey( - name: "FK_Groups_Chats_ChatId", - column: x => x.ChatId, - principalTable: "Chats", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_Groups_Users_CreatorId", - column: x => x.CreatorId, - principalTable: "Users", - principalColumn: "UserId"); - }); - - migrationBuilder.CreateTable( - name: "Messages", - columns: table => new - { - Id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), - Content = table.Column(type: "text", nullable: false), - SenderId = table.Column(type: "integer", nullable: false), - ChatId = table.Column(type: "integer", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Messages", x => x.Id); - table.ForeignKey( - name: "FK_Messages_Chats_ChatId", - column: x => x.ChatId, - principalTable: "Chats", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_Messages_Users_SenderId", - column: x => x.SenderId, - principalTable: "Users", - principalColumn: "UserId", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "Posts", - columns: table => new - { - Id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - Title = table.Column(type: "text", nullable: false), - GameId = table.Column(type: "integer", nullable: false), - Description = table.Column(type: "text", nullable: true), - StartTime = table.Column(type: "timestamp with time zone", nullable: true), - EndTime = table.Column(type: "timestamp with time zone", nullable: true), - MaxPlayers = table.Column(type: "integer", nullable: true), - ChatId = table.Column(type: "integer", nullable: false), - CreatorId = table.Column(type: "integer", nullable: false), - CreatedAt = table.Column(type: "timestamp with time zone", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Posts", x => x.Id); - table.ForeignKey( - name: "FK_Posts_Chats_ChatId", - column: x => x.ChatId, - principalTable: "Chats", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_Posts_Games_GameId", - column: x => x.GameId, - principalTable: "Games", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_Posts_Users_CreatorId", - column: x => x.CreatorId, - principalTable: "Users", - principalColumn: "UserId", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "GroupMemberships", - columns: table => new - { - Id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - UserId = table.Column(type: "integer", nullable: false), - GroupId = table.Column(type: "integer", nullable: false), - Role = table.Column(type: "integer", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_GroupMemberships", x => x.Id); - table.ForeignKey( - name: "FK_GroupMemberships_Groups_GroupId", - column: x => x.GroupId, - principalTable: "Groups", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_GroupMemberships_Users_UserId", - column: x => x.UserId, - principalTable: "Users", - principalColumn: "UserId", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "TagRelations", - columns: table => new - { - Id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - TagId = table.Column(type: "integer", nullable: false), - ApplicationUserUserId = table.Column(type: "integer", nullable: true), - GroupId = table.Column(type: "integer", nullable: true), - PostId = table.Column(type: "integer", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_TagRelations", x => x.Id); - table.ForeignKey( - name: "FK_TagRelations_Groups_GroupId", - column: x => x.GroupId, - principalTable: "Groups", - principalColumn: "Id"); - table.ForeignKey( - name: "FK_TagRelations_Posts_PostId", - column: x => x.PostId, - principalTable: "Posts", - principalColumn: "Id"); - table.ForeignKey( - name: "FK_TagRelations_Tags_TagId", - column: x => x.TagId, - principalTable: "Tags", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_TagRelations_Users_ApplicationUserUserId", - column: x => x.ApplicationUserUserId, - principalTable: "Users", - principalColumn: "UserId"); - }); - - migrationBuilder.CreateIndex( - name: "IX_ChatMemberships_ChatId", - table: "ChatMemberships", - column: "ChatId"); - - migrationBuilder.CreateIndex( - name: "IX_ChatMemberships_UserId", - table: "ChatMemberships", - column: "UserId"); - - migrationBuilder.CreateIndex( - name: "IX_Chats_CreatorId", - table: "Chats", - column: "CreatorId"); - - migrationBuilder.CreateIndex( - name: "IX_Chats_LastMessageId", - table: "Chats", - column: "LastMessageId", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_GameRelations_ApplicationUserUserId", - table: "GameRelations", - column: "ApplicationUserUserId"); - - migrationBuilder.CreateIndex( - name: "IX_GameRelations_GameId", - table: "GameRelations", - column: "GameId"); - - migrationBuilder.CreateIndex( - name: "IX_Games_Name", - table: "Games", - column: "Name", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_GroupMemberships_GroupId", - table: "GroupMemberships", - column: "GroupId"); - - migrationBuilder.CreateIndex( - name: "IX_GroupMemberships_UserId", - table: "GroupMemberships", - column: "UserId"); - - migrationBuilder.CreateIndex( - name: "IX_Groups_ChatId", - table: "Groups", - column: "ChatId"); - - migrationBuilder.CreateIndex( - name: "IX_Groups_CreatorId", - table: "Groups", - column: "CreatorId"); - - migrationBuilder.CreateIndex( - name: "IX_Groups_Name", - table: "Groups", - column: "Name", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_Messages_ChatId", - table: "Messages", - column: "ChatId"); - - migrationBuilder.CreateIndex( - name: "IX_Messages_SenderId", - table: "Messages", - column: "SenderId"); - - migrationBuilder.CreateIndex( - name: "IX_Posts_ChatId", - table: "Posts", - column: "ChatId"); - - migrationBuilder.CreateIndex( - name: "IX_Posts_CreatorId", - table: "Posts", - column: "CreatorId"); - - migrationBuilder.CreateIndex( - name: "IX_Posts_GameId", - table: "Posts", - column: "GameId"); - - migrationBuilder.CreateIndex( - name: "IX_TagRelations_ApplicationUserUserId", - table: "TagRelations", - column: "ApplicationUserUserId"); - - migrationBuilder.CreateIndex( - name: "IX_TagRelations_GroupId", - table: "TagRelations", - column: "GroupId"); - - migrationBuilder.CreateIndex( - name: "IX_TagRelations_PostId", - table: "TagRelations", - column: "PostId"); - - migrationBuilder.CreateIndex( - name: "IX_TagRelations_TagId", - table: "TagRelations", - column: "TagId"); - - migrationBuilder.CreateIndex( - name: "IX_Tags_Name", - table: "Tags", - column: "Name", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_UserRelations_User1Id", - table: "UserRelations", - column: "User1Id"); - - migrationBuilder.CreateIndex( - name: "IX_UserRelations_User2Id", - table: "UserRelations", - column: "User2Id"); - - migrationBuilder.CreateIndex( - name: "IX_Users_Email", - table: "Users", - column: "Email", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_Users_Username", - table: "Users", - column: "Username", - unique: true); - - migrationBuilder.AddForeignKey( - name: "FK_ChatMemberships_Chats_ChatId", - table: "ChatMemberships", - column: "ChatId", - principalTable: "Chats", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_Chats_Messages_LastMessageId", - table: "Chats", - column: "LastMessageId", - principalTable: "Messages", - principalColumn: "Id"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropForeignKey( - name: "FK_Messages_Chats_ChatId", - table: "Messages"); - - migrationBuilder.DropTable( - name: "ChatMemberships"); - - migrationBuilder.DropTable( - name: "GameRelations"); - - migrationBuilder.DropTable( - name: "GroupMemberships"); - - migrationBuilder.DropTable( - name: "TagRelations"); - - migrationBuilder.DropTable( - name: "UserRelations"); - - migrationBuilder.DropTable( - name: "Groups"); - - migrationBuilder.DropTable( - name: "Posts"); - - migrationBuilder.DropTable( - name: "Tags"); - - migrationBuilder.DropTable( - name: "Games"); - - migrationBuilder.DropTable( - name: "Chats"); - - migrationBuilder.DropTable( - name: "Messages"); - - migrationBuilder.DropTable( - name: "Users"); - } - } -} +#nullable disable + +namespace FU.API.Migrations +{ + using System; + using Microsoft.EntityFrameworkCore.Migrations; + using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + + /// + public partial class InitialDatabase : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Games", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Name = table.Column(type: "text", nullable: false), + NormalizedName = table.Column(type: "text", nullable: false), + ImageUrl = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Games", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Tags", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Name = table.Column(type: "character varying(50)", maxLength: 50, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Tags", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Users", + columns: table => new + { + UserId = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + PfpUrl = table.Column(type: "text", nullable: false), + IsOnline = table.Column(type: "boolean", nullable: false), + IsAdmin = table.Column(type: "boolean", nullable: false), + Bio = table.Column(type: "text", nullable: true), + DOB = table.Column(type: "date", nullable: true), + Username = table.Column(type: "text", nullable: false), + NormalizedUsername = table.Column(type: "text", nullable: false), + PasswordHash = table.Column(type: "text", nullable: false), + Email = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Users", x => x.UserId); + }); + + migrationBuilder.CreateTable( + name: "GameRelations", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + GameId = table.Column(type: "integer", nullable: false), + ApplicationUserUserId = table.Column(type: "integer", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_GameRelations", x => x.Id); + table.ForeignKey( + name: "FK_GameRelations_Games_GameId", + column: x => x.GameId, + principalTable: "Games", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_GameRelations_Users_ApplicationUserUserId", + column: x => x.ApplicationUserUserId, + principalTable: "Users", + principalColumn: "UserId"); + }); + + migrationBuilder.CreateTable( + name: "UserRelations", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + User1Id = table.Column(type: "integer", nullable: false), + User2Id = table.Column(type: "integer", nullable: false), + Status = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_UserRelations", x => x.Id); + table.ForeignKey( + name: "FK_UserRelations_Users_User1Id", + column: x => x.User1Id, + principalTable: "Users", + principalColumn: "UserId", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_UserRelations_Users_User2Id", + column: x => x.User2Id, + principalTable: "Users", + principalColumn: "UserId", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "ChatMemberships", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + UserId = table.Column(type: "integer", nullable: false), + ChatId = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ChatMemberships", x => x.Id); + table.ForeignKey( + name: "FK_ChatMemberships_Users_UserId", + column: x => x.UserId, + principalTable: "Users", + principalColumn: "UserId", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Chats", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + ChatName = table.Column(type: "text", nullable: true), + ChatType = table.Column(type: "integer", nullable: false), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + LastMessageId = table.Column(type: "integer", nullable: true), + LastMessageAt = table.Column(type: "timestamp with time zone", nullable: true), + CreatorId = table.Column(type: "integer", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Chats", x => x.Id); + table.ForeignKey( + name: "FK_Chats_Users_CreatorId", + column: x => x.CreatorId, + principalTable: "Users", + principalColumn: "UserId"); + }); + + migrationBuilder.CreateTable( + name: "Groups", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Name = table.Column(type: "text", nullable: false), + NormalizedName = table.Column(type: "text", nullable: false), + ImageUrl = table.Column(type: "text", nullable: true), + Description = table.Column(type: "text", nullable: true), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + CreatorId = table.Column(type: "integer", nullable: true), + ChatId = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Groups", x => x.Id); + table.ForeignKey( + name: "FK_Groups_Chats_ChatId", + column: x => x.ChatId, + principalTable: "Chats", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_Groups_Users_CreatorId", + column: x => x.CreatorId, + principalTable: "Users", + principalColumn: "UserId"); + }); + + migrationBuilder.CreateTable( + name: "Messages", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + Content = table.Column(type: "text", nullable: false), + SenderId = table.Column(type: "integer", nullable: false), + ChatId = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Messages", x => x.Id); + table.ForeignKey( + name: "FK_Messages_Chats_ChatId", + column: x => x.ChatId, + principalTable: "Chats", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_Messages_Users_SenderId", + column: x => x.SenderId, + principalTable: "Users", + principalColumn: "UserId", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Posts", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Title = table.Column(type: "text", nullable: false), + GameId = table.Column(type: "integer", nullable: false), + Description = table.Column(type: "text", nullable: true), + StartTime = table.Column(type: "timestamp with time zone", nullable: true), + EndTime = table.Column(type: "timestamp with time zone", nullable: true), + MaxPlayers = table.Column(type: "integer", nullable: true), + ChatId = table.Column(type: "integer", nullable: false), + CreatorId = table.Column(type: "integer", nullable: false), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Posts", x => x.Id); + table.ForeignKey( + name: "FK_Posts_Chats_ChatId", + column: x => x.ChatId, + principalTable: "Chats", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_Posts_Games_GameId", + column: x => x.GameId, + principalTable: "Games", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_Posts_Users_CreatorId", + column: x => x.CreatorId, + principalTable: "Users", + principalColumn: "UserId", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "GroupMemberships", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + UserId = table.Column(type: "integer", nullable: false), + GroupId = table.Column(type: "integer", nullable: false), + Role = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_GroupMemberships", x => x.Id); + table.ForeignKey( + name: "FK_GroupMemberships_Groups_GroupId", + column: x => x.GroupId, + principalTable: "Groups", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_GroupMemberships_Users_UserId", + column: x => x.UserId, + principalTable: "Users", + principalColumn: "UserId", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "TagRelations", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + TagId = table.Column(type: "integer", nullable: false), + ApplicationUserUserId = table.Column(type: "integer", nullable: true), + GroupId = table.Column(type: "integer", nullable: true), + PostId = table.Column(type: "integer", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_TagRelations", x => x.Id); + table.ForeignKey( + name: "FK_TagRelations_Groups_GroupId", + column: x => x.GroupId, + principalTable: "Groups", + principalColumn: "Id"); + table.ForeignKey( + name: "FK_TagRelations_Posts_PostId", + column: x => x.PostId, + principalTable: "Posts", + principalColumn: "Id"); + table.ForeignKey( + name: "FK_TagRelations_Tags_TagId", + column: x => x.TagId, + principalTable: "Tags", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_TagRelations_Users_ApplicationUserUserId", + column: x => x.ApplicationUserUserId, + principalTable: "Users", + principalColumn: "UserId"); + }); + + migrationBuilder.CreateIndex( + name: "IX_ChatMemberships_ChatId", + table: "ChatMemberships", + column: "ChatId"); + + migrationBuilder.CreateIndex( + name: "IX_ChatMemberships_UserId", + table: "ChatMemberships", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_Chats_CreatorId", + table: "Chats", + column: "CreatorId"); + + migrationBuilder.CreateIndex( + name: "IX_Chats_LastMessageId", + table: "Chats", + column: "LastMessageId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_GameRelations_ApplicationUserUserId", + table: "GameRelations", + column: "ApplicationUserUserId"); + + migrationBuilder.CreateIndex( + name: "IX_GameRelations_GameId", + table: "GameRelations", + column: "GameId"); + + migrationBuilder.CreateIndex( + name: "IX_Games_Name", + table: "Games", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_GroupMemberships_GroupId", + table: "GroupMemberships", + column: "GroupId"); + + migrationBuilder.CreateIndex( + name: "IX_GroupMemberships_UserId", + table: "GroupMemberships", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_Groups_ChatId", + table: "Groups", + column: "ChatId"); + + migrationBuilder.CreateIndex( + name: "IX_Groups_CreatorId", + table: "Groups", + column: "CreatorId"); + + migrationBuilder.CreateIndex( + name: "IX_Groups_Name", + table: "Groups", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Messages_ChatId", + table: "Messages", + column: "ChatId"); + + migrationBuilder.CreateIndex( + name: "IX_Messages_SenderId", + table: "Messages", + column: "SenderId"); + + migrationBuilder.CreateIndex( + name: "IX_Posts_ChatId", + table: "Posts", + column: "ChatId"); + + migrationBuilder.CreateIndex( + name: "IX_Posts_CreatorId", + table: "Posts", + column: "CreatorId"); + + migrationBuilder.CreateIndex( + name: "IX_Posts_GameId", + table: "Posts", + column: "GameId"); + + migrationBuilder.CreateIndex( + name: "IX_TagRelations_ApplicationUserUserId", + table: "TagRelations", + column: "ApplicationUserUserId"); + + migrationBuilder.CreateIndex( + name: "IX_TagRelations_GroupId", + table: "TagRelations", + column: "GroupId"); + + migrationBuilder.CreateIndex( + name: "IX_TagRelations_PostId", + table: "TagRelations", + column: "PostId"); + + migrationBuilder.CreateIndex( + name: "IX_TagRelations_TagId", + table: "TagRelations", + column: "TagId"); + + migrationBuilder.CreateIndex( + name: "IX_Tags_Name", + table: "Tags", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_UserRelations_User1Id", + table: "UserRelations", + column: "User1Id"); + + migrationBuilder.CreateIndex( + name: "IX_UserRelations_User2Id", + table: "UserRelations", + column: "User2Id"); + + migrationBuilder.CreateIndex( + name: "IX_Users_Email", + table: "Users", + column: "Email", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Users_Username", + table: "Users", + column: "Username", + unique: true); + + migrationBuilder.AddForeignKey( + name: "FK_ChatMemberships_Chats_ChatId", + table: "ChatMemberships", + column: "ChatId", + principalTable: "Chats", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_Chats_Messages_LastMessageId", + table: "Chats", + column: "LastMessageId", + principalTable: "Messages", + principalColumn: "Id"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Messages_Chats_ChatId", + table: "Messages"); + + migrationBuilder.DropTable( + name: "ChatMemberships"); + + migrationBuilder.DropTable( + name: "GameRelations"); + + migrationBuilder.DropTable( + name: "GroupMemberships"); + + migrationBuilder.DropTable( + name: "TagRelations"); + + migrationBuilder.DropTable( + name: "UserRelations"); + + migrationBuilder.DropTable( + name: "Groups"); + + migrationBuilder.DropTable( + name: "Posts"); + + migrationBuilder.DropTable( + name: "Tags"); + + migrationBuilder.DropTable( + name: "Games"); + + migrationBuilder.DropTable( + name: "Chats"); + + migrationBuilder.DropTable( + name: "Messages"); + + migrationBuilder.DropTable( + name: "Users"); + } + } +} diff --git a/FU.API/FU.API/Migrations/20231203001316_NonNullablePostDescription.cs b/FU.API/FU.API/Migrations/20231203001316_NonNullablePostDescription.cs index 47762e41..f7801599 100644 --- a/FU.API/FU.API/Migrations/20231203001316_NonNullablePostDescription.cs +++ b/FU.API/FU.API/Migrations/20231203001316_NonNullablePostDescription.cs @@ -1,36 +1,36 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace FU.API.Migrations -{ - /// - public partial class NonNullablePostDescription : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AlterColumn( - name: "Description", - table: "Posts", - type: "text", - nullable: false, - defaultValue: "", - oldClrType: typeof(string), - oldType: "text", - oldNullable: true); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.AlterColumn( - name: "Description", - table: "Posts", - type: "text", - nullable: true, - oldClrType: typeof(string), - oldType: "text"); - } - } -} +#nullable disable + +namespace FU.API.Migrations +{ + using Microsoft.EntityFrameworkCore.Migrations; + + /// + public partial class NonNullablePostDescription : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Description", + table: "Posts", + type: "text", + nullable: false, + defaultValue: string.Empty, + oldClrType: typeof(string), + oldType: "text", + oldNullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Description", + table: "Posts", + type: "text", + nullable: true, + oldClrType: typeof(string), + oldType: "text"); + } + } +} diff --git a/FU.API/FU.API/Migrations/20240123145358_NormalizedPostDescAndTitle.Designer.cs b/FU.API/FU.API/Migrations/20240123145358_NormalizedPostDescAndTitle.Designer.cs new file mode 100644 index 00000000..cc3fcbcc --- /dev/null +++ b/FU.API/FU.API/Migrations/20240123145358_NormalizedPostDescAndTitle.Designer.cs @@ -0,0 +1,627 @@ +// +using System; +using FU.API.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace FU.API.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20240123145358_NormalizedPostDescAndTitle")] + partial class NormalizedPostDescAndTitle + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.13") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("FU.API.Models.ApplicationUser", b => + { + b.Property("UserId") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("UserId")); + + b.Property("Bio") + .HasColumnType("text"); + + b.Property("DOB") + .HasColumnType("date"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("IsAdmin") + .HasColumnType("boolean"); + + b.Property("IsOnline") + .HasColumnType("boolean"); + + b.Property("NormalizedUsername") + .IsRequired() + .HasColumnType("text"); + + b.Property("PasswordHash") + .IsRequired() + .HasColumnType("text"); + + b.Property("PfpUrl") + .IsRequired() + .HasColumnType("text"); + + b.Property("Username") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("UserId"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("FU.API.Models.Chat", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChatName") + .HasColumnType("text"); + + b.Property("ChatType") + .HasColumnType("integer"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatorId") + .HasColumnType("integer"); + + b.Property("LastMessageAt") + .HasColumnType("timestamp with time zone"); + + b.Property("LastMessageId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("CreatorId"); + + b.HasIndex("LastMessageId") + .IsUnique(); + + b.ToTable("Chats"); + }); + + modelBuilder.Entity("FU.API.Models.ChatMembership", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChatId") + .HasColumnType("integer"); + + b.Property("UserId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ChatId"); + + b.HasIndex("UserId"); + + b.ToTable("ChatMemberships"); + }); + + modelBuilder.Entity("FU.API.Models.Game", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ImageUrl") + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("NormalizedName") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Games"); + }); + + modelBuilder.Entity("FU.API.Models.GameRelation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ApplicationUserUserId") + .HasColumnType("integer"); + + b.Property("GameId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationUserUserId"); + + b.HasIndex("GameId"); + + b.ToTable("GameRelations"); + }); + + modelBuilder.Entity("FU.API.Models.Group", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChatId") + .HasColumnType("integer"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatorId") + .HasColumnType("integer"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("ImageUrl") + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("NormalizedName") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ChatId"); + + b.HasIndex("CreatorId"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Groups"); + }); + + modelBuilder.Entity("FU.API.Models.GroupMembership", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("GroupId") + .HasColumnType("integer"); + + b.Property("Role") + .HasColumnType("integer"); + + b.Property("UserId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("GroupId"); + + b.HasIndex("UserId"); + + b.ToTable("GroupMemberships"); + }); + + modelBuilder.Entity("FU.API.Models.Message", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChatId") + .HasColumnType("integer"); + + b.Property("Content") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("SenderId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ChatId"); + + b.HasIndex("SenderId"); + + b.ToTable("Messages"); + }); + + modelBuilder.Entity("FU.API.Models.Post", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChatId") + .HasColumnType("integer"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatorId") + .HasColumnType("integer"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("EndTime") + .HasColumnType("timestamp with time zone"); + + b.Property("GameId") + .HasColumnType("integer"); + + b.Property("MaxPlayers") + .HasColumnType("integer"); + + b.Property("NormalizedDescription") + .IsRequired() + .HasColumnType("text"); + + b.Property("NormalizedTitle") + .IsRequired() + .HasColumnType("text"); + + b.Property("StartTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ChatId"); + + b.HasIndex("CreatorId"); + + b.HasIndex("GameId"); + + b.ToTable("Posts"); + }); + + modelBuilder.Entity("FU.API.Models.Tag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Tags"); + }); + + modelBuilder.Entity("FU.API.Models.TagRelation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ApplicationUserUserId") + .HasColumnType("integer"); + + b.Property("GroupId") + .HasColumnType("integer"); + + b.Property("PostId") + .HasColumnType("integer"); + + b.Property("TagId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationUserUserId"); + + b.HasIndex("GroupId"); + + b.HasIndex("PostId"); + + b.HasIndex("TagId"); + + b.ToTable("TagRelations"); + }); + + modelBuilder.Entity("FU.API.Models.UserRelation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("User1Id") + .HasColumnType("integer"); + + b.Property("User2Id") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("User1Id"); + + b.HasIndex("User2Id"); + + b.ToTable("UserRelations"); + }); + + modelBuilder.Entity("FU.API.Models.Chat", b => + { + b.HasOne("FU.API.Models.ApplicationUser", "Creator") + .WithMany() + .HasForeignKey("CreatorId"); + + b.HasOne("FU.API.Models.Message", "LastMessage") + .WithOne() + .HasForeignKey("FU.API.Models.Chat", "LastMessageId"); + + b.Navigation("Creator"); + + b.Navigation("LastMessage"); + }); + + modelBuilder.Entity("FU.API.Models.ChatMembership", b => + { + b.HasOne("FU.API.Models.Chat", "Chat") + .WithMany("Members") + .HasForeignKey("ChatId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("FU.API.Models.ApplicationUser", "User") + .WithMany("Chats") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chat"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("FU.API.Models.GameRelation", b => + { + b.HasOne("FU.API.Models.ApplicationUser", null) + .WithMany("FavoriteGames") + .HasForeignKey("ApplicationUserUserId"); + + b.HasOne("FU.API.Models.Game", "Game") + .WithMany() + .HasForeignKey("GameId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Game"); + }); + + modelBuilder.Entity("FU.API.Models.Group", b => + { + b.HasOne("FU.API.Models.Chat", "Chat") + .WithMany() + .HasForeignKey("ChatId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("FU.API.Models.ApplicationUser", "Creator") + .WithMany() + .HasForeignKey("CreatorId"); + + b.Navigation("Chat"); + + b.Navigation("Creator"); + }); + + modelBuilder.Entity("FU.API.Models.GroupMembership", b => + { + b.HasOne("FU.API.Models.Group", "Group") + .WithMany("Memberships") + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("FU.API.Models.ApplicationUser", "User") + .WithMany("Groups") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Group"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("FU.API.Models.Message", b => + { + b.HasOne("FU.API.Models.Chat", "Chat") + .WithMany("Messages") + .HasForeignKey("ChatId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("FU.API.Models.ApplicationUser", "Sender") + .WithMany() + .HasForeignKey("SenderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chat"); + + b.Navigation("Sender"); + }); + + modelBuilder.Entity("FU.API.Models.Post", b => + { + b.HasOne("FU.API.Models.Chat", "Chat") + .WithMany() + .HasForeignKey("ChatId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("FU.API.Models.ApplicationUser", "Creator") + .WithMany() + .HasForeignKey("CreatorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("FU.API.Models.Game", "Game") + .WithMany() + .HasForeignKey("GameId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chat"); + + b.Navigation("Creator"); + + b.Navigation("Game"); + }); + + modelBuilder.Entity("FU.API.Models.TagRelation", b => + { + b.HasOne("FU.API.Models.ApplicationUser", null) + .WithMany("FavoriteTags") + .HasForeignKey("ApplicationUserUserId"); + + b.HasOne("FU.API.Models.Group", null) + .WithMany("Tags") + .HasForeignKey("GroupId"); + + b.HasOne("FU.API.Models.Post", null) + .WithMany("Tags") + .HasForeignKey("PostId"); + + b.HasOne("FU.API.Models.Tag", "Tag") + .WithMany() + .HasForeignKey("TagId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tag"); + }); + + modelBuilder.Entity("FU.API.Models.UserRelation", b => + { + b.HasOne("FU.API.Models.ApplicationUser", "User1") + .WithMany() + .HasForeignKey("User1Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("FU.API.Models.ApplicationUser", "User2") + .WithMany() + .HasForeignKey("User2Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User1"); + + b.Navigation("User2"); + }); + + modelBuilder.Entity("FU.API.Models.ApplicationUser", b => + { + b.Navigation("Chats"); + + b.Navigation("FavoriteGames"); + + b.Navigation("FavoriteTags"); + + b.Navigation("Groups"); + }); + + modelBuilder.Entity("FU.API.Models.Chat", b => + { + b.Navigation("Members"); + + b.Navigation("Messages"); + }); + + modelBuilder.Entity("FU.API.Models.Group", b => + { + b.Navigation("Memberships"); + + b.Navigation("Tags"); + }); + + modelBuilder.Entity("FU.API.Models.Post", b => + { + b.Navigation("Tags"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/FU.API/FU.API/Migrations/20240123145358_NormalizedPostDescAndTitle.cs b/FU.API/FU.API/Migrations/20240123145358_NormalizedPostDescAndTitle.cs new file mode 100644 index 00000000..1103cb67 --- /dev/null +++ b/FU.API/FU.API/Migrations/20240123145358_NormalizedPostDescAndTitle.cs @@ -0,0 +1,40 @@ +#nullable disable + +namespace FU.API.Migrations +{ + using Microsoft.EntityFrameworkCore.Migrations; + + /// + public partial class NormalizedPostDescAndTitle : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "NormalizedDescription", + table: "Posts", + type: "text", + nullable: false, + defaultValue: string.Empty); + + migrationBuilder.AddColumn( + name: "NormalizedTitle", + table: "Posts", + type: "text", + nullable: false, + defaultValue: string.Empty); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "NormalizedDescription", + table: "Posts"); + + migrationBuilder.DropColumn( + name: "NormalizedTitle", + table: "Posts"); + } + } +} diff --git a/FU.API/FU.API/Migrations/AppDbContextModelSnapshot.cs b/FU.API/FU.API/Migrations/AppDbContextModelSnapshot.cs index ed10156f..5c392eae 100644 --- a/FU.API/FU.API/Migrations/AppDbContextModelSnapshot.cs +++ b/FU.API/FU.API/Migrations/AppDbContextModelSnapshot.cs @@ -310,6 +310,14 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("MaxPlayers") .HasColumnType("integer"); + b.Property("NormalizedDescription") + .IsRequired() + .HasColumnType("text"); + + b.Property("NormalizedTitle") + .IsRequired() + .HasColumnType("text"); + b.Property("StartTime") .HasColumnType("timestamp with time zone"); diff --git a/FU.API/FU.API/Models/ApplicationUser.cs b/FU.API/FU.API/Models/ApplicationUser.cs index dfe73a3d..80edf89e 100644 --- a/FU.API/FU.API/Models/ApplicationUser.cs +++ b/FU.API/FU.API/Models/ApplicationUser.cs @@ -3,12 +3,11 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Text.Json.Serialization; -using Microsoft.EntityFrameworkCore; /// /// User of the application. /// -[Index(nameof(Username))] +[Microsoft.EntityFrameworkCore.Index(nameof(Username))] public class ApplicationUser { /// diff --git a/FU.API/FU.API/Models/Post.cs b/FU.API/FU.API/Models/Post.cs index 29df77ed..5ce72382 100644 --- a/FU.API/FU.API/Models/Post.cs +++ b/FU.API/FU.API/Models/Post.cs @@ -1,5 +1,7 @@ namespace FU.API.Models; +using System.ComponentModel.DataAnnotations.Schema; + /// /// The post class. /// @@ -10,10 +12,23 @@ public class Post /// public int Id { get; set; } + [NotMapped] + private string _title = string.Empty; + /// /// Gets or sets the title of the post. /// - public string Title { get; set; } = string.Empty; + public string Title + { + get => _title; + set + { + _title = value; + NormalizedTitle = value.ToUpper(); + } + } + + public string NormalizedTitle { get; set; } = string.Empty; /// /// Gets or sets the game of the post. @@ -28,7 +43,20 @@ public class Post /// /// Gets or sets the description of the post. /// - public string Description { get; set; } = string.Empty; + [NotMapped] + private string _description = string.Empty; + + public string Description + { + get => _description; + set + { + _description = value; + NormalizedDescription = value.ToUpper(); + } + } + + public string NormalizedDescription { get; set; } = string.Empty; /// /// Gets or sets the start time. diff --git a/FU.API/FU.API/Models/PostQuery.cs b/FU.API/FU.API/Models/PostQuery.cs index 879a1525..e280588e 100644 --- a/FU.API/FU.API/Models/PostQuery.cs +++ b/FU.API/FU.API/Models/PostQuery.cs @@ -2,12 +2,12 @@ namespace FU.API.Models; public record PostQuery { - public List GameIds { get; set; } = new (); - public List TagIds { get; set; } = new (); + public List GameIds { get; set; } = new(); + public List TagIds { get; set; } = new(); public DateTime? After { get; set; } = null; public int MinimumRequiredPlayers { get; set; } = 0; - public List DescriptionContains { get; set; } = new (); + public List Keywords { get; set; } = new(); public SortOption? SortBy { get; set; } = null; public int Limit { get; set; } = 20; public int Offset { get; set; } = 0; -} \ No newline at end of file +} diff --git a/FU.API/FU.API/Program.cs b/FU.API/FU.API/Program.cs index 59ad05e4..6e15f94b 100644 --- a/FU.API/FU.API/Program.cs +++ b/FU.API/FU.API/Program.cs @@ -32,7 +32,7 @@ { options.RequireHttpsMetadata = false; options.SaveToken = true; - options.TokenValidationParameters = new () + options.TokenValidationParameters = new() { IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSecret)), ValidateLifetime = true, diff --git a/FU.API/FU.API/Services/AccountsService.cs b/FU.API/FU.API/Services/AccountsService.cs index 92afe85e..d452d872 100644 --- a/FU.API/FU.API/Services/AccountsService.cs +++ b/FU.API/FU.API/Services/AccountsService.cs @@ -68,7 +68,7 @@ public AccountsService(IConfiguration configuration, AppDbContext dbContext) var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration[ConfigKey.JwtSecret] ?? string.Empty)); var signingCredentials = new SigningCredentials(secretKey, SecurityAlgorithms.HmacSha256); - List claims = new () + List claims = new() { new (CustomClaimTypes.UserId, user.UserId.ToString()) }; diff --git a/FU.API/FU.API/Services/CommonService.cs b/FU.API/FU.API/Services/CommonService.cs index b882b815..ddd53526 100644 --- a/FU.API/FU.API/Services/CommonService.cs +++ b/FU.API/FU.API/Services/CommonService.cs @@ -1,51 +1,50 @@ -namespace FU.API.Services; - -using FU.API.Data; -using FU.API.Exceptions; -using FU.API.Helpers; -using FU.API.Interfaces; -using FU.API.Models; -using Microsoft.EntityFrameworkCore; -using System.Security.Claims; - -public class CommonService : ICommonService -{ - private readonly AppDbContext _dbContext; - - public CommonService(AppDbContext dbContext) - { - _dbContext = dbContext; - } - - public async Task GetCurrentUser(ClaimsPrincipal claims) - { - var stringId = claims.FindFirstValue(CustomClaimTypes.UserId); - - if (stringId is null || !int.TryParse(stringId, out int userId)) - { - return null; - } - - // Get the user from the database - return await _dbContext.Users.FindAsync(userId); - } - - public async Task GetUser(int userId) - { - return await _dbContext.Users.FindAsync(userId); - } - - public async Task HasJoinedPost(int userId, int postId) - { - var chat = await _dbContext.Posts - .Include(p => p.Chat) - .ThenInclude(c => c.Members) - .ThenInclude(cu => cu.User) - .Where(p => p.Id == postId) - .Select(p => p.Chat) - .FirstOrDefaultAsync(); - - var res = chat is not null && chat.Members.Any(m => m.UserId == userId); - return res; - } -} \ No newline at end of file +namespace FU.API.Services; + +using FU.API.Data; +using FU.API.Helpers; +using FU.API.Interfaces; +using FU.API.Models; +using Microsoft.EntityFrameworkCore; +using System.Security.Claims; + +public class CommonService : ICommonService +{ + private readonly AppDbContext _dbContext; + + public CommonService(AppDbContext dbContext) + { + _dbContext = dbContext; + } + + public async Task GetCurrentUser(ClaimsPrincipal claims) + { + var stringId = claims.FindFirstValue(CustomClaimTypes.UserId); + + if (stringId is null || !int.TryParse(stringId, out int userId)) + { + return null; + } + + // Get the user from the database + return await _dbContext.Users.FindAsync(userId); + } + + public async Task GetUser(int userId) + { + return await _dbContext.Users.FindAsync(userId); + } + + public async Task HasJoinedPost(int userId, int postId) + { + var chat = await _dbContext.Posts + .Include(p => p.Chat) + .ThenInclude(c => c.Members) + .ThenInclude(cu => cu.User) + .Where(p => p.Id == postId) + .Select(p => p.Chat) + .FirstOrDefaultAsync(); + + var res = chat is not null && chat.Members.Any(m => m.UserId == userId); + return res; + } +} diff --git a/FU.API/FU.API/Services/SearchService.cs b/FU.API/FU.API/Services/SearchService.cs index 0b057ed8..e9f9b3ae 100644 --- a/FU.API/FU.API/Services/SearchService.cs +++ b/FU.API/FU.API/Services/SearchService.cs @@ -5,6 +5,7 @@ namespace FU.API.Services; using FU.API.Interfaces; using FU.API.Models; using Microsoft.EntityFrameworkCore; +using LinqKit; public class SearchService : CommonService, ISearchService { @@ -30,7 +31,7 @@ public async Task> SearchPosts(PostQuery query) // Filter by tags // A post must have every tag in the filter - foreach (var tagId in query.TagIds) + foreach (int tagId in query.TagIds) { dbQuery = dbQuery.Where(p => p.Tags.Any(tr => tr.TagId == tagId)); } @@ -47,12 +48,8 @@ public async Task> SearchPosts(PostQuery query) // TODO } - // Filter by description keywords - foreach (string keyword in query.DescriptionContains) - { - // TODO don't require every keyword to match - dbQuery = dbQuery.Where(p => p.Description.Contains(keyword)); - } + // Filter by search keywords + dbQuery = dbQuery.Where(ContainsKeywords(query.Keywords)); // Sort results IOrderedQueryable orderedDbQuery = query.SortBy?.Direction == SortDirection.Ascending @@ -73,6 +70,22 @@ public async Task> SearchPosts(PostQuery query) .ToListAsync(); } + private static Expression> ContainsKeywords(List keywords) + { + if (keywords.Count == 0) + { + return PredicateBuilder.New(true); // nothing to do so return a true predicate + } + + var predicate = PredicateBuilder.New(false); // create a predicate that's false by default + foreach (string keyword in keywords) + { + predicate = predicate.Or(p => p.NormalizedDescription.Contains(keyword.ToUpper()) || p.NormalizedTitle.Contains(keyword.ToUpper())); + } + + return predicate; + } + private static Expression> SelectPostProperty(SortType? sortType) { return sortType switch @@ -83,4 +96,4 @@ private static Expression> SelectPostProperty(SortType? sortT _ => (post) => post.CreatedAt, }; } -} \ No newline at end of file +} diff --git a/FU.SPA/src/services/searchService.js b/FU.SPA/src/services/searchService.js index f3140a9e..0445992c 100644 --- a/FU.SPA/src/services/searchService.js +++ b/FU.SPA/src/services/searchService.js @@ -9,7 +9,7 @@ import AuthService from './authService'; */ const searchPosts = async (query) => { let queryString = ''; - queryString += 'keywords=' + encodeURIComponent(query.keywords); + queryString += 'keywords=' + encodeURIComponent(query.keywords.trim()); if (query.games.length > 0) { queryString += '&games=' + query.games.map((g) => String(g.id)).join(','); }