♻️ Update handling logic of activitypub

This commit is contained in:
2025-12-31 22:31:50 +08:00
parent 91764593c7
commit 4815d31b31
6 changed files with 2476 additions and 60 deletions

View File

@@ -107,7 +107,6 @@ public class SnPost : ModelBase, IIdentifiedResource, ITimelineEvent
public List<ContentMention>? Mentions { get; set; } public List<ContentMention>? Mentions { get; set; }
public int BoostCount { get; set; } public int BoostCount { get; set; }
public int LikeCount { get; set; }
public Guid? ActorId { get; set; } public Guid? ActorId { get; set; }
public SnFediverseActor? Actor { get; set; } public SnFediverseActor? Actor { get; set; }
@@ -232,7 +231,6 @@ public class SnPost : ModelBase, IIdentifiedResource, ITimelineEvent
proto.RepliesCount = RepliesCount; proto.RepliesCount = RepliesCount;
proto.BoostCount = BoostCount; proto.BoostCount = BoostCount;
proto.LikeCount = LikeCount;
if (ActorId.HasValue) if (ActorId.HasValue)
proto.ActorId = ActorId.Value.ToString(); proto.ActorId = ActorId.Value.ToString();
@@ -349,7 +347,6 @@ public class SnPost : ModelBase, IIdentifiedResource, ITimelineEvent
post.RepliesCount = proto.RepliesCount; post.RepliesCount = proto.RepliesCount;
post.BoostCount = proto.BoostCount; post.BoostCount = proto.BoostCount;
post.LikeCount = proto.LikeCount;
if (!string.IsNullOrEmpty(proto.ActorId)) if (!string.IsNullOrEmpty(proto.ActorId))
post.ActorId = Guid.Parse(proto.ActorId); post.ActorId = Guid.Parse(proto.ActorId);

View File

@@ -143,7 +143,6 @@ message Post {
optional PostContentType content_type = 44; optional PostContentType content_type = 44;
repeated ContentMention mentions = 48; repeated ContentMention mentions = 48;
int32 boost_count = 50; int32 boost_count = 50;
int32 like_count = 51;
optional string actor_id = 53; optional string actor_id = 53;
repeated PostAward awards = 33; repeated PostAward awards = 33;

View File

@@ -16,9 +16,32 @@ public class ActivityPubActivityHandler(
ActivityPubSignatureService signatureService, ActivityPubSignatureService signatureService,
ActivityPubDeliveryService deliveryService, ActivityPubDeliveryService deliveryService,
ActivityPubDiscoveryService discoveryService, ActivityPubDiscoveryService discoveryService,
ILogger<ActivityPubActivityHandler> logger ILogger<ActivityPubActivityHandler> logger,
IConfiguration configuration
) )
{ {
private string Domain => configuration["ActivityPub:Domain"] ?? "localhost";
private async Task<SnPost?> GetPostByUriAsync(string objectUri)
{
var uri = new Uri(objectUri);
var domain = uri.Host;
// Remote post
if (domain != Domain) return await db.Posts.FirstOrDefaultAsync(c => c.FediverseUri == objectUri);
// Local post, extract ID from path like /posts/{guid}
var path = uri.AbsolutePath.Trim('/');
var segments = path.Split('/');
if (segments is not [.., "posts", _]) return null;
var idStr = segments[^1];
if (Guid.TryParse(idStr, out var id))
{
return await db.Posts.FirstOrDefaultAsync(p => p.Id == id);
}
return null;
}
public async Task<bool> HandleIncomingActivityAsync( public async Task<bool> HandleIncomingActivityAsync(
HttpContext context, HttpContext context,
string username, string username,
@@ -237,8 +260,8 @@ public class ActivityPubActivityHandler(
return objectType switch return objectType switch
{ {
"Follow" => await UndoFollowAsync(actorUri, objectDict.GetValueOrDefault("object")?.ToString()), "Follow" => await UndoFollowAsync(actorUri, objectDict.GetValueOrDefault("object")?.ToString()),
"Like" => await UndoLikeAsync(actorUri, objectDict.GetValueOrDefault("id")?.ToString()), "Like" => await UndoLikeAsync(actorUri, objectDict.GetValueOrDefault("object")?.ToString()),
"Announce" => await UndoAnnounceAsync(actorUri, objectDict.GetValueOrDefault("id")?.ToString()), "Announce" => await UndoAnnounceAsync(actorUri, objectDict.GetValueOrDefault("object")?.ToString()),
_ => false _ => false
}; };
} }
@@ -287,8 +310,6 @@ public class ActivityPubActivityHandler(
Attachments = ParseAttachments(objectDict.GetValueOrDefault("attachment")) ?? [], Attachments = ParseAttachments(objectDict.GetValueOrDefault("attachment")) ?? [],
Type = objectType == "Article" ? PostType.Article : PostType.Moment, Type = objectType == "Article" ? PostType.Article : PostType.Moment,
Visibility = PostVisibility.Public, Visibility = PostVisibility.Public,
CreatedAt = SystemClock.Instance.GetCurrentInstant(),
UpdatedAt = SystemClock.Instance.GetCurrentInstant(),
Metadata = BuildMetadataFromActivity(objectDict) Metadata = BuildMetadataFromActivity(objectDict)
}; };
@@ -304,11 +325,10 @@ public class ActivityPubActivityHandler(
var objectUri = activity.GetValueOrDefault("object")?.ToString(); var objectUri = activity.GetValueOrDefault("object")?.ToString();
if (string.IsNullOrEmpty(objectUri)) if (string.IsNullOrEmpty(objectUri))
return false; return false;
var actor = await GetOrCreateActorAsync(actorUri); var actor = await GetOrCreateActorAsync(actorUri);
var content = await db.Posts var content = await GetPostByUriAsync(objectUri);
.FirstOrDefaultAsync(c => c.FediverseUri == objectUri);
if (content == null) if (content == null)
{ {
logger.LogWarning("Content not found for like: {Uri}", objectUri); logger.LogWarning("Content not found for like: {Uri}", objectUri);
@@ -319,7 +339,7 @@ public class ActivityPubActivityHandler(
.FirstOrDefaultAsync(r => .FirstOrDefaultAsync(r =>
r.ActorId == actor.Id && r.ActorId == actor.Id &&
r.PostId == content.Id && r.PostId == content.Id &&
r.Symbol == "❤️"); r.Symbol == "thumb_up");
if (existingReaction != null) if (existingReaction != null)
{ {
@@ -330,7 +350,7 @@ public class ActivityPubActivityHandler(
var reaction = new SnPostReaction var reaction = new SnPostReaction
{ {
FediverseUri = activity.GetValueOrDefault("id")?.ToString() ?? Guid.NewGuid().ToString(), FediverseUri = activity.GetValueOrDefault("id")?.ToString() ?? Guid.NewGuid().ToString(),
Symbol = "❤️", Symbol = "thumb_up",
Attitude = PostReactionAttitude.Positive, Attitude = PostReactionAttitude.Positive,
IsLocal = false, IsLocal = false,
PostId = content.Id, PostId = content.Id,
@@ -341,7 +361,7 @@ public class ActivityPubActivityHandler(
}; };
db.PostReactions.Add(reaction); db.PostReactions.Add(reaction);
content.LikeCount++; content.Upvotes++;
await db.SaveChangesAsync(); await db.SaveChangesAsync();
@@ -354,17 +374,16 @@ public class ActivityPubActivityHandler(
var objectUri = activity.GetValueOrDefault("object")?.ToString(); var objectUri = activity.GetValueOrDefault("object")?.ToString();
if (string.IsNullOrEmpty(objectUri)) if (string.IsNullOrEmpty(objectUri))
return false; return false;
var actor = await GetOrCreateActorAsync(actorUri); var actor = await GetOrCreateActorAsync(actorUri);
var content = await db.Posts var content = await GetPostByUriAsync(objectUri);
.FirstOrDefaultAsync(c => c.FediverseUri == objectUri);
if (content != null) if (content != null)
{ {
content.BoostCount++; content.BoostCount++;
await db.SaveChangesAsync(); await db.SaveChangesAsync();
} }
logger.LogInformation("Handled announce from {Actor}", actorUri); logger.LogInformation("Handled announce from {Actor}", actorUri);
return true; return true;
} }
@@ -374,17 +393,14 @@ public class ActivityPubActivityHandler(
var objectUri = activity.GetValueOrDefault("object")?.ToString(); var objectUri = activity.GetValueOrDefault("object")?.ToString();
if (string.IsNullOrEmpty(objectUri)) if (string.IsNullOrEmpty(objectUri))
return false; return false;
var content = await db.Posts var content = await GetPostByUriAsync(objectUri);
.FirstOrDefaultAsync(c => c.FediverseUri == objectUri);
if (content == null) return true;
if (content != null) content.DeletedAt = SystemClock.Instance.GetCurrentInstant();
{ await db.SaveChangesAsync();
content.DeletedAt = SystemClock.Instance.GetCurrentInstant(); logger.LogInformation("Deleted federated content: {Uri}", objectUri);
await db.SaveChangesAsync();
logger.LogInformation("Deleted federated content: {Uri}", objectUri);
}
return true; return true;
} }
@@ -393,10 +409,9 @@ public class ActivityPubActivityHandler(
var objectUri = activity.GetValueOrDefault("object")?.ToString(); var objectUri = activity.GetValueOrDefault("object")?.ToString();
if (string.IsNullOrEmpty(objectUri)) if (string.IsNullOrEmpty(objectUri))
return false; return false;
var content = await db.Posts var content = await GetPostByUriAsync(objectUri);
.FirstOrDefaultAsync(c => c.FediverseUri == objectUri);
if (content != null) if (content != null)
{ {
content.EditedAt = SystemClock.Instance.GetCurrentInstant(); content.EditedAt = SystemClock.Instance.GetCurrentInstant();
@@ -404,7 +419,7 @@ public class ActivityPubActivityHandler(
await db.SaveChangesAsync(); await db.SaveChangesAsync();
logger.LogInformation("Updated federated content: {Uri}", objectUri); logger.LogInformation("Updated federated content: {Uri}", objectUri);
} }
return true; return true;
} }
@@ -430,39 +445,46 @@ public class ActivityPubActivityHandler(
return true; return true;
} }
private async Task<bool> UndoLikeAsync(string actorUri, string? activityId) private async Task<bool> UndoLikeAsync(string actorUri, string? objectUri)
{ {
if (string.IsNullOrEmpty(objectUri))
return false;
var actor = await GetOrCreateActorAsync(actorUri); var actor = await GetOrCreateActorAsync(actorUri);
var content = await GetPostByUriAsync(objectUri);
var reactions = await db.PostReactions
.Where(r => r.ActorId == actor.Id && r.Symbol == "❤️") if (content == null)
.ToListAsync(); return false;
foreach (var reaction in reactions) var reaction = await db.PostReactions
.FirstOrDefaultAsync(r =>
r.ActorId == actor.Id &&
r.PostId == content.Id &&
r.Symbol == "thumb_up");
if (reaction != null)
{ {
var content = await db.Posts.FindAsync(reaction.PostId);
if (content != null)
{
content.LikeCount--;
}
db.PostReactions.Remove(reaction); db.PostReactions.Remove(reaction);
content.Upvotes--;
await db.SaveChangesAsync();
} }
await db.SaveChangesAsync();
return true; return true;
} }
private async Task<bool> UndoAnnounceAsync(string actorUri, string? activityId) private async Task<bool> UndoAnnounceAsync(string actorUri, string? objectUri)
{ {
var content = await db.Posts if (string.IsNullOrEmpty(objectUri))
.FirstOrDefaultAsync(c => c.FediverseUri == activityId); return false;
var content = await GetPostByUriAsync(objectUri);
if (content != null) if (content != null)
{ {
content.BoostCount = Math.Max(0, content.BoostCount - 1); content.BoostCount = Math.Max(0, content.BoostCount - 1);
await db.SaveChangesAsync(); await db.SaveChangesAsync();
} }
return true; return true;
} }

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,29 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace DysonNetwork.Sphere.Migrations
{
/// <inheritdoc />
public partial class RemoveSeprateLikeCountOnPost : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "like_count",
table: "posts");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "like_count",
table: "posts",
type: "integer",
nullable: false,
defaultValue: 0);
}
}
}

View File

@@ -840,10 +840,6 @@ namespace DysonNetwork.Sphere.Migrations
.HasColumnType("character varying(2048)") .HasColumnType("character varying(2048)")
.HasColumnName("language"); .HasColumnName("language");
b.Property<int>("LikeCount")
.HasColumnType("integer")
.HasColumnName("like_count");
b.Property<List<ContentMention>>("Mentions") b.Property<List<ContentMention>>("Mentions")
.HasColumnType("jsonb") .HasColumnType("jsonb")
.HasColumnName("mentions"); .HasColumnName("mentions");