diff --git a/AskFm/.idea/.idea.AskFm/.idea/.gitignore b/AskFm/.idea/.idea.AskFm/.idea/.gitignore
deleted file mode 100644
index 639f69a..0000000
--- a/AskFm/.idea/.idea.AskFm/.idea/.gitignore
+++ /dev/null
@@ -1,13 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
-# Rider ignored files
-/modules.xml
-/contentModel.xml
-/projectSettingsUpdater.xml
-/.idea.AskFm.iml
-# Editor-based HTTP Client requests
-/httpRequests/
-# Datasource local storage ignored files
-/dataSources/
-/dataSources.local.xml
diff --git a/AskFm/.idea/.idea.AskFm/.idea/encodings.xml b/AskFm/.idea/.idea.AskFm/.idea/encodings.xml
deleted file mode 100644
index df87cf9..0000000
--- a/AskFm/.idea/.idea.AskFm/.idea/encodings.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/AskFm/.idea/.idea.AskFm/.idea/indexLayout.xml b/AskFm/.idea/.idea.AskFm/.idea/indexLayout.xml
deleted file mode 100644
index 7c38c58..0000000
--- a/AskFm/.idea/.idea.AskFm/.idea/indexLayout.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
- ../../Backend
-
-
-
-
-
\ No newline at end of file
diff --git a/AskFm/.idea/.idea.AskFm/.idea/vcs.xml b/AskFm/.idea/.idea.AskFm/.idea/vcs.xml
deleted file mode 100644
index 62bd7a0..0000000
--- a/AskFm/.idea/.idea.AskFm/.idea/vcs.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/AskFm/AskFm.API/.env.example b/AskFm/AskFm.API/.env.example
new file mode 100644
index 0000000..ee8850c
--- /dev/null
+++ b/AskFm/AskFm.API/.env.example
@@ -0,0 +1 @@
+CONNECTION_STRING="Put you connection string here then rename file to .env"
diff --git a/AskFm/AskFm.API/AskFm.API.csproj b/AskFm/AskFm.API/AskFm.API.csproj
index 1fb1acc..d791ad5 100644
--- a/AskFm/AskFm.API/AskFm.API.csproj
+++ b/AskFm/AskFm.API/AskFm.API.csproj
@@ -7,15 +7,20 @@
-
-
-
-
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
-
-
+
+
diff --git a/AskFm/AskFm.API/Program.cs b/AskFm/AskFm.API/Program.cs
index df0e0cd..807ebe5 100644
--- a/AskFm/AskFm.API/Program.cs
+++ b/AskFm/AskFm.API/Program.cs
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;
using AskFm.DAL;
-
+using DotNetEnv;
namespace AskFm.API;
public class Program
@@ -15,8 +15,14 @@ public static void Main(string[] args)
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
builder.Services.AddOpenApi();
+ Env.Load();
+ string ConnectionString = Environment.GetEnvironmentVariable("CONNECTION_STRING");
+ if (ConnectionString is null)
+ {
+ throw new Exception("Connection string is null");
+ }
builder.Services.AddDbContext(options =>
- options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
+ options.UseSqlServer(ConnectionString));
var app = builder.Build();
diff --git a/AskFm/AskFm.API/appsettings.json b/AskFm/AskFm.API/appsettings.json
index dd02a79..779f8b0 100644
--- a/AskFm/AskFm.API/appsettings.json
+++ b/AskFm/AskFm.API/appsettings.json
@@ -1,6 +1,6 @@
{
"ConnectionStrings": {
- "DefaultConnection": "Server=.; Database = AskClone; Integrated Security = SSPI; TrustServerCertificate = True;"
+ "DefaultConnection": "CONNECTIONSTRING"
},
"Logging": {
"LogLevel": {
diff --git a/AskFm/AskFm.DAL/AppDbContext.cs b/AskFm/AskFm.DAL/AppDbContext.cs
index 0cd9d6a..70b80cd 100644
--- a/AskFm/AskFm.DAL/AppDbContext.cs
+++ b/AskFm/AskFm.DAL/AppDbContext.cs
@@ -1,6 +1,6 @@
-using AskFm.DAL.Moodels;
+using AskFm.DAL.Models;
using Microsoft.EntityFrameworkCore;
-using Thread = AskFm.DAL.Moodels.Thread;
+using Thread = AskFm.DAL.Models.Thread;
namespace AskFm.DAL;
@@ -14,10 +14,10 @@ public AppDbContext(DbContextOptions options) : base(options)
public DbSet Threads { get; set; }
public DbSet Comments { get; set; }
public DbSet Follows { get; set; }
- public DbSet QuestionLikes { get; set; }
+ public DbSet ThreadLikes { get; set; }
public DbSet CommentLikes { get; set; }
public DbSet Notifications { get; set; }
-
+ public DbSet SavedThreads { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
diff --git a/AskFm/AskFm.DAL/AskFm.DAL.csproj b/AskFm/AskFm.DAL/AskFm.DAL.csproj
index af00d85..4b32852 100644
--- a/AskFm/AskFm.DAL/AskFm.DAL.csproj
+++ b/AskFm/AskFm.DAL/AskFm.DAL.csproj
@@ -4,21 +4,22 @@
net9.0
enable
enable
- AskFm.DLL
+ AskFm.DAL
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
@@ -28,7 +29,7 @@
-
+
diff --git a/AskFm/AskFm.DAL/Enums/NotificationStatus.cs b/AskFm/AskFm.DAL/Enums/NotificationStatus.cs
index 8363d49..4a68626 100644
--- a/AskFm/AskFm.DAL/Enums/NotificationStatus.cs
+++ b/AskFm/AskFm.DAL/Enums/NotificationStatus.cs
@@ -2,10 +2,10 @@ namespace AskFm.DAL.Enums;
public enum NotificationStatus
{
- ANSWER = 1,
- QUESTION = 2,
- FOLLOW = 3,
- COMMENT_LIKE = 4,
- QUESTION_LIKE = 5,
- REPLAY = 6
+ ANSWER ,
+ QUESTION,
+ FOLLOW,
+ COMMENT_LIKE,
+ QUESTION_LIKE,
+ REPLAY
}
\ No newline at end of file
diff --git a/AskFm/AskFm.DAL/Enums/ThreadStatus.cs b/AskFm/AskFm.DAL/Enums/ThreadStatus.cs
index b91dbb7..8bd4d98 100644
--- a/AskFm/AskFm.DAL/Enums/ThreadStatus.cs
+++ b/AskFm/AskFm.DAL/Enums/ThreadStatus.cs
@@ -1,6 +1,8 @@
namespace AskFm.DAL.Enums;
public enum ThreadStatus
{
- PRIVATE = 1,
- PUBLIC = 2
+ PRIVATE,
+ PUBLIC,
+ Closed,
+ PRIVATEQUESTION
}
\ No newline at end of file
diff --git a/AskFm/AskFm.DAL/Migrations/20250728202022_Initial.Designer.cs b/AskFm/AskFm.DAL/Migrations/20250728202022_Initial.Designer.cs
new file mode 100644
index 0000000..027b16a
--- /dev/null
+++ b/AskFm/AskFm.DAL/Migrations/20250728202022_Initial.Designer.cs
@@ -0,0 +1,395 @@
+//
+using System;
+using AskFm.DAL;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace AskFm.DAL.Migrations
+{
+ [DbContext(typeof(AppDbContext))]
+ [Migration("20250728202022_Initial")]
+ partial class Initial
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "9.0.0")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128);
+
+ SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
+
+ modelBuilder.Entity("AskFm.DAL.Models.Comment", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("Content")
+ .IsRequired()
+ .HasMaxLength(1000)
+ .HasColumnType("nvarchar(1000)");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime");
+
+ b.Property("LikeCount")
+ .HasColumnType("int");
+
+ b.Property("ParentCommentId")
+ .HasColumnType("int");
+
+ b.Property("ThreadId")
+ .HasColumnType("int");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ParentCommentId");
+
+ b.HasIndex("ThreadId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("Comments");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.CommentLike", b =>
+ {
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.Property("CommentId")
+ .HasColumnType("int");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime");
+
+ b.HasKey("UserId", "CommentId");
+
+ b.HasIndex("CommentId");
+
+ b.ToTable("CommentLikes");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Follow", b =>
+ {
+ b.Property("FollowerId")
+ .HasColumnType("int");
+
+ b.Property("FollowedId")
+ .HasColumnType("int");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2");
+
+ b.HasKey("FollowerId", "FollowedId");
+
+ b.HasIndex("FollowedId");
+
+ b.ToTable("Follows");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Notification", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime");
+
+ b.Property("ResourceId")
+ .HasColumnType("int");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.Property("isRead")
+ .HasColumnType("bit");
+
+ b.Property("jsonContent")
+ .IsRequired()
+ .HasColumnType("NVARCHAR");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("Notifications");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Thread", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("AnswerContent")
+ .IsRequired()
+ .HasMaxLength(4000)
+ .HasColumnType("nvarchar(4000)");
+
+ b.Property("AskedId")
+ .HasColumnType("int");
+
+ b.Property("AskerId")
+ .HasColumnType("int");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime");
+
+ b.Property("QuestionContent")
+ .IsRequired()
+ .HasMaxLength(1000)
+ .HasColumnType("nvarchar(1000)");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("isAnonymous")
+ .HasColumnType("bit");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AskedId");
+
+ b.HasIndex("AskerId");
+
+ b.ToTable("Thread", (string)null);
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.ThreadLike", b =>
+ {
+ b.Property("ThreadId")
+ .HasColumnType("int");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime");
+
+ b.HasKey("ThreadId", "UserId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("ThreadLikes");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.User", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("AvatarPath")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Bio")
+ .IsRequired()
+ .HasMaxLength(500)
+ .HasColumnType("nvarchar(500)");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("Email")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("nvarchar(255)");
+
+ b.Property("FolloweingCount")
+ .HasColumnType("int");
+
+ b.Property("FollowersCount")
+ .HasColumnType("int");
+
+ b.Property("LastSeen")
+ .HasColumnType("datetime2");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("nvarchar(50)");
+
+ b.Property("Password")
+ .IsRequired()
+ .HasMaxLength(225)
+ .HasColumnType("nvarchar(225)");
+
+ b.Property("Username")
+ .IsRequired()
+ .HasColumnType("nvarchar(450)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Username")
+ .IsUnique();
+
+ b.ToTable("Users");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Comment", b =>
+ {
+ b.HasOne("AskFm.DAL.Models.Comment", "ParentComment")
+ .WithMany("Replies")
+ .HasForeignKey("ParentCommentId");
+
+ b.HasOne("AskFm.DAL.Models.Thread", "Thread")
+ .WithMany("Comments")
+ .HasForeignKey("ThreadId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("AskFm.DAL.Models.User", "User")
+ .WithMany("Comments")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.NoAction);
+
+ b.Navigation("ParentComment");
+
+ b.Navigation("Thread");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.CommentLike", b =>
+ {
+ b.HasOne("AskFm.DAL.Models.Comment", "Comment")
+ .WithMany("CommentLikes")
+ .HasForeignKey("CommentId")
+ .OnDelete(DeleteBehavior.NoAction)
+ .IsRequired();
+
+ b.HasOne("AskFm.DAL.Models.User", "User")
+ .WithMany("CommentLikes")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Comment");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Follow", b =>
+ {
+ b.HasOne("AskFm.DAL.Models.User", "Followed")
+ .WithMany("Followers")
+ .HasForeignKey("FollowedId")
+ .OnDelete(DeleteBehavior.NoAction)
+ .IsRequired();
+
+ b.HasOne("AskFm.DAL.Models.User", "Follower")
+ .WithMany("Following")
+ .HasForeignKey("FollowerId")
+ .OnDelete(DeleteBehavior.NoAction)
+ .IsRequired();
+
+ b.Navigation("Followed");
+
+ b.Navigation("Follower");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Notification", b =>
+ {
+ b.HasOne("AskFm.DAL.Models.User", "User")
+ .WithMany("Notifications")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Thread", b =>
+ {
+ b.HasOne("AskFm.DAL.Models.User", "Asked")
+ .WithMany("ReceivedThreads")
+ .HasForeignKey("AskedId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("AskFm.DAL.Models.User", "Asker")
+ .WithMany("AskedThreads")
+ .HasForeignKey("AskerId");
+
+ b.Navigation("Asked");
+
+ b.Navigation("Asker");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.ThreadLike", b =>
+ {
+ b.HasOne("AskFm.DAL.Models.Thread", "Thread")
+ .WithMany("ThreadLikes")
+ .HasForeignKey("ThreadId")
+ .OnDelete(DeleteBehavior.NoAction)
+ .IsRequired();
+
+ b.HasOne("AskFm.DAL.Models.User", "User")
+ .WithMany("ThreadLikes")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Thread");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Comment", b =>
+ {
+ b.Navigation("CommentLikes");
+
+ b.Navigation("Replies");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Thread", b =>
+ {
+ b.Navigation("Comments");
+
+ b.Navigation("ThreadLikes");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.User", b =>
+ {
+ b.Navigation("AskedThreads");
+
+ b.Navigation("CommentLikes");
+
+ b.Navigation("Comments");
+
+ b.Navigation("Followers");
+
+ b.Navigation("Following");
+
+ b.Navigation("Notifications");
+
+ b.Navigation("ReceivedThreads");
+
+ b.Navigation("ThreadLikes");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/AskFm/AskFm.DAL/Migrations/20250728202022_Initial.cs b/AskFm/AskFm.DAL/Migrations/20250728202022_Initial.cs
new file mode 100644
index 0000000..94399b1
--- /dev/null
+++ b/AskFm/AskFm.DAL/Migrations/20250728202022_Initial.cs
@@ -0,0 +1,271 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace AskFm.DAL.Migrations
+{
+ ///
+ public partial class Initial : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "Users",
+ columns: table => new
+ {
+ Id = table.Column(type: "int", nullable: false)
+ .Annotation("SqlServer:Identity", "1, 1"),
+ Name = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false),
+ Username = table.Column(type: "nvarchar(450)", nullable: false),
+ Email = table.Column(type: "nvarchar(255)", maxLength: 255, nullable: false),
+ Password = table.Column(type: "nvarchar(225)", maxLength: 225, nullable: false),
+ Bio = table.Column(type: "nvarchar(500)", maxLength: 500, nullable: false),
+ AvatarPath = table.Column(type: "nvarchar(max)", nullable: false),
+ FollowersCount = table.Column(type: "int", nullable: false),
+ FolloweingCount = table.Column(type: "int", nullable: false),
+ CreatedAt = table.Column(type: "datetime2", nullable: false),
+ LastSeen = table.Column(type: "datetime2", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Users", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Follows",
+ columns: table => new
+ {
+ FollowerId = table.Column(type: "int", nullable: false),
+ FollowedId = table.Column(type: "int", nullable: false),
+ CreatedAt = table.Column(type: "datetime2", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Follows", x => new { x.FollowerId, x.FollowedId });
+ table.ForeignKey(
+ name: "FK_Follows_Users_FollowedId",
+ column: x => x.FollowedId,
+ principalTable: "Users",
+ principalColumn: "Id");
+ table.ForeignKey(
+ name: "FK_Follows_Users_FollowerId",
+ column: x => x.FollowerId,
+ principalTable: "Users",
+ principalColumn: "Id");
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Notifications",
+ columns: table => new
+ {
+ Id = table.Column(type: "int", nullable: false)
+ .Annotation("SqlServer:Identity", "1, 1"),
+ UserId = table.Column(type: "int", nullable: false),
+ isRead = table.Column(type: "bit", nullable: false),
+ ResourceId = table.Column(type: "int", nullable: false),
+ jsonContent = table.Column(type: "NVARCHAR", nullable: false),
+ CreatedAt = table.Column(type: "datetime", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Notifications", x => x.Id);
+ table.ForeignKey(
+ name: "FK_Notifications_Users_UserId",
+ column: x => x.UserId,
+ principalTable: "Users",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Thread",
+ columns: table => new
+ {
+ Id = table.Column(type: "int", nullable: false)
+ .Annotation("SqlServer:Identity", "1, 1"),
+ QuestionContent = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: false),
+ AnswerContent = table.Column(type: "nvarchar(4000)", maxLength: 4000, nullable: false),
+ Status = table.Column(type: "nvarchar(max)", nullable: false),
+ isAnonymous = table.Column(type: "bit", nullable: false),
+ CreatedAt = table.Column(type: "datetime", nullable: false),
+ AskerId = table.Column(type: "int", nullable: true),
+ AskedId = table.Column(type: "int", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Thread", x => x.Id);
+ table.ForeignKey(
+ name: "FK_Thread_Users_AskedId",
+ column: x => x.AskedId,
+ principalTable: "Users",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ table.ForeignKey(
+ name: "FK_Thread_Users_AskerId",
+ column: x => x.AskerId,
+ principalTable: "Users",
+ principalColumn: "Id");
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Comments",
+ columns: table => new
+ {
+ Id = table.Column(type: "int", nullable: false)
+ .Annotation("SqlServer:Identity", "1, 1"),
+ Content = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: false),
+ CreatedAt = table.Column(type: "datetime", nullable: false),
+ LikeCount = table.Column(type: "int", nullable: false),
+ UserId = table.Column(type: "int", nullable: true),
+ ThreadId = table.Column(type: "int", nullable: false),
+ ParentCommentId = table.Column(type: "int", nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Comments", x => x.Id);
+ table.ForeignKey(
+ name: "FK_Comments_Comments_ParentCommentId",
+ column: x => x.ParentCommentId,
+ principalTable: "Comments",
+ principalColumn: "Id");
+ table.ForeignKey(
+ name: "FK_Comments_Thread_ThreadId",
+ column: x => x.ThreadId,
+ principalTable: "Thread",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ table.ForeignKey(
+ name: "FK_Comments_Users_UserId",
+ column: x => x.UserId,
+ principalTable: "Users",
+ principalColumn: "Id");
+ });
+
+ migrationBuilder.CreateTable(
+ name: "ThreadLikes",
+ columns: table => new
+ {
+ ThreadId = table.Column(type: "int", nullable: false),
+ UserId = table.Column(type: "int", nullable: false),
+ CreatedAt = table.Column(type: "datetime", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_ThreadLikes", x => new { x.ThreadId, x.UserId });
+ table.ForeignKey(
+ name: "FK_ThreadLikes_Thread_ThreadId",
+ column: x => x.ThreadId,
+ principalTable: "Thread",
+ principalColumn: "Id");
+ table.ForeignKey(
+ name: "FK_ThreadLikes_Users_UserId",
+ column: x => x.UserId,
+ principalTable: "Users",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "CommentLikes",
+ columns: table => new
+ {
+ CommentId = table.Column(type: "int", nullable: false),
+ UserId = table.Column(type: "int", nullable: false),
+ CreatedAt = table.Column(type: "datetime", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_CommentLikes", x => new { x.UserId, x.CommentId });
+ table.ForeignKey(
+ name: "FK_CommentLikes_Comments_CommentId",
+ column: x => x.CommentId,
+ principalTable: "Comments",
+ principalColumn: "Id");
+ table.ForeignKey(
+ name: "FK_CommentLikes_Users_UserId",
+ column: x => x.UserId,
+ principalTable: "Users",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateIndex(
+ name: "IX_CommentLikes_CommentId",
+ table: "CommentLikes",
+ column: "CommentId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Comments_ParentCommentId",
+ table: "Comments",
+ column: "ParentCommentId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Comments_ThreadId",
+ table: "Comments",
+ column: "ThreadId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Comments_UserId",
+ table: "Comments",
+ column: "UserId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Follows_FollowedId",
+ table: "Follows",
+ column: "FollowedId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Notifications_UserId",
+ table: "Notifications",
+ column: "UserId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Thread_AskedId",
+ table: "Thread",
+ column: "AskedId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Thread_AskerId",
+ table: "Thread",
+ column: "AskerId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_ThreadLikes_UserId",
+ table: "ThreadLikes",
+ column: "UserId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Users_Username",
+ table: "Users",
+ column: "Username",
+ unique: true);
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "CommentLikes");
+
+ migrationBuilder.DropTable(
+ name: "Follows");
+
+ migrationBuilder.DropTable(
+ name: "Notifications");
+
+ migrationBuilder.DropTable(
+ name: "ThreadLikes");
+
+ migrationBuilder.DropTable(
+ name: "Comments");
+
+ migrationBuilder.DropTable(
+ name: "Thread");
+
+ migrationBuilder.DropTable(
+ name: "Users");
+ }
+ }
+}
diff --git a/AskFm/AskFm.DAL/Migrations/20250728213423_add_2_status_Thread.Designer.cs b/AskFm/AskFm.DAL/Migrations/20250728213423_add_2_status_Thread.Designer.cs
new file mode 100644
index 0000000..7c621aa
--- /dev/null
+++ b/AskFm/AskFm.DAL/Migrations/20250728213423_add_2_status_Thread.Designer.cs
@@ -0,0 +1,398 @@
+//
+using System;
+using AskFm.DAL;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace AskFm.DAL.Migrations
+{
+ [DbContext(typeof(AppDbContext))]
+ [Migration("20250728213423_add_2_status_Thread")]
+ partial class add_2_status_Thread
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "9.0.0")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128);
+
+ SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
+
+ modelBuilder.Entity("AskFm.DAL.Models.Comment", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("Content")
+ .IsRequired()
+ .HasMaxLength(1000)
+ .HasColumnType("nvarchar(1000)");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime");
+
+ b.Property("LikeCount")
+ .HasColumnType("int");
+
+ b.Property("ParentCommentId")
+ .HasColumnType("int");
+
+ b.Property("ThreadId")
+ .HasColumnType("int");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ParentCommentId");
+
+ b.HasIndex("ThreadId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("Comments");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.CommentLike", b =>
+ {
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.Property("CommentId")
+ .HasColumnType("int");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime");
+
+ b.HasKey("UserId", "CommentId");
+
+ b.HasIndex("CommentId");
+
+ b.ToTable("CommentLikes");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Follow", b =>
+ {
+ b.Property("FollowerId")
+ .HasColumnType("int");
+
+ b.Property("FollowedId")
+ .HasColumnType("int");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("IsActive")
+ .HasColumnType("bit");
+
+ b.HasKey("FollowerId", "FollowedId");
+
+ b.HasIndex("FollowedId");
+
+ b.ToTable("Follows");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Notification", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime");
+
+ b.Property("ResourceId")
+ .HasColumnType("int");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.Property("isRead")
+ .HasColumnType("bit");
+
+ b.Property("jsonContent")
+ .IsRequired()
+ .HasColumnType("NVARCHAR");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("Notifications");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Thread", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("AnswerContent")
+ .IsRequired()
+ .HasMaxLength(4000)
+ .HasColumnType("nvarchar(4000)");
+
+ b.Property("AskedId")
+ .HasColumnType("int");
+
+ b.Property("AskerId")
+ .HasColumnType("int");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime");
+
+ b.Property("QuestionContent")
+ .IsRequired()
+ .HasMaxLength(1000)
+ .HasColumnType("nvarchar(1000)");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("isAnonymous")
+ .HasColumnType("bit");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AskedId");
+
+ b.HasIndex("AskerId");
+
+ b.ToTable("Thread", (string)null);
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.ThreadLike", b =>
+ {
+ b.Property("ThreadId")
+ .HasColumnType("int");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime");
+
+ b.HasKey("ThreadId", "UserId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("ThreadLikes");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.User", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("AvatarPath")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Bio")
+ .IsRequired()
+ .HasMaxLength(500)
+ .HasColumnType("nvarchar(500)");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("Email")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("nvarchar(255)");
+
+ b.Property("FolloweingCount")
+ .HasColumnType("int");
+
+ b.Property("FollowersCount")
+ .HasColumnType("int");
+
+ b.Property("LastSeen")
+ .HasColumnType("datetime2");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("nvarchar(50)");
+
+ b.Property("Password")
+ .IsRequired()
+ .HasMaxLength(225)
+ .HasColumnType("nvarchar(225)");
+
+ b.Property("Username")
+ .IsRequired()
+ .HasColumnType("nvarchar(450)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Username")
+ .IsUnique();
+
+ b.ToTable("Users");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Comment", b =>
+ {
+ b.HasOne("AskFm.DAL.Models.Comment", "ParentComment")
+ .WithMany("Replies")
+ .HasForeignKey("ParentCommentId");
+
+ b.HasOne("AskFm.DAL.Models.Thread", "Thread")
+ .WithMany("Comments")
+ .HasForeignKey("ThreadId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("AskFm.DAL.Models.User", "User")
+ .WithMany("Comments")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.NoAction);
+
+ b.Navigation("ParentComment");
+
+ b.Navigation("Thread");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.CommentLike", b =>
+ {
+ b.HasOne("AskFm.DAL.Models.Comment", "Comment")
+ .WithMany("CommentLikes")
+ .HasForeignKey("CommentId")
+ .OnDelete(DeleteBehavior.NoAction)
+ .IsRequired();
+
+ b.HasOne("AskFm.DAL.Models.User", "User")
+ .WithMany("CommentLikes")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Comment");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Follow", b =>
+ {
+ b.HasOne("AskFm.DAL.Models.User", "Followed")
+ .WithMany("Followers")
+ .HasForeignKey("FollowedId")
+ .OnDelete(DeleteBehavior.NoAction)
+ .IsRequired();
+
+ b.HasOne("AskFm.DAL.Models.User", "Follower")
+ .WithMany("Following")
+ .HasForeignKey("FollowerId")
+ .OnDelete(DeleteBehavior.NoAction)
+ .IsRequired();
+
+ b.Navigation("Followed");
+
+ b.Navigation("Follower");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Notification", b =>
+ {
+ b.HasOne("AskFm.DAL.Models.User", "User")
+ .WithMany("Notifications")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Thread", b =>
+ {
+ b.HasOne("AskFm.DAL.Models.User", "Asked")
+ .WithMany("ReceivedThreads")
+ .HasForeignKey("AskedId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("AskFm.DAL.Models.User", "Asker")
+ .WithMany("AskedThreads")
+ .HasForeignKey("AskerId");
+
+ b.Navigation("Asked");
+
+ b.Navigation("Asker");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.ThreadLike", b =>
+ {
+ b.HasOne("AskFm.DAL.Models.Thread", "Thread")
+ .WithMany("ThreadLikes")
+ .HasForeignKey("ThreadId")
+ .OnDelete(DeleteBehavior.NoAction)
+ .IsRequired();
+
+ b.HasOne("AskFm.DAL.Models.User", "User")
+ .WithMany("ThreadLikes")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Thread");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Comment", b =>
+ {
+ b.Navigation("CommentLikes");
+
+ b.Navigation("Replies");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Thread", b =>
+ {
+ b.Navigation("Comments");
+
+ b.Navigation("ThreadLikes");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.User", b =>
+ {
+ b.Navigation("AskedThreads");
+
+ b.Navigation("CommentLikes");
+
+ b.Navigation("Comments");
+
+ b.Navigation("Followers");
+
+ b.Navigation("Following");
+
+ b.Navigation("Notifications");
+
+ b.Navigation("ReceivedThreads");
+
+ b.Navigation("ThreadLikes");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/AskFm/AskFm.DAL/Migrations/20250728213423_add_2_status_Thread.cs b/AskFm/AskFm.DAL/Migrations/20250728213423_add_2_status_Thread.cs
new file mode 100644
index 0000000..92499b6
--- /dev/null
+++ b/AskFm/AskFm.DAL/Migrations/20250728213423_add_2_status_Thread.cs
@@ -0,0 +1,36 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace AskFm.DAL.Migrations
+{
+ ///
+ public partial class add_2_status_Thread : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AlterColumn(
+ name: "IsActive",
+ table: "Follows",
+ type: "bit",
+ nullable: false,
+ oldClrType: typeof(bool),
+ oldType: "bit",
+ oldDefaultValue: true);
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AlterColumn(
+ name: "IsActive",
+ table: "Follows",
+ type: "bit",
+ nullable: false,
+ defaultValue: true,
+ oldClrType: typeof(bool),
+ oldType: "bit");
+ }
+ }
+}
diff --git a/AskFm/AskFm.DAL/Migrations/20250728225552_apply_savedThread.Designer.cs b/AskFm/AskFm.DAL/Migrations/20250728225552_apply_savedThread.Designer.cs
new file mode 100644
index 0000000..eda00ed
--- /dev/null
+++ b/AskFm/AskFm.DAL/Migrations/20250728225552_apply_savedThread.Designer.cs
@@ -0,0 +1,436 @@
+//
+using System;
+using AskFm.DAL;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace AskFm.DAL.Migrations
+{
+ [DbContext(typeof(AppDbContext))]
+ [Migration("20250728225552_apply_savedThread")]
+ partial class apply_savedThread
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "9.0.0")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128);
+
+ SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
+
+ modelBuilder.Entity("AskFm.DAL.Models.Comment", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("Content")
+ .IsRequired()
+ .HasMaxLength(1000)
+ .HasColumnType("nvarchar(1000)");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime");
+
+ b.Property("LikeCount")
+ .HasColumnType("int");
+
+ b.Property("ParentCommentId")
+ .HasColumnType("int");
+
+ b.Property("ThreadId")
+ .HasColumnType("int");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ParentCommentId");
+
+ b.HasIndex("ThreadId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("Comments");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.CommentLike", b =>
+ {
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.Property("CommentId")
+ .HasColumnType("int");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime");
+
+ b.HasKey("UserId", "CommentId");
+
+ b.HasIndex("CommentId");
+
+ b.ToTable("CommentLikes");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Follow", b =>
+ {
+ b.Property("FollowerId")
+ .HasColumnType("int");
+
+ b.Property("FollowedId")
+ .HasColumnType("int");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("IsActive")
+ .HasColumnType("bit");
+
+ b.HasKey("FollowerId", "FollowedId");
+
+ b.HasIndex("FollowedId");
+
+ b.ToTable("Follows");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Notification", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime");
+
+ b.Property("ResourceId")
+ .HasColumnType("int");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.Property("isRead")
+ .HasColumnType("bit");
+
+ b.Property("jsonContent")
+ .IsRequired()
+ .HasColumnType("NVARCHAR");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("Notifications");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.SavedThreads", b =>
+ {
+ b.Property("ThreadId")
+ .HasColumnType("int");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.HasKey("ThreadId", "UserId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("SavedThreads");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Thread", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("AnswerContent")
+ .IsRequired()
+ .HasMaxLength(4000)
+ .HasColumnType("nvarchar(4000)");
+
+ b.Property("AskedId")
+ .HasColumnType("int");
+
+ b.Property("AskerId")
+ .HasColumnType("int");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime");
+
+ b.Property("QuestionContent")
+ .IsRequired()
+ .HasMaxLength(1000)
+ .HasColumnType("nvarchar(1000)");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("isAnonymous")
+ .HasColumnType("bit");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AskedId");
+
+ b.HasIndex("AskerId");
+
+ b.ToTable("Thread", (string)null);
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.ThreadLike", b =>
+ {
+ b.Property("ThreadId")
+ .HasColumnType("int");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime");
+
+ b.HasKey("ThreadId", "UserId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("ThreadLikes");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.User", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("AvatarPath")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Bio")
+ .IsRequired()
+ .HasMaxLength(500)
+ .HasColumnType("nvarchar(500)");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("Email")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("nvarchar(255)");
+
+ b.Property("FolloweingCount")
+ .HasColumnType("int");
+
+ b.Property("FollowersCount")
+ .HasColumnType("int");
+
+ b.Property("LastSeen")
+ .HasColumnType("datetime2");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("nvarchar(50)");
+
+ b.Property("Password")
+ .IsRequired()
+ .HasMaxLength(225)
+ .HasColumnType("nvarchar(225)");
+
+ b.Property("Username")
+ .IsRequired()
+ .HasColumnType("nvarchar(450)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Username")
+ .IsUnique();
+
+ b.ToTable("Users");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Comment", b =>
+ {
+ b.HasOne("AskFm.DAL.Models.Comment", "ParentComment")
+ .WithMany("Replies")
+ .HasForeignKey("ParentCommentId");
+
+ b.HasOne("AskFm.DAL.Models.Thread", "Thread")
+ .WithMany("Comments")
+ .HasForeignKey("ThreadId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("AskFm.DAL.Models.User", "User")
+ .WithMany("Comments")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.NoAction);
+
+ b.Navigation("ParentComment");
+
+ b.Navigation("Thread");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.CommentLike", b =>
+ {
+ b.HasOne("AskFm.DAL.Models.Comment", "Comment")
+ .WithMany("CommentLikes")
+ .HasForeignKey("CommentId")
+ .OnDelete(DeleteBehavior.NoAction)
+ .IsRequired();
+
+ b.HasOne("AskFm.DAL.Models.User", "User")
+ .WithMany("CommentLikes")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Comment");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Follow", b =>
+ {
+ b.HasOne("AskFm.DAL.Models.User", "Followed")
+ .WithMany("Followers")
+ .HasForeignKey("FollowedId")
+ .OnDelete(DeleteBehavior.NoAction)
+ .IsRequired();
+
+ b.HasOne("AskFm.DAL.Models.User", "Follower")
+ .WithMany("Following")
+ .HasForeignKey("FollowerId")
+ .OnDelete(DeleteBehavior.NoAction)
+ .IsRequired();
+
+ b.Navigation("Followed");
+
+ b.Navigation("Follower");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Notification", b =>
+ {
+ b.HasOne("AskFm.DAL.Models.User", "User")
+ .WithMany("Notifications")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.SavedThreads", b =>
+ {
+ b.HasOne("AskFm.DAL.Models.Thread", "Thread")
+ .WithMany("SavedThreads")
+ .HasForeignKey("ThreadId")
+ .OnDelete(DeleteBehavior.NoAction)
+ .IsRequired();
+
+ b.HasOne("AskFm.DAL.Models.User", "User")
+ .WithMany("SavedThreads")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.NoAction)
+ .IsRequired();
+
+ b.Navigation("Thread");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Thread", b =>
+ {
+ b.HasOne("AskFm.DAL.Models.User", "Asked")
+ .WithMany("ReceivedThreads")
+ .HasForeignKey("AskedId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("AskFm.DAL.Models.User", "Asker")
+ .WithMany("AskedThreads")
+ .HasForeignKey("AskerId");
+
+ b.Navigation("Asked");
+
+ b.Navigation("Asker");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.ThreadLike", b =>
+ {
+ b.HasOne("AskFm.DAL.Models.Thread", "Thread")
+ .WithMany("ThreadLikes")
+ .HasForeignKey("ThreadId")
+ .OnDelete(DeleteBehavior.NoAction)
+ .IsRequired();
+
+ b.HasOne("AskFm.DAL.Models.User", "User")
+ .WithMany("ThreadLikes")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Thread");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Comment", b =>
+ {
+ b.Navigation("CommentLikes");
+
+ b.Navigation("Replies");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Thread", b =>
+ {
+ b.Navigation("Comments");
+
+ b.Navigation("SavedThreads");
+
+ b.Navigation("ThreadLikes");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.User", b =>
+ {
+ b.Navigation("AskedThreads");
+
+ b.Navigation("CommentLikes");
+
+ b.Navigation("Comments");
+
+ b.Navigation("Followers");
+
+ b.Navigation("Following");
+
+ b.Navigation("Notifications");
+
+ b.Navigation("ReceivedThreads");
+
+ b.Navigation("SavedThreads");
+
+ b.Navigation("ThreadLikes");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/AskFm/AskFm.DAL/Migrations/20250728225552_apply_savedThread.cs b/AskFm/AskFm.DAL/Migrations/20250728225552_apply_savedThread.cs
new file mode 100644
index 0000000..844c7a2
--- /dev/null
+++ b/AskFm/AskFm.DAL/Migrations/20250728225552_apply_savedThread.cs
@@ -0,0 +1,22 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace AskFm.DAL.Migrations
+{
+ ///
+ public partial class apply_savedThread : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+
+ }
+ }
+}
diff --git a/AskFm/AskFm.DAL/Migrations/20250729175124_Typo_Column.Designer.cs b/AskFm/AskFm.DAL/Migrations/20250729175124_Typo_Column.Designer.cs
new file mode 100644
index 0000000..4949ab3
--- /dev/null
+++ b/AskFm/AskFm.DAL/Migrations/20250729175124_Typo_Column.Designer.cs
@@ -0,0 +1,436 @@
+//
+using System;
+using AskFm.DAL;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace AskFm.DAL.Migrations
+{
+ [DbContext(typeof(AppDbContext))]
+ [Migration("20250729175124_Typo_Column")]
+ partial class Typo_Column
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "9.0.0")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128);
+
+ SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
+
+ modelBuilder.Entity("AskFm.DAL.Models.Comment", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("Content")
+ .IsRequired()
+ .HasMaxLength(1000)
+ .HasColumnType("nvarchar(1000)");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime");
+
+ b.Property("LikeCount")
+ .HasColumnType("int");
+
+ b.Property("ParentCommentId")
+ .HasColumnType("int");
+
+ b.Property("ThreadId")
+ .HasColumnType("int");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ParentCommentId");
+
+ b.HasIndex("ThreadId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("Comments");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.CommentLike", b =>
+ {
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.Property("CommentId")
+ .HasColumnType("int");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime");
+
+ b.HasKey("UserId", "CommentId");
+
+ b.HasIndex("CommentId");
+
+ b.ToTable("CommentLikes");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Follow", b =>
+ {
+ b.Property("FollowerId")
+ .HasColumnType("int");
+
+ b.Property("FollowedId")
+ .HasColumnType("int");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("IsActive")
+ .HasColumnType("bit");
+
+ b.HasKey("FollowerId", "FollowedId");
+
+ b.HasIndex("FollowedId");
+
+ b.ToTable("Follows");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Notification", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime");
+
+ b.Property("ResourceId")
+ .HasColumnType("int");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.Property("isRead")
+ .HasColumnType("bit");
+
+ b.Property("jsonContent")
+ .IsRequired()
+ .HasColumnType("NVARCHAR");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("Notifications");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.SavedThreads", b =>
+ {
+ b.Property("ThreadId")
+ .HasColumnType("int");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.HasKey("ThreadId", "UserId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("SavedThreads");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Thread", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("AnswerContent")
+ .IsRequired()
+ .HasMaxLength(4000)
+ .HasColumnType("nvarchar(4000)");
+
+ b.Property("AskedId")
+ .HasColumnType("int");
+
+ b.Property("AskerId")
+ .HasColumnType("int");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime");
+
+ b.Property("QuestionContent")
+ .IsRequired()
+ .HasMaxLength(1000)
+ .HasColumnType("nvarchar(1000)");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("isAnonymous")
+ .HasColumnType("bit");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AskedId");
+
+ b.HasIndex("AskerId");
+
+ b.ToTable("Thread", (string)null);
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.ThreadLike", b =>
+ {
+ b.Property("ThreadId")
+ .HasColumnType("int");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime");
+
+ b.HasKey("ThreadId", "UserId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("ThreadLikes");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.User", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("AvatarPath")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Bio")
+ .IsRequired()
+ .HasMaxLength(500)
+ .HasColumnType("nvarchar(500)");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("Email")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("nvarchar(255)");
+
+ b.Property("FollowersCount")
+ .HasColumnType("int");
+
+ b.Property("FollowingCount")
+ .HasColumnType("int");
+
+ b.Property("LastSeen")
+ .HasColumnType("datetime2");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("nvarchar(50)");
+
+ b.Property("Password")
+ .IsRequired()
+ .HasMaxLength(225)
+ .HasColumnType("nvarchar(225)");
+
+ b.Property("Username")
+ .IsRequired()
+ .HasColumnType("nvarchar(450)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Username")
+ .IsUnique();
+
+ b.ToTable("Users");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Comment", b =>
+ {
+ b.HasOne("AskFm.DAL.Models.Comment", "ParentComment")
+ .WithMany("Replies")
+ .HasForeignKey("ParentCommentId");
+
+ b.HasOne("AskFm.DAL.Models.Thread", "Thread")
+ .WithMany("Comments")
+ .HasForeignKey("ThreadId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("AskFm.DAL.Models.User", "User")
+ .WithMany("Comments")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.NoAction);
+
+ b.Navigation("ParentComment");
+
+ b.Navigation("Thread");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.CommentLike", b =>
+ {
+ b.HasOne("AskFm.DAL.Models.Comment", "Comment")
+ .WithMany("CommentLikes")
+ .HasForeignKey("CommentId")
+ .OnDelete(DeleteBehavior.NoAction)
+ .IsRequired();
+
+ b.HasOne("AskFm.DAL.Models.User", "User")
+ .WithMany("CommentLikes")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Comment");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Follow", b =>
+ {
+ b.HasOne("AskFm.DAL.Models.User", "Followed")
+ .WithMany("Followers")
+ .HasForeignKey("FollowedId")
+ .OnDelete(DeleteBehavior.NoAction)
+ .IsRequired();
+
+ b.HasOne("AskFm.DAL.Models.User", "Follower")
+ .WithMany("Following")
+ .HasForeignKey("FollowerId")
+ .OnDelete(DeleteBehavior.NoAction)
+ .IsRequired();
+
+ b.Navigation("Followed");
+
+ b.Navigation("Follower");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Notification", b =>
+ {
+ b.HasOne("AskFm.DAL.Models.User", "User")
+ .WithMany("Notifications")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.SavedThreads", b =>
+ {
+ b.HasOne("AskFm.DAL.Models.Thread", "Thread")
+ .WithMany("SavedThreads")
+ .HasForeignKey("ThreadId")
+ .OnDelete(DeleteBehavior.NoAction)
+ .IsRequired();
+
+ b.HasOne("AskFm.DAL.Models.User", "User")
+ .WithMany("SavedThreads")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.NoAction)
+ .IsRequired();
+
+ b.Navigation("Thread");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Thread", b =>
+ {
+ b.HasOne("AskFm.DAL.Models.User", "Asked")
+ .WithMany("ReceivedThreads")
+ .HasForeignKey("AskedId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("AskFm.DAL.Models.User", "Asker")
+ .WithMany("AskedThreads")
+ .HasForeignKey("AskerId");
+
+ b.Navigation("Asked");
+
+ b.Navigation("Asker");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.ThreadLike", b =>
+ {
+ b.HasOne("AskFm.DAL.Models.Thread", "Thread")
+ .WithMany("ThreadLikes")
+ .HasForeignKey("ThreadId")
+ .OnDelete(DeleteBehavior.NoAction)
+ .IsRequired();
+
+ b.HasOne("AskFm.DAL.Models.User", "User")
+ .WithMany("ThreadLikes")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Thread");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Comment", b =>
+ {
+ b.Navigation("CommentLikes");
+
+ b.Navigation("Replies");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Thread", b =>
+ {
+ b.Navigation("Comments");
+
+ b.Navigation("SavedThreads");
+
+ b.Navigation("ThreadLikes");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.User", b =>
+ {
+ b.Navigation("AskedThreads");
+
+ b.Navigation("CommentLikes");
+
+ b.Navigation("Comments");
+
+ b.Navigation("Followers");
+
+ b.Navigation("Following");
+
+ b.Navigation("Notifications");
+
+ b.Navigation("ReceivedThreads");
+
+ b.Navigation("SavedThreads");
+
+ b.Navigation("ThreadLikes");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/AskFm/AskFm.DAL/Migrations/20250729175124_Typo_Column.cs b/AskFm/AskFm.DAL/Migrations/20250729175124_Typo_Column.cs
new file mode 100644
index 0000000..52ab62d
--- /dev/null
+++ b/AskFm/AskFm.DAL/Migrations/20250729175124_Typo_Column.cs
@@ -0,0 +1,28 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace AskFm.DAL.Migrations
+{
+ ///
+ public partial class Typo_Column : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.RenameColumn(
+ name: "FolloweingCount",
+ table: "Users",
+ newName: "FollowingCount");
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.RenameColumn(
+ name: "FollowingCount",
+ table: "Users",
+ newName: "FolloweingCount");
+ }
+ }
+}
diff --git a/AskFm/AskFm.DAL/Migrations/20250729180455_Test_SavedThread_Creation.Designer.cs b/AskFm/AskFm.DAL/Migrations/20250729180455_Test_SavedThread_Creation.Designer.cs
new file mode 100644
index 0000000..6113043
--- /dev/null
+++ b/AskFm/AskFm.DAL/Migrations/20250729180455_Test_SavedThread_Creation.Designer.cs
@@ -0,0 +1,436 @@
+//
+using System;
+using AskFm.DAL;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace AskFm.DAL.Migrations
+{
+ [DbContext(typeof(AppDbContext))]
+ [Migration("20250729180455_Test_SavedThread_Creation")]
+ partial class Test_SavedThread_Creation
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "9.0.0")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128);
+
+ SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
+
+ modelBuilder.Entity("AskFm.DAL.Models.Comment", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("Content")
+ .IsRequired()
+ .HasMaxLength(1000)
+ .HasColumnType("nvarchar(1000)");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime");
+
+ b.Property("LikeCount")
+ .HasColumnType("int");
+
+ b.Property("ParentCommentId")
+ .HasColumnType("int");
+
+ b.Property("ThreadId")
+ .HasColumnType("int");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ParentCommentId");
+
+ b.HasIndex("ThreadId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("Comments");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.CommentLike", b =>
+ {
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.Property("CommentId")
+ .HasColumnType("int");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime");
+
+ b.HasKey("UserId", "CommentId");
+
+ b.HasIndex("CommentId");
+
+ b.ToTable("CommentLikes");
+ });
+
+ modelBuilder.Entity("AskFm.DAL.Models.Follow", b =>
+ {
+ b.Property("FollowerId")
+ .HasColumnType("int");
+
+ b.Property("FollowedId")
+ .HasColumnType("int");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2");
+
+ b.Property