diff --git a/.github/workflows/backend-smoke-test.yml b/.github/workflows/backend-smoke-test.yml
index d1f5cdbf..f2a15c8a 100644
--- a/.github/workflows/backend-smoke-test.yml
+++ b/.github/workflows/backend-smoke-test.yml
@@ -17,7 +17,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
- dotnet-version: 6.0.x
+ dotnet-version: 10.0.x
- name: Restore dependencies
run: dotnet restore
@@ -28,10 +28,13 @@ jobs:
{
"JwtSettings": {
"Issuer": "AnalySim",
- "Secret": "very_hard_secret",
+ "Secret": "github-actions-smoke-test-secret-with-at-least-32-chars",
"ExpireTime": 60,
"Audience": "https://www.analysim.tech/"
},
+ "ConnectionStrings": {
+ "DBConnectionString": "Host=localhost;Port=5432;Database=analysim;Username=postgres;Password=postgres"
+ },
"Logging": {
"LogLevel": {
"Default": "Information",
@@ -48,20 +51,20 @@ jobs:
- name: Start backend
run: |
cd src/Analysim.Web
- dotnet run --no-launch-profile > ../../backend.log 2>&1 &
+ ASPNETCORE_URLS=http://localhost:5000 ASPNETCORE_ENVIRONMENT=Development dotnet run --no-launch-profile --no-build --configuration Release > ../../backend.log 2>&1 &
echo $! > ../../backend.pid
- name: Wait for backend to be ready
run: |
for i in {1..15}; do
- RESPONSE=$(curl -k -s https://localhost:5001/api/health || true)
+ RESPONSE=$(curl -s http://localhost:5000/api/health || true)
if [[ "$RESPONSE" == *Healthy* ]]; then
echo "Backend is healthy"
exit 0
fi
- echo "Attempt $i/30: backend not ready yet"
+ echo "Attempt $i/15: backend not ready yet"
sleep 6
done
diff --git a/Dockerfile b/Dockerfile
index d37d3b3b..6946f1eb 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,6 +1,6 @@
# Builds and runs ASPNET project Analysim
# Requires running database
-FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
+FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /source
# install Node.js and Python
@@ -9,7 +9,7 @@ RUN curl -sL https://deb.nodesource.com/setup_20.x | bash - && apt-get install -
RUN npm install -g npm
# Install .Net EF Tools
-RUN dotnet tool install --global dotnet-ef --version 6.0
+RUN dotnet tool install --global dotnet-ef --version 10.0.9
ENV PATH="$PATH:/root/.dotnet/tools"
# then copy sources so previous step is cached
@@ -25,7 +25,7 @@ WORKDIR /source/Analysim.Web
CMD dotnet ef database update
# run project in new container
-FROM mcr.microsoft.com/dotnet/aspnet:6.0 as run
+FROM mcr.microsoft.com/dotnet/aspnet:10.0 as run
WORKDIR /app
COPY --from=build /app .
diff --git a/Dockerfile.run b/Dockerfile.run
index 88ec924a..f092ab68 100644
--- a/Dockerfile.run
+++ b/Dockerfile.run
@@ -1,7 +1,7 @@
# Run published project
-FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
+FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
WORKDIR /app
-COPY src/Analysim.Web/bin/Release/net6.0/publish/ .
+COPY src/Analysim.Web/bin/Release/net10.0/publish/ .
#CMD ASPNETCORE_URLS=http://*:$PORT dotnet Analysim.Web.dll
CMD dotnet Analysim.Web.dll
diff --git a/README.md b/README.md
index c81bf67a..e7f47966 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,7 @@ git clone https://github.com/soft-eng-practicum/AnalySim.git
### Required software for development
-- [Visual Studio](https://visualstudio.microsoft.com/downloads/) or [ASP.Net 6.0 command-line interface (CLI)](https://dotnet.microsoft.com/en-us/download) (Required)
+- [Visual Studio](https://visualstudio.microsoft.com/downloads/) or [ASP.NET 10.0 command-line interface (CLI)](https://dotnet.microsoft.com/en-us/download) (Required)
- [Visual Studio Code](https://code.visualstudio.com/download) or other editor
- [Postman](https://www.postman.com/downloads/) for testing API calls
- [Python](https://www.python.org/downloads/) for building project
@@ -128,7 +128,7 @@ line by first navigating into the `src\Analysim.Web` folder:
```sh
dotnet run --environment Development
```
-(This will also automatically run Angular and a [Swagger](https://learn.microsoft.com/en-us/aspnet/core/tutorials/getting-started-with-swashbuckle?view=aspnetcore-8.0&tabs=visual-studio) UI on port 5001)
+(This will also automatically run Angular and a [Swagger](https://learn.microsoft.com/en-us/aspnet/core/tutorials/getting-started-with-swashbuckle?view=aspnetcore-10.0&tabs=visual-studio) UI on port 5001)
## Deploying
diff --git a/deploy/build.Dockerfile b/deploy/build.Dockerfile
index 955c25d4..f9536661 100644
--- a/deploy/build.Dockerfile
+++ b/deploy/build.Dockerfile
@@ -1,6 +1,6 @@
# Learn about building .NET container images:
# https://github.com/dotnet/dotnet-docker/blob/main/samples/README.md
-FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
+FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /source
# copy csproj and restore as distinct layers
@@ -30,7 +30,7 @@ RUN dotnet publish -o /app --configuration Release
#RUN dotnet ef database update
# final stage/image
-FROM mcr.microsoft.com/dotnet/aspnet:6.0
+FROM mcr.microsoft.com/dotnet/aspnet:10.0
WORKDIR /app
COPY --from=build /app .
ENTRYPOINT ["dotnet", "Analysim.Web.dll"]
diff --git a/src/Analysim.Core/Analysim.Core.csproj b/src/Analysim.Core/Analysim.Core.csproj
index 71aed483..febbcf5f 100644
--- a/src/Analysim.Core/Analysim.Core.csproj
+++ b/src/Analysim.Core/Analysim.Core.csproj
@@ -1,25 +1,23 @@
- net6.0
+ net10.0
Analysim.Core
Analysim.Core
-
-
-
-
-
-
-
+
+
+
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
+
+
diff --git a/src/Analysim.Core/Entities/Project.cs b/src/Analysim.Core/Entities/Project.cs
index 6db08a00..06013a5d 100644
--- a/src/Analysim.Core/Entities/Project.cs
+++ b/src/Analysim.Core/Entities/Project.cs
@@ -5,6 +5,7 @@
namespace Core.Entities
{
+ [Microsoft.EntityFrameworkCore.Index(nameof(Route), IsUnique = true)]
public class Project
{
@@ -30,7 +31,6 @@ public class Project
[Required(ErrorMessage = "Project Route is a required field.")]
- [Index(IsUnique = true)]
public string Route { get; set; }
public List ProjectTags { get; set; }
@@ -50,4 +50,3 @@ public class Project
}
}
-
diff --git a/src/Analysim.Core/Entities/Tag.cs b/src/Analysim.Core/Entities/Tag.cs
index 1cfc7bfe..3d4f7066 100644
--- a/src/Analysim.Core/Entities/Tag.cs
+++ b/src/Analysim.Core/Entities/Tag.cs
@@ -5,13 +5,13 @@
namespace Core.Entities
{
+ [Microsoft.EntityFrameworkCore.Index(nameof(Name), IsUnique = true)]
public class Tag
{
[KeyAttribute]
public int TagID { get; set; }
[Required(ErrorMessage = "Tag Name is a required field.")]
- [Index(IsUnique = true)]
public string Name { get; set; }
public ICollection ProjectTags { get; } = new List();
diff --git a/src/Analysim.Infrastructure/Analysim.Infrastructure.csproj b/src/Analysim.Infrastructure/Analysim.Infrastructure.csproj
index 8341e1ac..a1738911 100644
--- a/src/Analysim.Infrastructure/Analysim.Infrastructure.csproj
+++ b/src/Analysim.Infrastructure/Analysim.Infrastructure.csproj
@@ -1,19 +1,19 @@
- net6.0
+ net10.0
Analysim.Infrastructure
Analysim.Infrastructure
-
-
-
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
diff --git a/src/Analysim.Infrastructure/Data/ApplicationDbContext.cs b/src/Analysim.Infrastructure/Data/ApplicationDbContext.cs
index 0e8812a1..611a7a0f 100644
--- a/src/Analysim.Infrastructure/Data/ApplicationDbContext.cs
+++ b/src/Analysim.Infrastructure/Data/ApplicationDbContext.cs
@@ -96,9 +96,9 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity>().HasData(
- new IdentityRole { Id = 1, Name = "Admin", NormalizedName = "ADMIN" },
- new IdentityRole { Id = 2, Name = "Customer", NormalizedName = "CUSTOMER" },
- new IdentityRole { Id = 3, Name = "Moderator", NormalizedName = "MODERATOR" }
+ new IdentityRole { Id = 1, Name = "Admin", NormalizedName = "ADMIN", ConcurrencyStamp = "d7c6278e-3f78-4db6-8832-aa41ea9fd62c" },
+ new IdentityRole { Id = 2, Name = "Customer", NormalizedName = "CUSTOMER", ConcurrencyStamp = "7383e31e-a884-4cd6-82f7-a6287b4e30a5" },
+ new IdentityRole { Id = 3, Name = "Moderator", NormalizedName = "MODERATOR", ConcurrencyStamp = "398ef1f2-6b82-45f2-9601-ed2129f197e9" }
);
// Many To One Relationship ( ObservableNotebookDataset -> Notebook)
diff --git a/src/Analysim.Infrastructure/Infrastructure/Migrations/ApplicationDbContextModelSnapshot.cs b/src/Analysim.Infrastructure/Infrastructure/Migrations/ApplicationDbContextModelSnapshot.cs
index 7989d6d6..5036053f 100644
--- a/src/Analysim.Infrastructure/Infrastructure/Migrations/ApplicationDbContextModelSnapshot.cs
+++ b/src/Analysim.Infrastructure/Infrastructure/Migrations/ApplicationDbContextModelSnapshot.cs
@@ -17,7 +17,7 @@ protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
- .HasAnnotation("ProductVersion", "6.0.6")
+ .HasAnnotation("ProductVersion", "10.0.9")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
@@ -239,6 +239,9 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.HasKey("ProjectID");
+ b.HasIndex("Route")
+ .IsUnique();
+
b.ToTable("Projects");
});
@@ -478,8 +481,7 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.Property("Volume")
.HasColumnType("text");
- b.Property("Year")
- .IsRequired()
+ b.Property("Year")
.HasColumnType("integer");
b.HasKey("PublicationID");
@@ -503,6 +505,9 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.HasKey("TagID");
+ b.HasIndex("Name")
+ .IsUnique();
+
b.ToTable("Tag");
});
diff --git a/src/Analysim.Infrastructure/Migrations/20260702170313_AddUniqueIndexesForProjectRouteAndTagName.Designer.cs b/src/Analysim.Infrastructure/Migrations/20260702170313_AddUniqueIndexesForProjectRouteAndTagName.Designer.cs
new file mode 100644
index 00000000..6141d77b
--- /dev/null
+++ b/src/Analysim.Infrastructure/Migrations/20260702170313_AddUniqueIndexesForProjectRouteAndTagName.Designer.cs
@@ -0,0 +1,1124 @@
+//
+using System;
+using Infrastructure.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 Analysim.Infrastructure.Migrations
+{
+ [DbContext(typeof(ApplicationDbContext))]
+ [Migration("20260702170313_AddUniqueIndexesForProjectRouteAndTagName")]
+ partial class AddUniqueIndexesForProjectRouteAndTagName
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "10.0.9")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("Analysim.Core.Entities.BlobFileContent", b =>
+ {
+ b.Property("BlobFileID")
+ .HasColumnType("integer");
+
+ b.Property("Content")
+ .IsRequired()
+ .HasColumnType("bytea");
+
+ b.Property("DateCreated")
+ .HasColumnType("timestamp with time zone");
+
+ b.HasKey("BlobFileID");
+
+ b.ToTable("BlobFileContent");
+ });
+
+ modelBuilder.Entity("Analysim.Core.Entities.NotebookContent", b =>
+ {
+ b.Property("NotebookID")
+ .HasColumnType("integer")
+ .HasColumnOrder(1);
+
+ b.Property("Version")
+ .HasColumnType("integer")
+ .HasColumnOrder(2);
+
+ b.Property("Author")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Content")
+ .IsRequired()
+ .HasColumnType("bytea");
+
+ b.Property("DateCreated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Size")
+ .HasColumnType("integer");
+
+ b.HasKey("NotebookID", "Version");
+
+ b.ToTable("NotebookContent");
+ });
+
+ modelBuilder.Entity("Core.Entities.BlobFile", b =>
+ {
+ b.Property("BlobFileID")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("BlobFileID"));
+
+ b.Property("Container")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("DateCreated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Directory")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Extension")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("LastModified")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ProjectID")
+ .HasColumnType("integer");
+
+ b.Property("Size")
+ .HasColumnType("integer");
+
+ b.Property("Uri")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UserID")
+ .HasColumnType("integer");
+
+ b.HasKey("BlobFileID");
+
+ b.HasIndex("ProjectID");
+
+ b.HasIndex("UserID");
+
+ b.ToTable("BlobFiles");
+ });
+
+ modelBuilder.Entity("Core.Entities.Notebook", b =>
+ {
+ b.Property("NotebookID")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("NotebookID"));
+
+ b.Property("Container")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("DateCreated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Directory")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Extension")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("LastModified")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ProjectID")
+ .HasColumnType("integer");
+
+ b.Property("Route")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Size")
+ .HasColumnType("integer");
+
+ b.Property("Uri")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("type")
+ .HasColumnType("text");
+
+ b.HasKey("NotebookID");
+
+ b.HasIndex("Directory");
+
+ b.HasIndex("ProjectID");
+
+ b.ToTable("Notebook");
+ });
+
+ modelBuilder.Entity("Core.Entities.ObservableNotebookDataset", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ID"));
+
+ b.Property("BlobFileID")
+ .HasColumnType("integer");
+
+ b.Property("NotebookID")
+ .HasColumnType("integer");
+
+ b.Property("datasetName")
+ .HasColumnType("text");
+
+ b.Property("datasetURL")
+ .HasColumnType("text");
+
+ b.HasKey("ID");
+
+ b.HasIndex("NotebookID");
+
+ b.ToTable("ObservableNotebookDataset");
+ });
+
+ modelBuilder.Entity("Core.Entities.Project", b =>
+ {
+ b.Property("ProjectID")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ProjectID"));
+
+ b.Property("DateCreated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Description")
+ .HasMaxLength(500)
+ .HasColumnType("character varying(500)");
+
+ b.Property("ForkedFromProjectID")
+ .HasColumnType("integer");
+
+ b.Property("LastUpdated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("character varying(20)");
+
+ b.Property("Route")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Visibility")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("ProjectID");
+
+ b.HasIndex("Route")
+ .IsUnique();
+
+ b.ToTable("Projects");
+ });
+
+ modelBuilder.Entity("Core.Entities.ProjectComment", b =>
+ {
+ b.Property("CommentID")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("CommentID"));
+
+ b.Property("Content")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("IsDeleted")
+ .HasColumnType("boolean");
+
+ b.Property("IsPendingReview")
+ .HasColumnType("boolean");
+
+ b.Property("ParentCommentID")
+ .HasColumnType("integer");
+
+ b.Property("ProjectID")
+ .HasColumnType("integer");
+
+ b.Property("ProjectLogID")
+ .HasColumnType("integer");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("UserID")
+ .HasColumnType("integer");
+
+ b.HasKey("CommentID");
+
+ b.HasIndex("ParentCommentID");
+
+ b.HasIndex("ProjectID");
+
+ b.HasIndex("ProjectLogID");
+
+ b.HasIndex("UserID");
+
+ b.ToTable("ProjectComments");
+ });
+
+ modelBuilder.Entity("Core.Entities.ProjectCommentFlag", b =>
+ {
+ b.Property("FlagID")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("FlagID"));
+
+ b.Property("CommentContentSnapshot")
+ .HasColumnType("text");
+
+ b.Property("CommentID")
+ .HasColumnType("integer");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("UserID")
+ .HasColumnType("integer");
+
+ b.HasKey("FlagID");
+
+ b.HasIndex("UserID");
+
+ b.HasIndex("CommentID", "UserID")
+ .IsUnique();
+
+ b.ToTable("ProjectCommentFlags");
+ });
+
+ modelBuilder.Entity("Core.Entities.ProjectCommentLike", b =>
+ {
+ b.Property("CommentID")
+ .HasColumnType("integer");
+
+ b.Property("UserID")
+ .HasColumnType("integer");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.HasKey("CommentID", "UserID");
+
+ b.HasIndex("UserID");
+
+ b.ToTable("ProjectCommentLikes");
+ });
+
+ modelBuilder.Entity("Core.Entities.ProjectLog", b =>
+ {
+ b.Property("LogID")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("LogID"));
+
+ b.Property("BlobFileID")
+ .HasColumnType("integer");
+
+ b.Property("Content")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ExpiresAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("IsDeleted")
+ .HasColumnType("boolean");
+
+ b.Property("ProjectID")
+ .HasColumnType("integer");
+
+ b.Property("ReferencedNotebookID")
+ .HasColumnType("integer");
+
+ b.Property("ReferencedNotebookVersion")
+ .HasColumnType("integer");
+
+ b.Property("Title")
+ .HasColumnType("text");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("UserID")
+ .HasColumnType("integer");
+
+ b.HasKey("LogID");
+
+ b.HasIndex("BlobFileID");
+
+ b.HasIndex("ProjectID");
+
+ b.HasIndex("ReferencedNotebookID");
+
+ b.HasIndex("UserID");
+
+ b.ToTable("ProjectLogs");
+ });
+
+ modelBuilder.Entity("Core.Entities.ProjectTag", b =>
+ {
+ b.Property("ProjectID")
+ .HasColumnType("integer")
+ .HasColumnOrder(2);
+
+ b.Property("TagID")
+ .HasColumnType("integer")
+ .HasColumnOrder(1);
+
+ b.HasKey("ProjectID", "TagID");
+
+ b.HasIndex("TagID");
+
+ b.ToTable("ProjectTags");
+ });
+
+ modelBuilder.Entity("Core.Entities.ProjectUser", b =>
+ {
+ b.Property("UserID")
+ .HasColumnType("integer")
+ .HasColumnOrder(1);
+
+ b.Property("ProjectID")
+ .HasColumnType("integer")
+ .HasColumnOrder(2);
+
+ b.Property("IsFollowing")
+ .HasColumnType("boolean");
+
+ b.Property("UserRole")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("UserID", "ProjectID");
+
+ b.HasIndex("ProjectID");
+
+ b.ToTable("ProjectUsers");
+ });
+
+ modelBuilder.Entity("Core.Entities.Publication", b =>
+ {
+ b.Property("PublicationID")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("PublicationID"));
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Doi")
+ .HasColumnType("text");
+
+ b.Property("Issue")
+ .HasColumnType("text");
+
+ b.Property("Journal")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Notes")
+ .HasColumnType("text");
+
+ b.Property("Pages")
+ .HasColumnType("text");
+
+ b.Property("ProjectID")
+ .HasColumnType("integer");
+
+ b.Property("SourceAuthor")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Title")
+ .HasColumnType("text");
+
+ b.Property("Url")
+ .HasColumnType("text");
+
+ b.Property("Volume")
+ .HasColumnType("text");
+
+ b.Property("Year")
+ .HasColumnType("integer");
+
+ b.HasKey("PublicationID");
+
+ b.HasIndex("ProjectID");
+
+ b.ToTable("Publications");
+ });
+
+ modelBuilder.Entity("Core.Entities.Tag", b =>
+ {
+ b.Property("TagID")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("TagID"));
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("TagID");
+
+ b.HasIndex("Name")
+ .IsUnique();
+
+ b.ToTable("Tag");
+ });
+
+ modelBuilder.Entity("Core.Entities.User", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("AccessFailedCount")
+ .HasColumnType("integer");
+
+ b.Property("Bio")
+ .HasColumnType("text");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .HasColumnType("text");
+
+ b.Property("DateCreated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Email")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property("EmailConfirmed")
+ .HasColumnType("boolean");
+
+ b.Property("LastOnline")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("LockoutEnabled")
+ .HasColumnType("boolean");
+
+ b.Property("LockoutEnd")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("NormalizedEmail")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property("NormalizedUserName")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property("PasswordHash")
+ .HasColumnType("text");
+
+ b.Property("PhoneNumber")
+ .HasColumnType("text");
+
+ b.Property("PhoneNumberConfirmed")
+ .HasColumnType("boolean");
+
+ b.Property("ReceiveCommentReplyEmails")
+ .HasColumnType("boolean");
+
+ b.Property("RegistrationSurvey")
+ .HasColumnType("text");
+
+ b.Property("SecurityStamp")
+ .HasColumnType("text");
+
+ b.Property("TwoFactorEnabled")
+ .HasColumnType("boolean");
+
+ b.Property("UserName")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("NormalizedEmail")
+ .HasDatabaseName("EmailIndex");
+
+ b.HasIndex("NormalizedUserName")
+ .IsUnique()
+ .HasDatabaseName("UserNameIndex");
+
+ b.ToTable("AspNetUsers", (string)null);
+ });
+
+ modelBuilder.Entity("Core.Entities.UserUser", b =>
+ {
+ b.Property("UserID")
+ .HasColumnType("integer")
+ .HasColumnOrder(1);
+
+ b.Property("FollowerID")
+ .HasColumnType("integer")
+ .HasColumnOrder(2);
+
+ b.HasKey("UserID", "FollowerID");
+
+ b.HasIndex("FollowerID");
+
+ b.ToTable("UserUsers");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .HasColumnType("text");
+
+ b.Property("Name")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property("NormalizedName")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("NormalizedName")
+ .IsUnique()
+ .HasDatabaseName("RoleNameIndex");
+
+ b.ToTable("AspNetRoles", (string)null);
+
+ b.HasData(
+ new
+ {
+ Id = 1,
+ ConcurrencyStamp = "d7c6278e-3f78-4db6-8832-aa41ea9fd62c",
+ Name = "Admin",
+ NormalizedName = "ADMIN"
+ },
+ new
+ {
+ Id = 2,
+ ConcurrencyStamp = "7383e31e-a884-4cd6-82f7-a6287b4e30a5",
+ Name = "Customer",
+ NormalizedName = "CUSTOMER"
+ },
+ new
+ {
+ Id = 3,
+ ConcurrencyStamp = "398ef1f2-6b82-45f2-9601-ed2129f197e9",
+ Name = "Moderator",
+ NormalizedName = "MODERATOR"
+ });
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("ClaimType")
+ .HasColumnType("text");
+
+ b.Property("ClaimValue")
+ .HasColumnType("text");
+
+ b.Property("RoleId")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.HasIndex("RoleId");
+
+ b.ToTable("AspNetRoleClaims", (string)null);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("ClaimType")
+ .HasColumnType("text");
+
+ b.Property("ClaimValue")
+ .HasColumnType("text");
+
+ b.Property("UserId")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("AspNetUserClaims", (string)null);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b =>
+ {
+ b.Property("LoginProvider")
+ .HasColumnType("text");
+
+ b.Property("ProviderKey")
+ .HasColumnType("text");
+
+ b.Property("ProviderDisplayName")
+ .HasColumnType("text");
+
+ b.Property("UserId")
+ .HasColumnType("integer");
+
+ b.HasKey("LoginProvider", "ProviderKey");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("AspNetUserLogins", (string)null);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b =>
+ {
+ b.Property("UserId")
+ .HasColumnType("integer");
+
+ b.Property("RoleId")
+ .HasColumnType("integer");
+
+ b.HasKey("UserId", "RoleId");
+
+ b.HasIndex("RoleId");
+
+ b.ToTable("AspNetUserRoles", (string)null);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b =>
+ {
+ b.Property("UserId")
+ .HasColumnType("integer");
+
+ b.Property("LoginProvider")
+ .HasColumnType("text");
+
+ b.Property("Name")
+ .HasColumnType("text");
+
+ b.Property("Value")
+ .HasColumnType("text");
+
+ b.HasKey("UserId", "LoginProvider", "Name");
+
+ b.ToTable("AspNetUserTokens", (string)null);
+ });
+
+ modelBuilder.Entity("Analysim.Core.Entities.BlobFileContent", b =>
+ {
+ b.HasOne("Core.Entities.BlobFile", "BlobFile")
+ .WithMany("BlobFileContents")
+ .HasForeignKey("BlobFileID")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("BlobFile");
+ });
+
+ modelBuilder.Entity("Analysim.Core.Entities.NotebookContent", b =>
+ {
+ b.HasOne("Core.Entities.Notebook", "Notebook")
+ .WithMany("NotebookContents")
+ .HasForeignKey("NotebookID")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Notebook");
+ });
+
+ modelBuilder.Entity("Core.Entities.BlobFile", b =>
+ {
+ b.HasOne("Core.Entities.Project", "Project")
+ .WithMany("BlobFiles")
+ .HasForeignKey("ProjectID")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("Core.Entities.User", "User")
+ .WithMany("BlobFiles")
+ .HasForeignKey("UserID")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Project");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("Core.Entities.Notebook", b =>
+ {
+ b.HasOne("Core.Entities.Project", "Project")
+ .WithMany("Notebooks")
+ .HasForeignKey("ProjectID")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.Navigation("Project");
+ });
+
+ modelBuilder.Entity("Core.Entities.ObservableNotebookDataset", b =>
+ {
+ b.HasOne("Core.Entities.Notebook", "notebook")
+ .WithMany("observableNotebookDatasets")
+ .HasForeignKey("NotebookID")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("notebook");
+ });
+
+ modelBuilder.Entity("Core.Entities.ProjectComment", b =>
+ {
+ b.HasOne("Core.Entities.ProjectComment", "ParentComment")
+ .WithMany("Replies")
+ .HasForeignKey("ParentCommentID")
+ .OnDelete(DeleteBehavior.Restrict);
+
+ b.HasOne("Core.Entities.Project", "Project")
+ .WithMany("ProjectComments")
+ .HasForeignKey("ProjectID")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Core.Entities.ProjectLog", "ProjectLog")
+ .WithMany("Comments")
+ .HasForeignKey("ProjectLogID")
+ .OnDelete(DeleteBehavior.Restrict);
+
+ b.HasOne("Core.Entities.User", "User")
+ .WithMany("ProjectComments")
+ .HasForeignKey("UserID")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired();
+
+ b.Navigation("ParentComment");
+
+ b.Navigation("Project");
+
+ b.Navigation("ProjectLog");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("Core.Entities.ProjectCommentFlag", b =>
+ {
+ b.HasOne("Core.Entities.ProjectComment", "ProjectComment")
+ .WithMany("CommentFlags")
+ .HasForeignKey("CommentID")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Core.Entities.User", "User")
+ .WithMany("CommentFlags")
+ .HasForeignKey("UserID")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("ProjectComment");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("Core.Entities.ProjectCommentLike", b =>
+ {
+ b.HasOne("Core.Entities.ProjectComment", "ProjectComment")
+ .WithMany("CommentLikes")
+ .HasForeignKey("CommentID")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Core.Entities.User", "User")
+ .WithMany("CommentLikes")
+ .HasForeignKey("UserID")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("ProjectComment");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("Core.Entities.ProjectLog", b =>
+ {
+ b.HasOne("Core.Entities.BlobFile", "BlobFile")
+ .WithMany()
+ .HasForeignKey("BlobFileID")
+ .OnDelete(DeleteBehavior.SetNull);
+
+ b.HasOne("Core.Entities.Project", "Project")
+ .WithMany("ProjectLogs")
+ .HasForeignKey("ProjectID")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Core.Entities.Notebook", "ReferencedNotebook")
+ .WithMany()
+ .HasForeignKey("ReferencedNotebookID")
+ .OnDelete(DeleteBehavior.SetNull);
+
+ b.HasOne("Core.Entities.User", "User")
+ .WithMany("ProjectLogs")
+ .HasForeignKey("UserID")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired();
+
+ b.Navigation("BlobFile");
+
+ b.Navigation("Project");
+
+ b.Navigation("ReferencedNotebook");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("Core.Entities.ProjectTag", b =>
+ {
+ b.HasOne("Core.Entities.Project", "Project")
+ .WithMany("ProjectTags")
+ .HasForeignKey("ProjectID")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Core.Entities.Tag", "Tag")
+ .WithMany("ProjectTags")
+ .HasForeignKey("TagID")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Project");
+
+ b.Navigation("Tag");
+ });
+
+ modelBuilder.Entity("Core.Entities.ProjectUser", b =>
+ {
+ b.HasOne("Core.Entities.Project", "Project")
+ .WithMany("ProjectUsers")
+ .HasForeignKey("ProjectID")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Core.Entities.User", "User")
+ .WithMany("ProjectUsers")
+ .HasForeignKey("UserID")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Project");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("Core.Entities.Publication", b =>
+ {
+ b.HasOne("Core.Entities.Project", "Project")
+ .WithMany("Publications")
+ .HasForeignKey("ProjectID")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Project");
+ });
+
+ modelBuilder.Entity("Core.Entities.UserUser", b =>
+ {
+ b.HasOne("Core.Entities.User", "Follower")
+ .WithMany("Following")
+ .HasForeignKey("FollowerID")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Core.Entities.User", "User")
+ .WithMany("Followers")
+ .HasForeignKey("UserID")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Follower");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b =>
+ {
+ b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
+ .WithMany()
+ .HasForeignKey("RoleId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b =>
+ {
+ b.HasOne("Core.Entities.User", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b =>
+ {
+ b.HasOne("Core.Entities.User", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b =>
+ {
+ b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
+ .WithMany()
+ .HasForeignKey("RoleId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Core.Entities.User", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b =>
+ {
+ b.HasOne("Core.Entities.User", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Core.Entities.BlobFile", b =>
+ {
+ b.Navigation("BlobFileContents");
+ });
+
+ modelBuilder.Entity("Core.Entities.Notebook", b =>
+ {
+ b.Navigation("NotebookContents");
+
+ b.Navigation("observableNotebookDatasets");
+ });
+
+ modelBuilder.Entity("Core.Entities.Project", b =>
+ {
+ b.Navigation("BlobFiles");
+
+ b.Navigation("Notebooks");
+
+ b.Navigation("ProjectComments");
+
+ b.Navigation("ProjectLogs");
+
+ b.Navigation("ProjectTags");
+
+ b.Navigation("ProjectUsers");
+
+ b.Navigation("Publications");
+ });
+
+ modelBuilder.Entity("Core.Entities.ProjectComment", b =>
+ {
+ b.Navigation("CommentFlags");
+
+ b.Navigation("CommentLikes");
+
+ b.Navigation("Replies");
+ });
+
+ modelBuilder.Entity("Core.Entities.ProjectLog", b =>
+ {
+ b.Navigation("Comments");
+ });
+
+ modelBuilder.Entity("Core.Entities.Tag", b =>
+ {
+ b.Navigation("ProjectTags");
+ });
+
+ modelBuilder.Entity("Core.Entities.User", b =>
+ {
+ b.Navigation("BlobFiles");
+
+ b.Navigation("CommentFlags");
+
+ b.Navigation("CommentLikes");
+
+ b.Navigation("Followers");
+
+ b.Navigation("Following");
+
+ b.Navigation("ProjectComments");
+
+ b.Navigation("ProjectLogs");
+
+ b.Navigation("ProjectUsers");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/src/Analysim.Infrastructure/Migrations/20260702170313_AddUniqueIndexesForProjectRouteAndTagName.cs b/src/Analysim.Infrastructure/Migrations/20260702170313_AddUniqueIndexesForProjectRouteAndTagName.cs
new file mode 100644
index 00000000..48e20ad6
--- /dev/null
+++ b/src/Analysim.Infrastructure/Migrations/20260702170313_AddUniqueIndexesForProjectRouteAndTagName.cs
@@ -0,0 +1,38 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace Analysim.Infrastructure.Migrations
+{
+ ///
+ public partial class AddUniqueIndexesForProjectRouteAndTagName : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateIndex(
+ name: "IX_Tag_Name",
+ table: "Tag",
+ column: "Name",
+ unique: true);
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Projects_Route",
+ table: "Projects",
+ column: "Route",
+ unique: true);
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropIndex(
+ name: "IX_Tag_Name",
+ table: "Tag");
+
+ migrationBuilder.DropIndex(
+ name: "IX_Projects_Route",
+ table: "Projects");
+ }
+ }
+}
diff --git a/src/Analysim.Web/Analysim.Web.csproj b/src/Analysim.Web/Analysim.Web.csproj
index 85d9912d..cb17338d 100644
--- a/src/Analysim.Web/Analysim.Web.csproj
+++ b/src/Analysim.Web/Analysim.Web.csproj
@@ -1,7 +1,7 @@
- net6.0
+ net10.0
true
Latest
false
@@ -19,17 +19,16 @@
-
-
-
-
-
-
+
+
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
+
+
diff --git a/src/Analysim.Web/Startup.cs b/src/Analysim.Web/Startup.cs
index 028ed82d..e4814af3 100644
--- a/src/Analysim.Web/Startup.cs
+++ b/src/Analysim.Web/Startup.cs
@@ -1,4 +1,4 @@
-using AutoMapper;
+using System.Collections.Generic;
using Core.Interfaces;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
@@ -8,6 +8,7 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
+using Microsoft.OpenApi;
using Web.Extensions;
namespace Web
@@ -31,34 +32,27 @@ public void ConfigureServices(IServiceCollection services)
services.AddSwaggerGen(c =>
{
- c.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo
+ c.SwaggerDoc("v1", new OpenApiInfo
{
Title = "AnalySim API",
Version = "v1"
});
- c.AddSecurityDefinition("Bearer", new Microsoft.OpenApi.Models.OpenApiSecurityScheme
+ c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Name = "Authorization",
- Type = Microsoft.OpenApi.Models.SecuritySchemeType.ApiKey,
+ Type = SecuritySchemeType.ApiKey,
Scheme = "Bearer",
BearerFormat = "JWT",
- In = Microsoft.OpenApi.Models.ParameterLocation.Header,
+ In = ParameterLocation.Header,
Description = "Enter 'Bearer' followed by your JWT token (e.g. 'Bearer eyJhbGci...')"
});
- c.AddSecurityRequirement(new Microsoft.OpenApi.Models.OpenApiSecurityRequirement
+ c.AddSecurityRequirement(document => new OpenApiSecurityRequirement
{
{
- new Microsoft.OpenApi.Models.OpenApiSecurityScheme
- {
- Reference = new Microsoft.OpenApi.Models.OpenApiReference
- {
- Type = Microsoft.OpenApi.Models.ReferenceType.SecurityScheme,
- Id = "Bearer"
- }
- },
- new string[] {}
+ new OpenApiSecuritySchemeReference("Bearer", document, null),
+ new List()
}
});
});
@@ -76,8 +70,6 @@ public void ConfigureServices(IServiceCollection services)
services.ConfigureMailService(Configuration);
- services.AddAutoMapper(typeof(Startup));
-
services.AddControllers(config =>
{
config.RespectBrowserAcceptHeader = true;