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;