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

View File

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

View File

@@ -16,9 +16,32 @@ public class ActivityPubActivityHandler(
ActivityPubSignatureService signatureService,
ActivityPubDeliveryService deliveryService,
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(
HttpContext context,
string username,
@@ -237,8 +260,8 @@ public class ActivityPubActivityHandler(
return objectType switch
{
"Follow" => await UndoFollowAsync(actorUri, objectDict.GetValueOrDefault("object")?.ToString()),
"Like" => await UndoLikeAsync(actorUri, objectDict.GetValueOrDefault("id")?.ToString()),
"Announce" => await UndoAnnounceAsync(actorUri, objectDict.GetValueOrDefault("id")?.ToString()),
"Like" => await UndoLikeAsync(actorUri, objectDict.GetValueOrDefault("object")?.ToString()),
"Announce" => await UndoAnnounceAsync(actorUri, objectDict.GetValueOrDefault("object")?.ToString()),
_ => false
};
}
@@ -287,8 +310,6 @@ public class ActivityPubActivityHandler(
Attachments = ParseAttachments(objectDict.GetValueOrDefault("attachment")) ?? [],
Type = objectType == "Article" ? PostType.Article : PostType.Moment,
Visibility = PostVisibility.Public,
CreatedAt = SystemClock.Instance.GetCurrentInstant(),
UpdatedAt = SystemClock.Instance.GetCurrentInstant(),
Metadata = BuildMetadataFromActivity(objectDict)
};
@@ -304,11 +325,10 @@ public class ActivityPubActivityHandler(
var objectUri = activity.GetValueOrDefault("object")?.ToString();
if (string.IsNullOrEmpty(objectUri))
return false;
var actor = await GetOrCreateActorAsync(actorUri);
var content = await db.Posts
.FirstOrDefaultAsync(c => c.FediverseUri == objectUri);
var content = await GetPostByUriAsync(objectUri);
if (content == null)
{
logger.LogWarning("Content not found for like: {Uri}", objectUri);
@@ -319,7 +339,7 @@ public class ActivityPubActivityHandler(
.FirstOrDefaultAsync(r =>
r.ActorId == actor.Id &&
r.PostId == content.Id &&
r.Symbol == "❤️");
r.Symbol == "thumb_up");
if (existingReaction != null)
{
@@ -330,7 +350,7 @@ public class ActivityPubActivityHandler(
var reaction = new SnPostReaction
{
FediverseUri = activity.GetValueOrDefault("id")?.ToString() ?? Guid.NewGuid().ToString(),
Symbol = "❤️",
Symbol = "thumb_up",
Attitude = PostReactionAttitude.Positive,
IsLocal = false,
PostId = content.Id,
@@ -341,7 +361,7 @@ public class ActivityPubActivityHandler(
};
db.PostReactions.Add(reaction);
content.LikeCount++;
content.Upvotes++;
await db.SaveChangesAsync();
@@ -354,17 +374,16 @@ public class ActivityPubActivityHandler(
var objectUri = activity.GetValueOrDefault("object")?.ToString();
if (string.IsNullOrEmpty(objectUri))
return false;
var actor = await GetOrCreateActorAsync(actorUri);
var content = await db.Posts
.FirstOrDefaultAsync(c => c.FediverseUri == objectUri);
var content = await GetPostByUriAsync(objectUri);
if (content != null)
{
content.BoostCount++;
await db.SaveChangesAsync();
}
logger.LogInformation("Handled announce from {Actor}", actorUri);
return true;
}
@@ -374,17 +393,14 @@ public class ActivityPubActivityHandler(
var objectUri = activity.GetValueOrDefault("object")?.ToString();
if (string.IsNullOrEmpty(objectUri))
return false;
var content = await db.Posts
.FirstOrDefaultAsync(c => c.FediverseUri == objectUri);
if (content != null)
{
content.DeletedAt = SystemClock.Instance.GetCurrentInstant();
await db.SaveChangesAsync();
logger.LogInformation("Deleted federated content: {Uri}", objectUri);
}
var content = await GetPostByUriAsync(objectUri);
if (content == null) return true;
content.DeletedAt = SystemClock.Instance.GetCurrentInstant();
await db.SaveChangesAsync();
logger.LogInformation("Deleted federated content: {Uri}", objectUri);
return true;
}
@@ -393,10 +409,9 @@ public class ActivityPubActivityHandler(
var objectUri = activity.GetValueOrDefault("object")?.ToString();
if (string.IsNullOrEmpty(objectUri))
return false;
var content = await db.Posts
.FirstOrDefaultAsync(c => c.FediverseUri == objectUri);
var content = await GetPostByUriAsync(objectUri);
if (content != null)
{
content.EditedAt = SystemClock.Instance.GetCurrentInstant();
@@ -404,7 +419,7 @@ public class ActivityPubActivityHandler(
await db.SaveChangesAsync();
logger.LogInformation("Updated federated content: {Uri}", objectUri);
}
return true;
}
@@ -430,39 +445,46 @@ public class ActivityPubActivityHandler(
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 reactions = await db.PostReactions
.Where(r => r.ActorId == actor.Id && r.Symbol == "❤️")
.ToListAsync();
foreach (var reaction in reactions)
var content = await GetPostByUriAsync(objectUri);
if (content == null)
return false;
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);
content.Upvotes--;
await db.SaveChangesAsync();
}
await db.SaveChangesAsync();
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
.FirstOrDefaultAsync(c => c.FediverseUri == activityId);
if (string.IsNullOrEmpty(objectUri))
return false;
var content = await GetPostByUriAsync(objectUri);
if (content != null)
{
content.BoostCount = Math.Max(0, content.BoostCount - 1);
await db.SaveChangesAsync();
}
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)")
.HasColumnName("language");
b.Property<int>("LikeCount")
.HasColumnType("integer")
.HasColumnName("like_count");
b.Property<List<ContentMention>>("Mentions")
.HasColumnType("jsonb")
.HasColumnName("mentions");