mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-10 23:36:14 -05:00
Fixed followers list on profile in admin-x-activitypub app (#21370)
refs [AP-489](https://linear.app/ghost/issue/AP-489/followers-showing-unknown-on-user-profile) Fixed the followers list on profile in admin-x-activitypub app by utilising a custom endpoint to fetch a list of expanded followers seeming though the followers endpoint only returns follower id's
This commit is contained in:
parent
b9768f99e9
commit
e9914d8fe5
5 changed files with 127 additions and 3 deletions
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@tryghost/admin-x-activitypub",
|
||||
"version": "0.1.5",
|
||||
"version": "0.1.6",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
|
@ -562,6 +562,104 @@ describe('ActivityPubAPI', function () {
|
|||
});
|
||||
});
|
||||
|
||||
describe('getFollowersExpanded', function () {
|
||||
test('It passes the token to the followers endpoint', async function () {
|
||||
const fakeFetch = Fetch({
|
||||
'https://auth.api/': {
|
||||
response: JSONResponse({
|
||||
identities: [{
|
||||
token: 'fake-token'
|
||||
}]
|
||||
})
|
||||
},
|
||||
'https://activitypub.api/.ghost/activitypub/followers-expanded/index': {
|
||||
async assert(_resource, init) {
|
||||
const headers = new Headers(init?.headers);
|
||||
expect(headers.get('Authorization')).toContain('fake-token');
|
||||
},
|
||||
response: JSONResponse({
|
||||
type: 'Collection',
|
||||
orderedItems: []
|
||||
})
|
||||
}
|
||||
});
|
||||
const api = new ActivityPubAPI(
|
||||
new URL('https://activitypub.api'),
|
||||
new URL('https://auth.api'),
|
||||
'index',
|
||||
fakeFetch
|
||||
);
|
||||
|
||||
await api.getFollowersExpanded();
|
||||
});
|
||||
|
||||
test('Returns an empty array when the followers is empty', async function () {
|
||||
const fakeFetch = Fetch({
|
||||
'https://auth.api/': {
|
||||
response: JSONResponse({
|
||||
identities: [{
|
||||
token: 'fake-token'
|
||||
}]
|
||||
})
|
||||
},
|
||||
'https://activitypub.api/.ghost/activitypub/followers-expanded/index': {
|
||||
response: JSONResponse({
|
||||
type: 'Collection',
|
||||
orderedItems: []
|
||||
})
|
||||
}
|
||||
});
|
||||
const api = new ActivityPubAPI(
|
||||
new URL('https://activitypub.api'),
|
||||
new URL('https://auth.api'),
|
||||
'index',
|
||||
fakeFetch
|
||||
);
|
||||
|
||||
const actual = await api.getFollowersExpanded();
|
||||
const expected: never[] = [];
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
|
||||
test('Returns all the items array when the followers is not empty', async function () {
|
||||
const fakeFetch = Fetch({
|
||||
'https://auth.api/': {
|
||||
response: JSONResponse({
|
||||
identities: [{
|
||||
token: 'fake-token'
|
||||
}]
|
||||
})
|
||||
},
|
||||
'https://activitypub.api/.ghost/activitypub/followers-expanded/index': {
|
||||
response:
|
||||
JSONResponse({
|
||||
type: 'Collection',
|
||||
orderedItems: [{
|
||||
type: 'Person'
|
||||
}]
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
const api = new ActivityPubAPI(
|
||||
new URL('https://activitypub.api'),
|
||||
new URL('https://auth.api'),
|
||||
'index',
|
||||
fakeFetch
|
||||
);
|
||||
|
||||
const actual = await api.getFollowersExpanded();
|
||||
const expected: Activity[] = [
|
||||
{
|
||||
type: 'Person'
|
||||
}
|
||||
];
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('follow', function () {
|
||||
test('It passes the token to the follow endpoint', async function () {
|
||||
const fakeFetch = Fetch({
|
||||
|
|
|
@ -159,6 +159,21 @@ export class ActivityPubAPI {
|
|||
return 0;
|
||||
}
|
||||
|
||||
get followersExpandedApiUrl() {
|
||||
return new URL(`.ghost/activitypub/followers-expanded/${this.handle}`, this.apiUrl);
|
||||
}
|
||||
|
||||
async getFollowersExpanded(): Promise<Activity[]> {
|
||||
const json = await this.fetchJSON(this.followersExpandedApiUrl);
|
||||
if (json === null) {
|
||||
return [];
|
||||
}
|
||||
if ('orderedItems' in json) {
|
||||
return Array.isArray(json.orderedItems) ? json.orderedItems : [json.orderedItems];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
async getFollowersForProfile(handle: string, next?: string): Promise<GetFollowersForProfileResponse> {
|
||||
const url = new URL(`.ghost/activitypub/profile/${handle}/followers`, this.apiUrl);
|
||||
if (next) {
|
||||
|
|
|
@ -8,7 +8,7 @@ import {ActorProperties} from '@tryghost/admin-x-framework/api/activitypub';
|
|||
import {Button, Heading, List, NoValueLabel, Tab, TabView} from '@tryghost/admin-x-design-system';
|
||||
import {
|
||||
useFollowersCountForUser,
|
||||
useFollowersForUser,
|
||||
useFollowersExpandedForUser,
|
||||
useFollowingCountForUser,
|
||||
useFollowingForUser,
|
||||
useLikedForUser,
|
||||
|
@ -22,7 +22,7 @@ const Profile: React.FC<ProfileProps> = ({}) => {
|
|||
const {data: followersCount = 0} = useFollowersCountForUser('index');
|
||||
const {data: followingCount = 0} = useFollowingCountForUser('index');
|
||||
const {data: following = []} = useFollowingForUser('index');
|
||||
const {data: followers = []} = useFollowersForUser('index');
|
||||
const {data: followers = []} = useFollowersExpandedForUser('index');
|
||||
const {data: liked = []} = useLikedForUser('index');
|
||||
const {data: posts = []} = useOutboxForUser('index');
|
||||
|
||||
|
|
|
@ -193,6 +193,17 @@ export function useFollowersForUser(handle: string) {
|
|||
});
|
||||
}
|
||||
|
||||
export function useFollowersExpandedForUser(handle: string) {
|
||||
return useQuery({
|
||||
queryKey: [`followers_expanded:${handle}`],
|
||||
async queryFn() {
|
||||
const siteUrl = await getSiteUrl();
|
||||
const api = createActivityPubAPI(handle, siteUrl);
|
||||
return api.getFollowersExpanded();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function useAllActivitiesForUser({
|
||||
handle,
|
||||
includeOwn = false,
|
||||
|
|
Loading…
Add table
Reference in a new issue