🐛 Post reaction fixes

This commit is contained in:
LittleSheep 2025-05-05 13:12:20 +08:00
parent 2206676214
commit 02aee07116
6 changed files with 2512 additions and 24 deletions

View File

@ -55,6 +55,7 @@ public class AppDatabase(
public DbSet<Chat.ChatMember> ChatMembers { get; set; } public DbSet<Chat.ChatMember> ChatMembers { get; set; }
public DbSet<Chat.Message> ChatMessages { get; set; } public DbSet<Chat.Message> ChatMessages { get; set; }
public DbSet<Chat.MessageStatus> ChatStatuses { get; set; } public DbSet<Chat.MessageStatus> ChatStatuses { get; set; }
public DbSet<Chat.MessageReaction> ChatReactions { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{ {
@ -80,7 +81,7 @@ public class AppDatabase(
Nodes = Nodes =
{ {
PermissionService.NewPermissionNode("group:default", "global", "posts.create", true), PermissionService.NewPermissionNode("group:default", "global", "posts.create", true),
PermissionService.NewPermissionNode("group:default", "global", "posts.reactions.create", true), PermissionService.NewPermissionNode("group:default", "global", "posts.react", true),
PermissionService.NewPermissionNode("group:default", "global", "publishers.create", true), PermissionService.NewPermissionNode("group:default", "global", "publishers.create", true),
PermissionService.NewPermissionNode("group:default", "global", "files.create", true), PermissionService.NewPermissionNode("group:default", "global", "files.create", true),
PermissionService.NewPermissionNode("group:default", "global", "chat.create", true) PermissionService.NewPermissionNode("group:default", "global", "chat.create", true)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,112 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace DysonNetwork.Sphere.Migrations
{
/// <inheritdoc />
public partial class NoIdeaHowToNameThis : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "fk_message_reaction_chat_members_sender_id",
table: "message_reaction");
migrationBuilder.DropForeignKey(
name: "fk_message_reaction_chat_messages_message_id",
table: "message_reaction");
migrationBuilder.DropPrimaryKey(
name: "pk_message_reaction",
table: "message_reaction");
migrationBuilder.RenameTable(
name: "message_reaction",
newName: "chat_reactions");
migrationBuilder.RenameIndex(
name: "ix_message_reaction_sender_id",
table: "chat_reactions",
newName: "ix_chat_reactions_sender_id");
migrationBuilder.RenameIndex(
name: "ix_message_reaction_message_id",
table: "chat_reactions",
newName: "ix_chat_reactions_message_id");
migrationBuilder.AddPrimaryKey(
name: "pk_chat_reactions",
table: "chat_reactions",
column: "id");
migrationBuilder.AddForeignKey(
name: "fk_chat_reactions_chat_members_sender_id",
table: "chat_reactions",
column: "sender_id",
principalTable: "chat_members",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "fk_chat_reactions_chat_messages_message_id",
table: "chat_reactions",
column: "message_id",
principalTable: "chat_messages",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "fk_chat_reactions_chat_members_sender_id",
table: "chat_reactions");
migrationBuilder.DropForeignKey(
name: "fk_chat_reactions_chat_messages_message_id",
table: "chat_reactions");
migrationBuilder.DropPrimaryKey(
name: "pk_chat_reactions",
table: "chat_reactions");
migrationBuilder.RenameTable(
name: "chat_reactions",
newName: "message_reaction");
migrationBuilder.RenameIndex(
name: "ix_chat_reactions_sender_id",
table: "message_reaction",
newName: "ix_message_reaction_sender_id");
migrationBuilder.RenameIndex(
name: "ix_chat_reactions_message_id",
table: "message_reaction",
newName: "ix_message_reaction_message_id");
migrationBuilder.AddPrimaryKey(
name: "pk_message_reaction",
table: "message_reaction",
column: "id");
migrationBuilder.AddForeignKey(
name: "fk_message_reaction_chat_members_sender_id",
table: "message_reaction",
column: "sender_id",
principalTable: "chat_members",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "fk_message_reaction_chat_messages_message_id",
table: "message_reaction",
column: "message_id",
principalTable: "chat_messages",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
}
}
}

View File

@ -888,15 +888,15 @@ namespace DysonNetwork.Sphere.Migrations
.HasColumnName("updated_at"); .HasColumnName("updated_at");
b.HasKey("Id") b.HasKey("Id")
.HasName("pk_message_reaction"); .HasName("pk_chat_reactions");
b.HasIndex("MessageId") b.HasIndex("MessageId")
.HasDatabaseName("ix_message_reaction_message_id"); .HasDatabaseName("ix_chat_reactions_message_id");
b.HasIndex("SenderId") b.HasIndex("SenderId")
.HasDatabaseName("ix_message_reaction_sender_id"); .HasDatabaseName("ix_chat_reactions_sender_id");
b.ToTable("message_reaction", (string)null); b.ToTable("chat_reactions", (string)null);
}); });
modelBuilder.Entity("DysonNetwork.Sphere.Chat.MessageStatus", b => modelBuilder.Entity("DysonNetwork.Sphere.Chat.MessageStatus", b =>
@ -2003,14 +2003,14 @@ namespace DysonNetwork.Sphere.Migrations
.HasForeignKey("MessageId") .HasForeignKey("MessageId")
.OnDelete(DeleteBehavior.Cascade) .OnDelete(DeleteBehavior.Cascade)
.IsRequired() .IsRequired()
.HasConstraintName("fk_message_reaction_chat_messages_message_id"); .HasConstraintName("fk_chat_reactions_chat_messages_message_id");
b.HasOne("DysonNetwork.Sphere.Chat.ChatMember", "Sender") b.HasOne("DysonNetwork.Sphere.Chat.ChatMember", "Sender")
.WithMany() .WithMany()
.HasForeignKey("SenderId") .HasForeignKey("SenderId")
.OnDelete(DeleteBehavior.Cascade) .OnDelete(DeleteBehavior.Cascade)
.IsRequired() .IsRequired()
.HasConstraintName("fk_message_reaction_chat_members_sender_id"); .HasConstraintName("fk_chat_reactions_chat_members_sender_id");
b.Navigation("Message"); b.Navigation("Message");

View File

@ -216,8 +216,8 @@ public class PostController(AppDatabase db, PostService ps, RelationshipService
[HttpPost("{id:long}/reactions")] [HttpPost("{id:long}/reactions")]
[Authorize] [Authorize]
[RequiredPermission("global", "posts.reactions.create")] [RequiredPermission("global", "posts.react")]
public async Task<ActionResult<PostReaction>> CreatePostReaction(long id, [FromBody] PostReactionRequest request) public async Task<ActionResult<PostReaction>> ReactPost(long id, [FromBody] PostReactionRequest request)
{ {
HttpContext.Items.TryGetValue("CurrentUser", out var currentUserValue); HttpContext.Items.TryGetValue("CurrentUser", out var currentUserValue);
if (currentUserValue is not Account.Account currentUser) return Unauthorized(); if (currentUserValue is not Account.Account currentUser) return Unauthorized();
@ -241,9 +241,9 @@ public class PostController(AppDatabase db, PostService ps, RelationshipService
PostId = post.Id, PostId = post.Id,
AccountId = currentUser.Id AccountId = currentUser.Id
}; };
await ps.ModifyPostVotes(post, reaction, isExistingReaction); var isRemoving = await ps.ModifyPostVotes(post, reaction, isExistingReaction);
if (isExistingReaction) return NoContent(); if (isRemoving) return NoContent();
return Ok(reaction); return Ok(reaction);
} }

View File

@ -174,27 +174,39 @@ public class PostService(AppDatabase db, FileService fs, ActivityService act)
/// <param name="post">Post that modifying</param> /// <param name="post">Post that modifying</param>
/// <param name="reaction">The new / target reaction adding / removing</param> /// <param name="reaction">The new / target reaction adding / removing</param>
/// <param name="isRemoving">Indicate this operation is adding / removing</param> /// <param name="isRemoving">Indicate this operation is adding / removing</param>
public async Task ModifyPostVotes(Post post, PostReaction reaction, bool isRemoving) public async Task<bool> ModifyPostVotes(Post post, PostReaction reaction, bool isRemoving)
{ {
var isExistingReaction = await db.Set<PostReaction>() var isExistingReaction = await db.Set<PostReaction>()
.AnyAsync(r => r.PostId == post.Id && r.AccountId == reaction.AccountId); .AnyAsync(r => r.PostId == post.Id && r.AccountId == reaction.AccountId);
if (isExistingReaction) return;
if (!isRemoving) if (isRemoving)
await db.PostReactions
.Where(r => r.PostId == post.Id && r.Symbol == reaction.Symbol && r.AccountId == reaction.AccountId)
.ExecuteDeleteAsync();
else
db.PostReactions.Add(reaction);
if (isExistingReaction)
{ {
db.Add(reaction); if (!isRemoving)
switch (reaction.Attitude) await db.SaveChangesAsync();
{ return isRemoving;
case PostReactionAttitude.Positive: }
post.Upvotes++;
break; switch (reaction.Attitude)
case PostReactionAttitude.Negative: {
post.Downvotes++; case PostReactionAttitude.Positive:
break; if (isRemoving) post.Upvotes--;
} else post.Upvotes++;
break;
case PostReactionAttitude.Negative:
if (isRemoving) post.Downvotes--;
else post.Downvotes++;
break;
} }
await db.SaveChangesAsync(); await db.SaveChangesAsync();
return isRemoving;
} }
public async Task<Dictionary<string, int>> GetPostReactionMap(long postId) public async Task<Dictionary<string, int>> GetPostReactionMap(long postId)