A moved account's profile says where it went
PrivaPub now fills `moved` once a move is believed; the profile shows it, linking the new account's profile. The e2e opens the account SocialPub's moves scenario moved and finds the new one named. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
This commit is contained in:
1 parent
228708c328
commit
f9de55ffd5
6 files changed
+51
No files matched your search
@@ -231,6 +231,8 @@ supplies:
|
|||||||
link, participants and status.
|
link, participants and status.
|
||||||
- **Profiles and search** (`Pages/Profile.razor` at `/account/{id}`, `Pages/Search.razor` at `/search?q=`): a card's
|
- **Profiles and search** (`Pages/Profile.razor` at `/account/{id}`, `Pages/Search.razor` at `/search?q=`): a card's
|
||||||
author and a notification's account open the profile in the app; "Open original" is the only way to the remote site.
|
author and a notification's account open the profile in the app; "Open original" is the only way to the remote site.
|
||||||
|
An account that moved says where to (`Account.Moved`, which PrivaPub fills once the new account names the old one),
|
||||||
|
linking the new account's profile.
|
||||||
A card in a fixed-height flex column with `overflow-hidden` needs `flex-none`, or it collapses to nothing.
|
A card in a fixed-height flex column with `overflow-hidden` needs `flex-none`, or it collapses to nothing.
|
||||||
- **Groups** (`Pages/Groups.razor` at `/groups`): the persona's communities and circles (`GroupService`, `/clientapi/group`):
|
- **Groups** (`Pages/Groups.razor` at `/groups`): the persona's communities and circles (`GroupService`, `/clientapi/group`):
|
||||||
made (a circle unless it is a community, with an invitation code and an optional password), joined by invitation and
|
made (a circle unless it is a community, with an invitation code and an optional password), joined by invitation and
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ public class Account
|
|||||||
public string LastStatusAt { get; set; }
|
public string LastStatusAt { get; set; }
|
||||||
public List<CustomEmoji> Emojis { get; set; } = [];
|
public List<CustomEmoji> Emojis { get; set; } = [];
|
||||||
public List<AccountField> Fields { get; set; } = [];
|
public List<AccountField> Fields { get; set; } = [];
|
||||||
|
/// <summary>The account it moved to (PrivaPub shows it once the new account names this one among its aliases).</summary>
|
||||||
|
public Account Moved { get; set; }
|
||||||
/// <summary>Whether it is listed in the directory and suggested; null when its server does not say.</summary>
|
/// <summary>Whether it is listed in the directory and suggested; null when its server does not say.</summary>
|
||||||
public bool? Discoverable { get; set; }
|
public bool? Discoverable { get; set; }
|
||||||
/// <summary>Whether its public posts may be found by full-text search.</summary>
|
/// <summary>Whether its public posts may be found by full-text search.</summary>
|
||||||
|
|||||||
@@ -32,6 +32,14 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@if (account.Moved is { } moved)
|
||||||
|
{
|
||||||
|
<p class="flex flex-wrap items-center gap-2 p-3 rounded-xl neo-inset neo-2xs text-sm" data-moved>
|
||||||
|
<i class="ion-md-swap"></i>
|
||||||
|
<span>@Localizer["{0} has moved to", account.Name]</span>
|
||||||
|
<a class="link font-semibold" href="@($"account/{Uri.EscapeDataString(moved.Id)}")">@("@" + moved.Acct)</a>
|
||||||
|
</p>
|
||||||
|
}
|
||||||
<article class="flex flex-none flex-col rounded-xl neo-raised neo-xs overflow-hidden" data-account-id="@account.Id">
|
<article class="flex flex-none flex-col rounded-xl neo-raised neo-xs overflow-hidden" data-account-id="@account.Id">
|
||||||
<div class="h-28 md:h-40 bg-base-200 bg-cover bg-center" style="@HeaderStyle"></div>
|
<div class="h-28 md:h-40 bg-base-200 bg-cover bg-center" style="@HeaderStyle"></div>
|
||||||
<div class="flex flex-wrap items-end gap-3 px-4 -mt-10">
|
<div class="flex flex-wrap items-end gap-3 px-4 -mt-10">
|
||||||
|
|||||||
@@ -1715,4 +1715,7 @@
|
|||||||
<data name="Every persona of this login goes with it, and everything public they had, here and on the servers that hold it. It cannot be undone." xml:space="preserve">
|
<data name="Every persona of this login goes with it, and everything public they had, here and on the servers that hold it. It cannot be undone." xml:space="preserve">
|
||||||
<value>Ogni persona di questo accesso se ne va con lui, e tutto ciò che avevano di pubblico, qui e sui server che lo tengono. Non si può annullare.</value>
|
<value>Ogni persona di questo accesso se ne va con lui, e tutto ciò che avevano di pubblico, qui e sui server che lo tengono. Non si può annullare.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="{0} has moved to" xml:space="preserve">
|
||||||
|
<value>{0} si è trasferito su</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -1715,4 +1715,7 @@
|
|||||||
<data name="Every persona of this login goes with it, and everything public they had, here and on the servers that hold it. It cannot be undone." xml:space="preserve">
|
<data name="Every persona of this login goes with it, and everything public they had, here and on the servers that hold it. It cannot be undone." xml:space="preserve">
|
||||||
<value>Every persona of this login goes with it, and everything public they had, here and on the servers that hold it. It cannot be undone.</value>
|
<value>Every persona of this login goes with it, and everything public they had, here and on the servers that hold it. It cannot be undone.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="{0} has moved to" xml:space="preserve">
|
||||||
|
<value>{0} has moved to</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -24,6 +24,39 @@ namespace decePubClient.E2E.Actions
|
|||||||
return candidates.Last();
|
return candidates.Last();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the newest GoToSocial account that SocialPub's moves scenario moved (scenarios/moves.sh), as PrivaPub knows it
|
||||||
|
static async Task<(string Old, string New)> Moved()
|
||||||
|
{
|
||||||
|
var start = new System.Diagnostics.ProcessStartInfo("podman") { RedirectStandardOutput = true, RedirectStandardError = true };
|
||||||
|
foreach (var arg in new[] { "exec", "pasture-mongo", "mongosh", "--quiet", "PrivaPub", "--eval",
|
||||||
|
"const a = db.ForeignAvatar.find({ActorURI: {$regex: 'gts.test.users.mvold'}, MovedToURL: {$ne: null}}).sort({_id: -1}).limit(1).toArray()[0];" +
|
||||||
|
"print(a ? a.ActorURI + ' ' + a.MovedToURL : '')" })
|
||||||
|
start.ArgumentList.Add(arg);
|
||||||
|
using var process = System.Diagnostics.Process.Start(start)!;
|
||||||
|
var output = (await process.StandardOutput.ReadToEndAsync()).Trim();
|
||||||
|
await process.WaitForExitAsync();
|
||||||
|
var parts = output.Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
return parts.Length == 2 ? (parts[0], parts[1]) : default;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task A_moved_accounts_profile_says_where_it_went()
|
||||||
|
{
|
||||||
|
var (old, moved) = await Moved();
|
||||||
|
Assert.SkipWhen(old is null, "no moved account: run SocialPub's tools/pasture/interop.sh moves");
|
||||||
|
var persona = Pasture.Personas().First();
|
||||||
|
var handle = old.Split("/users/")[1] + "@gts.test";
|
||||||
|
await using var session = await SignIn.As(browser, persona);
|
||||||
|
await Results.Cell("client.render.moved", "gts", handle, async () =>
|
||||||
|
{
|
||||||
|
await session.Page.GotoAsync($"{Pasture.Site}/search?q={Uri.EscapeDataString("@" + handle)}");
|
||||||
|
var banner = session.Page.Locator("[data-moved]");
|
||||||
|
await banner.WaitForAsync(new() { Timeout = 30000 });
|
||||||
|
await Assertions.Expect(banner).ToContainTextAsync("@" + moved.Split("/users/")[1] + "@gts.test");
|
||||||
|
await session.AssertGuards();
|
||||||
|
}, session.Page);
|
||||||
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[MemberData(nameof(Origins))]
|
[MemberData(nameof(Origins))]
|
||||||
public async Task A_remote_account_found_by_its_handle_is_followed_and_unfollowed_from_its_profile(string platform)
|
public async Task A_remote_account_found_by_its_handle_is_followed_and_unfollowed_from_its_profile(string platform)
|
||||||
|
|||||||
Reference in new issue
Block a user