[backend/federation] Make sure new follow & unfollow activities have a consistent identifier (ISH-367)
This commit is contained in:
parent
1f29ad99c7
commit
fc7a1fe95c
6 changed files with 85 additions and 19 deletions
|
@ -0,0 +1,42 @@
|
|||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Iceshrimp.Backend.Core.Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
[DbContext(typeof(DatabaseContext))]
|
||||
[Migration("20240617151122_AddFollowRelationshipIdColumns")]
|
||||
public partial class AddFollowRelationshipIdColumns : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<Guid>(
|
||||
name: "relationshipId",
|
||||
table: "following",
|
||||
type: "uuid",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<Guid>(
|
||||
name: "relationshipId",
|
||||
table: "follow_request",
|
||||
type: "uuid",
|
||||
nullable: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "relationshipId",
|
||||
table: "following");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "relationshipId",
|
||||
table: "follow_request");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1158,6 +1158,10 @@ namespace Iceshrimp.Backend.Core.Database.Migrations
|
|||
.HasColumnName("followerSharedInbox")
|
||||
.HasComment("[Denormalized]");
|
||||
|
||||
b.Property<Guid?>("RelationshipId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("relationshipId");
|
||||
|
||||
b.Property<string>("RequestId")
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)")
|
||||
|
@ -1238,6 +1242,10 @@ namespace Iceshrimp.Backend.Core.Database.Migrations
|
|||
.HasColumnName("followerSharedInbox")
|
||||
.HasComment("[Denormalized]");
|
||||
|
||||
b.Property<Guid?>("RelationshipId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("relationshipId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CreatedAt");
|
||||
|
|
|
@ -36,6 +36,9 @@ public class FollowRequest : IEntity
|
|||
[Column("requestId")]
|
||||
[StringLength(128)]
|
||||
public string? RequestId { get; set; }
|
||||
|
||||
[Column("relationshipId")]
|
||||
public Guid? RelationshipId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [Denormalized]
|
||||
|
|
|
@ -79,6 +79,9 @@ public class Following
|
|||
[Column("followeeSharedInbox")]
|
||||
[StringLength(512)]
|
||||
public string? FolloweeSharedInbox { get; set; }
|
||||
|
||||
[Column("relationshipId")]
|
||||
public Guid? RelationshipId { get; set; }
|
||||
|
||||
[ForeignKey(nameof(FolloweeId))]
|
||||
[InverseProperty(nameof(User.IncomingFollowRelationships))]
|
||||
|
|
|
@ -109,7 +109,7 @@ public class ActivityRenderer(
|
|||
return res;
|
||||
}
|
||||
|
||||
public ASFollow RenderFollow(User follower, User followee)
|
||||
public ASFollow RenderFollow(User follower, User followee, Guid? relationshipId)
|
||||
{
|
||||
if (follower.Host == null && followee.Host == null)
|
||||
throw GracefulException.BadRequest("Refusing to render follow activity between two remote users");
|
||||
|
@ -118,10 +118,10 @@ public class ActivityRenderer(
|
|||
|
||||
return RenderFollow(userRenderer.RenderLite(follower),
|
||||
userRenderer.RenderLite(followee),
|
||||
RenderFollowId(follower, followee));
|
||||
RenderFollowId(follower, followee, relationshipId));
|
||||
}
|
||||
|
||||
public ASActivity RenderUnfollow(User follower, User followee)
|
||||
public ASActivity RenderUnfollow(User follower, User followee, Guid? relationshipId)
|
||||
{
|
||||
if (follower.Host == null && followee.Host == null)
|
||||
throw GracefulException.BadRequest("Refusing to render unfollow activity between two remote users");
|
||||
|
@ -132,13 +132,13 @@ public class ActivityRenderer(
|
|||
{
|
||||
var actor = userRenderer.RenderLite(follower);
|
||||
var obj = userRenderer.RenderLite(followee);
|
||||
return RenderUndo(actor, RenderFollow(actor, obj, RenderFollowId(follower, followee)));
|
||||
return RenderUndo(actor, RenderFollow(actor, obj, RenderFollowId(follower, followee, relationshipId)));
|
||||
}
|
||||
else
|
||||
{
|
||||
var actor = userRenderer.RenderLite(followee);
|
||||
var obj = userRenderer.RenderLite(follower);
|
||||
return RenderReject(actor, RenderFollow(actor, obj, RenderFollowId(follower, followee)));
|
||||
return RenderReject(actor, RenderFollow(actor, obj, RenderFollowId(follower, followee, relationshipId)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -178,8 +178,8 @@ public class ActivityRenderer(
|
|||
};
|
||||
|
||||
[SuppressMessage("ReSharper", "SuggestBaseTypeForParameter", Justification = "This only makes sense for users")]
|
||||
private string RenderFollowId(User follower, User followee) =>
|
||||
$"https://{config.Value.WebDomain}/follows/{follower.Id}/{followee.Id}/{Guid.NewGuid().ToStringLower()}";
|
||||
private string RenderFollowId(User follower, User followee, Guid? relationshipId) =>
|
||||
$"https://{config.Value.WebDomain}/follows/{follower.Id}/{followee.Id}/{(relationshipId ?? Guid.NewGuid()).ToStringLower()}";
|
||||
|
||||
public static ASAnnounce RenderAnnounce(
|
||||
ASNote note, ASActor actor, List<ASObjectBase> to, List<ASObjectBase> cc, string uri
|
||||
|
|
|
@ -561,7 +561,8 @@ public class UserService(
|
|||
FollowerInbox = request.FollowerInbox,
|
||||
FolloweeInbox = request.FolloweeInbox,
|
||||
FollowerSharedInbox = request.FollowerSharedInbox,
|
||||
FolloweeSharedInbox = request.FolloweeSharedInbox
|
||||
FolloweeSharedInbox = request.FolloweeSharedInbox,
|
||||
RelationshipId = request.RelationshipId
|
||||
};
|
||||
|
||||
await db.Users.Where(p => p.Id == request.Follower.Id)
|
||||
|
@ -645,13 +646,16 @@ public class UserService(
|
|||
if (follower.Host != null && followee.Host != null)
|
||||
throw GracefulException.UnprocessableEntity("Cannot process follow between two remote users");
|
||||
|
||||
if (followee.Host != null)
|
||||
Guid? relationshipId = null;
|
||||
|
||||
if (followee.IsRemoteUser)
|
||||
{
|
||||
var activity = activityRenderer.RenderFollow(follower, followee);
|
||||
relationshipId = Guid.NewGuid();
|
||||
var activity = activityRenderer.RenderFollow(follower, followee, relationshipId);
|
||||
await deliverSvc.DeliverToAsync(activity, follower, followee);
|
||||
}
|
||||
|
||||
if (follower.Host != null)
|
||||
if (follower.IsRemoteUser)
|
||||
{
|
||||
if (requestId == null)
|
||||
throw GracefulException.UnprocessableEntity("Cannot process remote follow without requestId");
|
||||
|
@ -688,7 +692,8 @@ public class UserService(
|
|||
FolloweeInbox = followee.Inbox,
|
||||
FollowerInbox = follower.Inbox,
|
||||
FolloweeSharedInbox = followee.SharedInbox,
|
||||
FollowerSharedInbox = follower.SharedInbox
|
||||
FollowerSharedInbox = follower.SharedInbox,
|
||||
RelationshipId = relationshipId
|
||||
};
|
||||
|
||||
await db.AddAsync(request);
|
||||
|
@ -764,13 +769,18 @@ public class UserService(
|
|||
/// </remarks>
|
||||
public async Task UnfollowUserAsync(User user, User followee)
|
||||
{
|
||||
if ((followee.PrecomputedIsFollowedBy ?? false) || (followee.PrecomputedIsRequestedBy ?? false))
|
||||
if (((followee.PrecomputedIsFollowedBy ?? false) || (followee.PrecomputedIsRequestedBy ?? false)) &&
|
||||
followee.IsRemoteUser)
|
||||
{
|
||||
if (followee.Host != null)
|
||||
{
|
||||
var activity = activityRenderer.RenderUnfollow(user, followee);
|
||||
await deliverSvc.DeliverToAsync(activity, user, followee);
|
||||
}
|
||||
var relationshipId = await db.Followings.Where(p => p.Follower == user && p.Followee == followee)
|
||||
.Select(p => p.RelationshipId)
|
||||
.FirstOrDefaultAsync() ??
|
||||
await db.FollowRequests.Where(p => p.Follower == user && p.Followee == followee)
|
||||
.Select(p => p.RelationshipId)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
var activity = activityRenderer.RenderUnfollow(user, followee, relationshipId);
|
||||
await deliverSvc.DeliverToAsync(activity, user, followee);
|
||||
}
|
||||
|
||||
if (followee.PrecomputedIsFollowedBy ?? false)
|
||||
|
@ -787,7 +797,7 @@ public class UserService(
|
|||
db.RemoveRange(followings);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
if (followee.Host != null)
|
||||
if (followee.IsRemoteUser)
|
||||
{
|
||||
_ = followupTaskSvc.ExecuteTask("DecrementInstanceOutgoingFollowsCounter", async provider =>
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue