0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-01-20 22:42:53 -05:00

Refactored collection retrieval in admin-x-activitypub (#21491)

no refs

Refactored collection retrieval to reduce code duplication and
complexity
This commit is contained in:
Michael Barrett 2024-10-31 20:31:20 +00:00 committed by GitHub
parent 4c79887b79
commit b90e16219d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 48 additions and 137 deletions

View file

@ -183,7 +183,7 @@ describe('ActivityPubAPI', function () {
});
describe('getOutbox', function () {
test('It passes the token to the outbox endpoint', async function () {
test('It passes the token to the outbox collection endpoint', async function () {
const fakeFetch = Fetch({
'https://auth.api/': {
response: JSONResponse({
@ -213,7 +213,7 @@ describe('ActivityPubAPI', function () {
await api.getOutbox();
});
test('Returns an empty array when the outbox is empty', async function () {
test('Returns an empty array when the outbox collection is empty', async function () {
const fakeFetch = Fetch({
'https://auth.api/': {
response: JSONResponse({
@ -247,7 +247,7 @@ describe('ActivityPubAPI', function () {
expect(actual).toEqual(expected);
});
test('Recursively retrieves all items and returns them when the outbox is not empty', async function () {
test('Recursively retrieves all items and returns them when the outbox collection is not empty', async function () {
const fakeFetch = Fetch({
'https://auth.api/': {
response: JSONResponse({
@ -316,7 +316,7 @@ describe('ActivityPubAPI', function () {
});
describe('getFollowing', function () {
test('It passes the token to the following endpoint', async function () {
test('It passes the token to the following collection endpoint', async function () {
const fakeFetch = Fetch({
'https://auth.api/': {
response: JSONResponse({
@ -346,7 +346,7 @@ describe('ActivityPubAPI', function () {
await api.getFollowing();
});
test('Returns an empty array when the following is empty', async function () {
test('Returns an empty array when the following collection is empty', async function () {
const fakeFetch = Fetch({
'https://auth.api/': {
response: JSONResponse({
@ -380,7 +380,7 @@ describe('ActivityPubAPI', function () {
expect(actual).toEqual(expected);
});
test('Recursively retrieves all items and returns them when the following is not empty', async function () {
test('Recursively retrieves all items and returns them when the following collection is not empty', async function () {
const fakeFetch = Fetch({
'https://auth.api/': {
response: JSONResponse({
@ -437,7 +437,7 @@ describe('ActivityPubAPI', function () {
});
describe('getFollowers', function () {
test('It passes the token to the following endpoint', async function () {
test('It passes the token to the followers collection endpoint', async function () {
const fakeFetch = Fetch({
'https://auth.api/': {
response: JSONResponse({
@ -467,7 +467,7 @@ describe('ActivityPubAPI', function () {
await api.getFollowers();
});
test('Returns an empty array when the followers is empty', async function () {
test('Returns an empty array when the followers collection is empty', async function () {
const fakeFetch = Fetch({
'https://auth.api/': {
response: JSONResponse({
@ -501,7 +501,7 @@ describe('ActivityPubAPI', function () {
expect(actual).toEqual(expected);
});
test('Recursively retrieves all items and returns them when the followers is not empty', async function () {
test('Recursively retrieves all items and returns them when the followers collection is not empty', async function () {
const fakeFetch = Fetch({
'https://auth.api/': {
response: JSONResponse({

View file

@ -73,6 +73,41 @@ export class ActivityPubAPI {
return json;
}
private async getActivityPubCollection<T>(collectionUrl: URL): Promise<T[]> {
const fetchPage = async (pageUrl: URL): Promise<T[]> => {
const json = await this.fetchJSON(pageUrl);
if (json === null) {
return [];
}
let items: T[] = [];
if ('orderedItems' in json) {
items = Array.isArray(json.orderedItems) ? json.orderedItems : [json.orderedItems];
}
if ('next' in json && typeof json.next === 'string') {
const nextPageUrl = new URL(json.next);
const nextPageItems = await fetchPage(nextPageUrl);
items = items.concat(nextPageItems);
}
return items;
};
const initialJson = await this.fetchJSON(collectionUrl);
if (initialJson === null || !('first' in initialJson) || typeof initialJson.first !== 'string') {
return [];
}
const firstPageUrl = new URL(initialJson.first);
return fetchPage(firstPageUrl);
}
get inboxApiUrl() {
return new URL(`.ghost/activitypub/inbox/${this.handle}`, this.apiUrl);
}
@ -96,38 +131,7 @@ export class ActivityPubAPI {
}
async getOutbox(): Promise<Activity[]> {
const fetchOutboxPage = async (url: URL): Promise<Activity[]> => {
const json = await this.fetchJSON(url);
if (json === null) {
return [];
}
let items: Activity[] = [];
if ('orderedItems' in json) {
items = Array.isArray(json.orderedItems) ? json.orderedItems : [json.orderedItems];
}
if ('next' in json && typeof json.next === 'string') {
const nextUrl = new URL(json.next);
const nextItems = await fetchOutboxPage(nextUrl);
items = items.concat(nextItems);
}
return items;
};
const initialJson = await this.fetchJSON(this.outboxApiUrl);
if (initialJson === null || !('first' in initialJson) || typeof initialJson.first !== 'string') {
return [];
}
const firstPageUrl = new URL(initialJson.first);
return fetchOutboxPage(firstPageUrl);
return this.getActivityPubCollection<Activity>(this.outboxApiUrl);
}
get followingApiUrl() {
@ -135,38 +139,7 @@ export class ActivityPubAPI {
}
async getFollowing(): Promise<Actor[]> {
const fetchFollowingPage = async (url: URL): Promise<Actor[]> => {
const json = await this.fetchJSON(url);
if (json === null) {
return [];
}
let items: Actor[] = [];
if ('orderedItems' in json) {
items = Array.isArray(json.orderedItems) ? json.orderedItems : [json.orderedItems];
}
if ('next' in json && typeof json.next === 'string') {
const nextUrl = new URL(json.next);
const nextItems = await fetchFollowingPage(nextUrl);
items = items.concat(nextItems);
}
return items;
};
const initialJson = await this.fetchJSON(this.followingApiUrl);
if (initialJson === null || !('first' in initialJson) || typeof initialJson.first !== 'string') {
return [];
}
const firstPageUrl = new URL(initialJson.first);
return fetchFollowingPage(firstPageUrl);
return this.getActivityPubCollection<Actor>(this.followingApiUrl);
}
async getFollowingCount(): Promise<number> {
@ -185,38 +158,7 @@ export class ActivityPubAPI {
}
async getFollowers(): Promise<Actor[]> {
const fetchFollowersPage = async (url: URL): Promise<Actor[]> => {
const json = await this.fetchJSON(url);
if (json === null) {
return [];
}
let items: Actor[] = [];
if ('orderedItems' in json) {
items = Array.isArray(json.orderedItems) ? json.orderedItems : [json.orderedItems];
}
if ('next' in json && typeof json.next === 'string') {
const nextUrl = new URL(json.next);
const nextItems = await fetchFollowersPage(nextUrl);
items = items.concat(nextItems);
}
return items;
};
const initialJson = await this.fetchJSON(this.followersApiUrl);
if (initialJson === null || !('first' in initialJson) || typeof initialJson.first !== 'string') {
return [];
}
const firstPageUrl = new URL(initialJson.first);
return fetchFollowersPage(firstPageUrl);
return this.getActivityPubCollection<Actor>(this.followersApiUrl);
}
async getFollowersCount(): Promise<number> {
@ -307,38 +249,7 @@ export class ActivityPubAPI {
}
async getLiked() {
const fetchLikedPage = async (url: URL): Promise<Activity[]> => {
const json = await this.fetchJSON(url);
if (json === null) {
return [];
}
let items: Activity[] = [];
if ('orderedItems' in json) {
items = Array.isArray(json.orderedItems) ? json.orderedItems : [json.orderedItems];
}
if ('next' in json && typeof json.next === 'string') {
const nextUrl = new URL(json.next);
const nextItems = await fetchLikedPage(nextUrl);
items = items.concat(nextItems);
}
return items;
};
const initialJson = await this.fetchJSON(this.likedApiUrl);
if (initialJson === null || !('first' in initialJson) || typeof initialJson.first !== 'string') {
return [];
}
const firstPageUrl = new URL(initialJson.first);
return fetchLikedPage(firstPageUrl);
return this.getActivityPubCollection<Activity>(this.likedApiUrl);
}
async like(id: string): Promise<void> {