From 72e243cf84203d8ac1969aa3ac190a79bc6a7ce8 Mon Sep 17 00:00:00 2001 From: Jonathan Bourdon Date: Thu, 27 Jun 2024 12:37:59 -0400 Subject: [PATCH] Adds messages api --- Directory.Packages.props | 1 + src/Application/Common/Models/UserModel.cs | 2 + .../Identity/IdentityService.cs | 11 ++- src/Infrastructure/Utils/GenerateJwtToken.cs | 25 +++++-- src/Web/Controllers/GoogleController.cs | 12 ++- src/Web/Endpoints/Users.cs | 10 +-- src/Web/Messages/Data/Message.cs | 13 ++++ src/Web/Messages/Data/MessagingDbContext.cs | 19 +++++ src/Web/Messages/Handlers/GetMessages.cs | 30 ++++++++ .../Messages/Handlers/GetMessagesByUser.cs | 33 ++++++++ src/Web/Messages/Handlers/PostMessage.cs | 34 +++++++++ src/Web/Messages/Handlers/PostReplyMessage.cs | 37 +++++++++ .../20240627081653_Initial.Designer.cs | 59 +++++++++++++++ .../Migrations/20240627081653_Initial.cs | 38 ++++++++++ .../MessagingDbContextModelSnapshot.cs | 56 ++++++++++++++ src/Web/Messages/Shared.cs | 42 +++++++++++ src/Web/Program.cs | 75 ++++++++++++------- src/Web/Web.csproj | 31 ++++---- src/Web/Web.http | 14 +++- src/Web/appsettings.Development.json | 3 +- .../CustomWebApplicationFactory.cs | 1 + 21 files changed, 485 insertions(+), 61 deletions(-) create mode 100644 src/Web/Messages/Data/Message.cs create mode 100644 src/Web/Messages/Data/MessagingDbContext.cs create mode 100644 src/Web/Messages/Handlers/GetMessages.cs create mode 100644 src/Web/Messages/Handlers/GetMessagesByUser.cs create mode 100644 src/Web/Messages/Handlers/PostMessage.cs create mode 100644 src/Web/Messages/Handlers/PostReplyMessage.cs create mode 100644 src/Web/Messages/Migrations/20240627081653_Initial.Designer.cs create mode 100644 src/Web/Messages/Migrations/20240627081653_Initial.cs create mode 100644 src/Web/Messages/Migrations/MessagingDbContextModelSnapshot.cs create mode 100644 src/Web/Messages/Shared.cs diff --git a/Directory.Packages.props b/Directory.Packages.props index a2b4869..3c60acd 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -10,6 +10,7 @@ + diff --git a/src/Application/Common/Models/UserModel.cs b/src/Application/Common/Models/UserModel.cs index 5c4358b..71a2680 100644 --- a/src/Application/Common/Models/UserModel.cs +++ b/src/Application/Common/Models/UserModel.cs @@ -1,5 +1,6 @@ namespace Hutopy.Application.Common.Models; +// TODO: Review nullable affectation here public class UserModel { public string? Id { get; set; } @@ -7,4 +8,5 @@ public class UserModel public string? FirstName { get; set; } public string? LastName { get; set; } public string? Email { get; set; } + public string? PortraitUrl { get; set; } } diff --git a/src/Infrastructure/Identity/IdentityService.cs b/src/Infrastructure/Identity/IdentityService.cs index 9997316..7cdf080 100644 --- a/src/Infrastructure/Identity/IdentityService.cs +++ b/src/Infrastructure/Identity/IdentityService.cs @@ -1,3 +1,4 @@ +using System.Diagnostics; using Google.Apis.Oauth2.v2.Data; using System.Security.Claims; using Hutopy.Application.Common.Interfaces; @@ -220,14 +221,20 @@ public class IdentityService( } var user = await GetUserByUserNameAsync(userName); + + if (user is null) throw new InvalidOperationException(); var jwtSection = configuration.GetRequiredSection("Authentication:Jwt"); - + var token = JwtTokenHelper.GenerateJwtToken( issuer: jwtSection["Issuer"] ?? "", audience: jwtSection["Audience"] ?? "", key: jwtSection["Key"] ?? "", - userId: user?.Id ?? ""); + userId: user.Id, + email: user.Email, + firstname: user.FirstName, + lastname: user.LastName, + portraitUrl: user.PortraitUrl); return token; } diff --git a/src/Infrastructure/Utils/GenerateJwtToken.cs b/src/Infrastructure/Utils/GenerateJwtToken.cs index 00423f9..19e6cbd 100644 --- a/src/Infrastructure/Utils/GenerateJwtToken.cs +++ b/src/Infrastructure/Utils/GenerateJwtToken.cs @@ -7,20 +7,31 @@ namespace Hutopy.Infrastructure.Utils; public static class JwtTokenHelper { - public static string GenerateJwtToken(string issuer, string audience, string key, string userId) + public static string GenerateJwtToken(string issuer, string audience, string key, string? userId, string? email, + string? firstname, string? lastname, string? portraitUrl) { var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key)); var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256); + var claims = new List(new[] + { + new Claim(JwtRegisteredClaimNames.Sub, userId), + new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), + new Claim(ClaimTypes.NameIdentifier, userId), + new Claim(ClaimTypes.Email, email), + new Claim(ClaimTypes.GivenName, firstname), + new Claim(ClaimTypes.Surname, lastname), + }); + + if (portraitUrl is not null) + { + claims.Add(new Claim("portrait-url", portraitUrl)); + } + var token = new JwtSecurityToken( issuer: issuer, audience: audience, - claims: new[] - { - new Claim(JwtRegisteredClaimNames.Sub, userId), - new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), - new Claim(ClaimTypes.NameIdentifier, userId) - }, + claims: claims, expires: DateTime.Now.AddMinutes(30), signingCredentials: credentials); diff --git a/src/Web/Controllers/GoogleController.cs b/src/Web/Controllers/GoogleController.cs index 40e8adc..dfaa91e 100644 --- a/src/Web/Controllers/GoogleController.cs +++ b/src/Web/Controllers/GoogleController.cs @@ -64,10 +64,14 @@ public class GoogleController(IIdentityService identityService, IHttpClientFacto var jwtSection = configuration.GetRequiredSection("Authentication:Jwt"); var token = JwtTokenHelper.GenerateJwtToken( - issuer: jwtSection["Issuer"] ?? throw new ArgumentNullException("The Jwt issuer is missing."), - audience: jwtSection["Audience"] ?? throw new ArgumentNullException("The Jwt audience is missing."), - key: jwtSection["Key"] ?? throw new ArgumentNullException("The Jwt key is missing."), - userId: user.Id); + jwtSection["Issuer"] ?? throw new ArgumentNullException("The Jwt issuer is missing."), + jwtSection["Audience"] ?? throw new ArgumentNullException("The Jwt audience is missing."), + jwtSection["Key"] ?? throw new ArgumentNullException("The Jwt key is missing."), + user.Id, + user.Email, + user.FirstName, + user.LastName, + user.PortraitUrl); return Ok(new { accessToken = token, email }); } diff --git a/src/Web/Endpoints/Users.cs b/src/Web/Endpoints/Users.cs index c344509..bcfa964 100644 --- a/src/Web/Endpoints/Users.cs +++ b/src/Web/Endpoints/Users.cs @@ -23,18 +23,16 @@ public class Users : EndpointGroupBase { return await sender.Send(query); } - + private static async Task Login(ISender sender, LoginCommand command) { return await sender.Send(command); } - + private static async Task UploadProfilePicture(ISender sender, Stream stream) { - var command = new UploadProfilePictureCommand - { - ProfilePicture = stream - }; + var command = new UploadProfilePictureCommand { ProfilePicture = stream }; + return await sender.Send(command); } } diff --git a/src/Web/Messages/Data/Message.cs b/src/Web/Messages/Data/Message.cs new file mode 100644 index 0000000..df0fa50 --- /dev/null +++ b/src/Web/Messages/Data/Message.cs @@ -0,0 +1,13 @@ +namespace Hutopy.Web.Messages.Data; + +public class Message +{ + public Guid Id { get; init; } + public Guid ContentId { get; init; } // works for any - VideoId, ChatId, RoomId, xxxId, ForumId + public Guid CreatedBy { get; init; } + public DateTime CreatedAt { get; } + + public Guid ParentId { get; init; } + + public string Value { get; init; } = null!; +} diff --git a/src/Web/Messages/Data/MessagingDbContext.cs b/src/Web/Messages/Data/MessagingDbContext.cs new file mode 100644 index 0000000..28bb977 --- /dev/null +++ b/src/Web/Messages/Data/MessagingDbContext.cs @@ -0,0 +1,19 @@ +using Microsoft.EntityFrameworkCore; + +namespace Hutopy.Web.Messages.Data; + +public class MessagingDbContext( + DbContextOptions options) + : DbContext(options) +{ + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder + .Entity() + .Property(c => c.CreatedAt) + .ValueGeneratedOnAdd() + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + } + + public DbSet Messages { get; set; } +} diff --git a/src/Web/Messages/Handlers/GetMessages.cs b/src/Web/Messages/Handlers/GetMessages.cs new file mode 100644 index 0000000..d7afb3f --- /dev/null +++ b/src/Web/Messages/Handlers/GetMessages.cs @@ -0,0 +1,30 @@ +using FastEndpoints; +using Hutopy.Web.Messages.Data; +using Microsoft.EntityFrameworkCore; + +namespace Hutopy.Web.Messages.Handlers; + +public class GetMessages( + MessagingDbContext context) + : EndpointWithoutRequest> +{ + public override void Configure() + { + Tags("Messages"); + Get("/api/messages/{ContentId:guid}"); + AllowAnonymous(); + } + + public override async Task HandleAsync( + CancellationToken ct) + { + var contentId = Route("ContentId"); + + var comments = await context + .Messages + .Where(c => c.ContentId == contentId) + .ToListAsync(cancellationToken: ct); + + await SendAsync(comments, cancellation: ct); + } +} diff --git a/src/Web/Messages/Handlers/GetMessagesByUser.cs b/src/Web/Messages/Handlers/GetMessagesByUser.cs new file mode 100644 index 0000000..d70cd11 --- /dev/null +++ b/src/Web/Messages/Handlers/GetMessagesByUser.cs @@ -0,0 +1,33 @@ +using FastEndpoints; +using Hutopy.Web.Messages.Data; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; + +namespace Hutopy.Web.Messages.Handlers; + +public record GetMessagesByUserRequest( + [FromRoute] Guid UserId); + +public class GetMessagesByUser( + MessagingDbContext context) + : EndpointWithoutRequest> +{ + public override void Configure() + { + Tags("Messages"); + Get("/api/messages/by-user/{UserId:guid}"); + } + + public override async Task HandleAsync( + CancellationToken ct) + { + var userId = Route("UserId"); + + var posts = await context + .Messages + .Where(c => c.CreatedBy == userId) + .ToListAsync(cancellationToken: ct); + + await SendAsync(posts, cancellation: ct); + } +} diff --git a/src/Web/Messages/Handlers/PostMessage.cs b/src/Web/Messages/Handlers/PostMessage.cs new file mode 100644 index 0000000..7460728 --- /dev/null +++ b/src/Web/Messages/Handlers/PostMessage.cs @@ -0,0 +1,34 @@ +using FastEndpoints; +using Hutopy.Web.Messages.Data; + +namespace Hutopy.Web.Messages.Handlers; + +public record PostMessageRequest( + Guid ContentId, + string Message); + +public class PostMessage( + MessagingDbContext context) + : Endpoint +{ + public override void Configure() + { + // TODO: Find how to specify the name we see in Swagger + Tags("Messages"); + Post("/api/messages"); + } + + public override async Task HandleAsync( + PostMessageRequest req, + CancellationToken ct) + { + await context.Messages.AddAsync( + new Message { + ContentId = req.ContentId, + CreatedBy = User.GetUserId(), + Value = req.Message }, + ct); + + await context.SaveChangesAsync(ct); + } +} diff --git a/src/Web/Messages/Handlers/PostReplyMessage.cs b/src/Web/Messages/Handlers/PostReplyMessage.cs new file mode 100644 index 0000000..2385765 --- /dev/null +++ b/src/Web/Messages/Handlers/PostReplyMessage.cs @@ -0,0 +1,37 @@ +using FastEndpoints; +using Hutopy.Web.Messages.Data; + +namespace Hutopy.Web.Messages.Handlers; + +public record PostReplyMessageRequest( + Guid ContentId, + Guid ParentId, + string Message); + +public sealed class PostReplyMessage( + MessagingDbContext context) + : Endpoint +{ + public override void Configure() + { + Tags("Messages"); + Post("/api/messages/reply"); + } + + public override async Task HandleAsync( + PostReplyMessageRequest req, + CancellationToken ct) + { + await context.Messages.AddAsync( + new Message + { + ContentId = req.ContentId, + ParentId = req.ParentId, + CreatedBy = User.GetUserId(), + Value = req.Message + }, + ct); + + await context.SaveChangesAsync(ct); + } +} diff --git a/src/Web/Messages/Migrations/20240627081653_Initial.Designer.cs b/src/Web/Messages/Migrations/20240627081653_Initial.Designer.cs new file mode 100644 index 0000000..72d8e1c --- /dev/null +++ b/src/Web/Messages/Migrations/20240627081653_Initial.Designer.cs @@ -0,0 +1,59 @@ +// +using System; +using Hutopy.Web.Messages.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Hutopy.Web.Messages.Migrations +{ + [DbContext(typeof(MessagingDbContext))] + [Migration("20240627081653_Initial")] + partial class Initial + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Hutopy.Web.Messages.Data.Message", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ContentId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("CreatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("ParentId") + .HasColumnType("uniqueidentifier"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Messages"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Web/Messages/Migrations/20240627081653_Initial.cs b/src/Web/Messages/Migrations/20240627081653_Initial.cs new file mode 100644 index 0000000..bd5664e --- /dev/null +++ b/src/Web/Messages/Migrations/20240627081653_Initial.cs @@ -0,0 +1,38 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Hutopy.Web.Messages.Migrations +{ + /// + public partial class Initial : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Messages", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + ContentId = table.Column(type: "uniqueidentifier", nullable: false), + CreatedBy = table.Column(type: "uniqueidentifier", nullable: false), + CreatedAt = table.Column(type: "datetime2", nullable: false, defaultValueSql: "CURRENT_TIMESTAMP"), + ParentId = table.Column(type: "uniqueidentifier", nullable: false), + Value = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Messages", x => x.Id); + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Messages"); + } + } +} diff --git a/src/Web/Messages/Migrations/MessagingDbContextModelSnapshot.cs b/src/Web/Messages/Migrations/MessagingDbContextModelSnapshot.cs new file mode 100644 index 0000000..be9a4b9 --- /dev/null +++ b/src/Web/Messages/Migrations/MessagingDbContextModelSnapshot.cs @@ -0,0 +1,56 @@ +// +using System; +using Hutopy.Web.Messages.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Hutopy.Web.Messages.Migrations +{ + [DbContext(typeof(MessagingDbContext))] + partial class MessagingDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Hutopy.Web.Messages.Data.Message", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ContentId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("CreatedBy") + .HasColumnType("uniqueidentifier"); + + b.Property("ParentId") + .HasColumnType("uniqueidentifier"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Messages"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Web/Messages/Shared.cs b/src/Web/Messages/Shared.cs new file mode 100644 index 0000000..eb48399 --- /dev/null +++ b/src/Web/Messages/Shared.cs @@ -0,0 +1,42 @@ +using System.Security.Claims; + +namespace Hutopy.Web.Messages; + +public class Shared(string claimName) : Exception; + +public static class ClaimsPrincipalExtensions +{ + public static Guid GetUserId(this ClaimsPrincipal claims) + { + return (Guid)claims.GetFirstValue(ClaimTypes.NameIdentifier); + } + + public static string GetFirstName(this ClaimsPrincipal claims) + { + return (string)claims.GetFirstValue(ClaimTypes.GivenName); + } + + public static string GetLastName(this ClaimsPrincipal claims) + { + return (string)claims.GetFirstValue(ClaimTypes.Surname); + } + + public static string GetEmail(this ClaimsPrincipal claims) + { + return (string)claims.GetFirstValue(ClaimTypes.Email); + } + + public static object GetFirstValue(this ClaimsPrincipal claims, string key) + { + var claim = claims.FindFirst(key); + + if (claim is null) throw new Shared(key); + + if (typeof(TValue) == typeof(Guid)) + { + return Guid.Parse(claim.Value); + } + + return Convert.ChangeType(claim.Value, typeof(TValue)); + } +} diff --git a/src/Web/Program.cs b/src/Web/Program.cs index ea5b072..78700bc 100644 --- a/src/Web/Program.cs +++ b/src/Web/Program.cs @@ -1,10 +1,14 @@ +using Azure.Identity; +using FastEndpoints; using Hutopy.Application; using Hutopy.Infrastructure; using Hutopy.Infrastructure.Data; using Hutopy.Web; -using Azure.Identity; +using Hutopy.Web.Messages.Data; using Microsoft.AspNetCore.HttpOverrides; +using Microsoft.EntityFrameworkCore; using NSwag; +using NSwag.Generation.AspNetCore.Processors; using NSwag.Generation.Processors.Security; var builder = WebApplication.CreateBuilder(args); @@ -16,31 +20,31 @@ if (!builder.Environment.IsDevelopment()) } builder.Services.AddCors(options => +{ + options.AddPolicy("AllowAll", builder => { - options.AddPolicy("AllowAll", builder => - { - builder.AllowAnyOrigin() - .AllowAnyMethod() - .AllowAnyHeader(); - }); - - options.AddPolicy("AllowHutopyUi", builder => - { - builder.WithOrigins("https://zealous-bay-08204590f.5.azurestaticapps.net") - .AllowAnyMethod() - .AllowAnyHeader() - .AllowCredentials(); - }); - - options.AddPolicy("AllowHutopyUiPreview", builder => - { - builder.WithOrigins("https://zealous-bay-08204590f-preview.eastus2.5.azurestaticapps.net") - .AllowAnyMethod() - .AllowAnyHeader() - .AllowCredentials(); - }); + builder.AllowAnyOrigin() + .AllowAnyMethod() + .AllowAnyHeader(); }); + options.AddPolicy("AllowHutopyUi", builder => + { + builder.WithOrigins("https://zealous-bay-08204590f.5.azurestaticapps.net") + .AllowAnyMethod() + .AllowAnyHeader() + .AllowCredentials(); + }); + + options.AddPolicy("AllowHutopyUiPreview", builder => + { + builder.WithOrigins("https://zealous-bay-08204590f-preview.eastus2.5.azurestaticapps.net") + .AllowAnyMethod() + .AllowAnyHeader() + .AllowCredentials(); + }); +}); + // Add services to the container. builder.Services.AddKeyVaultIfConfigured(builder.Configuration); @@ -48,6 +52,8 @@ builder.Services.AddApplicationServices(); builder.Services.AddInfrastructureServices(builder.Configuration); builder.Services.AddWebServices(); builder.Services.AddAuthorizationAndAuthentication(builder.Configuration); + +// TODO: This old tech should be remove - need to move Facebook / Google controllers to FastEndpoints builder.Services.AddControllers(); builder.Services.AddOpenApiDocument((configure, sp) => @@ -63,11 +69,19 @@ builder.Services.AddOpenApiDocument((configure, sp) => Type = OpenApiSecuritySchemeType.ApiKey, Name = "Authorization", In = OpenApiSecurityApiKeyLocation.Header, - Description = "Type into the textbox: Bearer {your JWT token}." + Description = "Type into the textbox: Bearer {your JWT token}.", }); - + + configure.OperationProcessors.Add(new AspNetCoreOperationTagsProcessor()); configure.OperationProcessors.Add(new AspNetCoreOperationSecurityScopeProcessor("JWT")); - }); +}); + +builder.Services.AddFastEndpoints(); + +builder.Services.AddDbContext((_, options) => +{ + options.UseSqlServer(builder.Configuration.GetConnectionString("CommentStore")); +}); var app = builder.Build(); @@ -110,6 +124,13 @@ app.MapControllerRoute( // app.UseExceptionHandler(); app.MapEndpoints(); +app.UseFastEndpoints(); + app.Run(); -public abstract partial class Program { } +namespace Hutopy.Web +{ + public abstract partial class Program + { + } +} diff --git a/src/Web/Web.csproj b/src/Web/Web.csproj index 80a1ea9..053126a 100644 --- a/src/Web/Web.csproj +++ b/src/Web/Web.csproj @@ -7,26 +7,31 @@ - - + + - - - - - - - - - - + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + + + + + diff --git a/src/Web/Web.http b/src/Web/Web.http index c0ac5aa..054f4e4 100644 --- a/src/Web/Web.http +++ b/src/Web/Web.http @@ -23,7 +23,7 @@ Content-Type: application/json "password": "{{Password}}" } -> {% client.global.set("auth_token", response.body); %} +> {% client.global.set("auth_token", response.body.accessToken); %} ### @@ -46,4 +46,16 @@ Authorization: Bearer {{auth_token}} # GET GetMyUser GET {{base_url}}/api/GetMyUser +Authorization: Bearer {{auth_token}} + +### + +# GET /api/posts + +GET {{base_url}}/api/messages/00000001-0000-0000-0000-000000000001 + +### + +# GET /api/posts/by-user +GET {{base_url}}/api/messages/by-user/325C69E8-DBC4-4CEE-B56E-C3C90AEE7963 Authorization: Bearer {{auth_token}} \ No newline at end of file diff --git a/src/Web/appsettings.Development.json b/src/Web/appsettings.Development.json index 43ba880..9e2b285 100644 --- a/src/Web/appsettings.Development.json +++ b/src/Web/appsettings.Development.json @@ -8,7 +8,8 @@ } }, "ConnectionStrings": { - "DefaultConnection": "Server=localhost,1433;Initial Catalog=Hutopy;User Id=sa;Password=P@ssword123!;MultipleActiveResultSets=true;TrustServerCertificate=True;MultiSubnetFailover=True" + "DefaultConnection": "Server=localhost,1433;Initial Catalog=Hutopy;User Id=sa;Password=P@ssword123!;MultipleActiveResultSets=true;TrustServerCertificate=True;MultiSubnetFailover=True", + "CommentStore": "Server=localhost,1433;Initial Catalog=Hutopy;User Id=sa;Password=P@ssword123!;MultipleActiveResultSets=true;TrustServerCertificate=True;MultiSubnetFailover=True" }, "Authentication": { "Jwt": { diff --git a/tests/Application.FunctionalTests/CustomWebApplicationFactory.cs b/tests/Application.FunctionalTests/CustomWebApplicationFactory.cs index d99727f..c1d8a80 100644 --- a/tests/Application.FunctionalTests/CustomWebApplicationFactory.cs +++ b/tests/Application.FunctionalTests/CustomWebApplicationFactory.cs @@ -1,6 +1,7 @@ using System.Data.Common; using Hutopy.Application.Common.Interfaces; using Hutopy.Infrastructure.Data; +using Hutopy.Web; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.AspNetCore.TestHost;