Fixed handling of single item collections (#20688)

Fedify will not use an array for the `items` key of collections when
there is only a single item, which wasn't being handled in our
activitypub api module.

Now we always return an array so that the components recieve consistent
data.
This commit is contained in:
Fabien 'egg' O'Carroll 2024-07-30 17:33:25 +07:00 committed by GitHub
parent bbec5c0ba6
commit 178c98c17f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 123 additions and 6 deletions

View File

@ -95,7 +95,7 @@ describe('ActivityPubAPI', function () {
expect(actual).toEqual(expected);
});
test('Returns an the items array when the inbox is not empty', async function () {
test('Returns all the items array when the inbox is not empty', async function () {
const fakeFetch = Fetch({
'https://auth.api/': {
response: JSONResponse({
@ -137,6 +137,49 @@ describe('ActivityPubAPI', function () {
expect(actual).toEqual(expected);
});
test('Returns an array when the items key is a single object', async function () {
const fakeFetch = Fetch({
'https://auth.api/': {
response: JSONResponse({
identities: [{
token: 'fake-token'
}]
})
},
'https://activitypub.api/.ghost/activitypub/inbox/index': {
response:
JSONResponse({
type: 'Collection',
items: {
type: 'Create',
object: {
type: 'Note'
}
}
})
}
});
const api = new ActivityPubAPI(
new URL('https://activitypub.api'),
new URL('https://auth.api'),
'index',
fakeFetch
);
const actual = await api.getInbox();
const expected: Activity[] = [
{
type: 'Create',
object: {
type: 'Note'
}
}
];
expect(actual).toEqual(expected);
});
});
describe('getFollowing', function () {
@ -199,7 +242,7 @@ describe('ActivityPubAPI', function () {
expect(actual).toEqual(expected);
});
test('Returns an the items array when the following is not empty', async function () {
test('Returns all the items array when the following is not empty', async function () {
const fakeFetch = Fetch({
'https://auth.api/': {
response: JSONResponse({
@ -235,6 +278,43 @@ describe('ActivityPubAPI', function () {
expect(actual).toEqual(expected);
});
test('Returns an array when the items key is a single object', async function () {
const fakeFetch = Fetch({
'https://auth.api/': {
response: JSONResponse({
identities: [{
token: 'fake-token'
}]
})
},
'https://activitypub.api/.ghost/activitypub/following/index': {
response:
JSONResponse({
type: 'Collection',
items: {
type: 'Person'
}
})
}
});
const api = new ActivityPubAPI(
new URL('https://activitypub.api'),
new URL('https://auth.api'),
'index',
fakeFetch
);
const actual = await api.getFollowing();
const expected: Activity[] = [
{
type: 'Person'
}
];
expect(actual).toEqual(expected);
});
});
describe('getFollowers', function () {
@ -297,7 +377,7 @@ describe('ActivityPubAPI', function () {
expect(actual).toEqual(expected);
});
test('Returns an the items array when the followers is not empty', async function () {
test('Returns all the items array when the followers is not empty', async function () {
const fakeFetch = Fetch({
'https://auth.api/': {
response: JSONResponse({
@ -333,6 +413,43 @@ describe('ActivityPubAPI', function () {
expect(actual).toEqual(expected);
});
test('Returns an array when the items key is a single object', async function () {
const fakeFetch = Fetch({
'https://auth.api/': {
response: JSONResponse({
identities: [{
token: 'fake-token'
}]
})
},
'https://activitypub.api/.ghost/activitypub/followers/index': {
response:
JSONResponse({
type: 'Collection',
items: {
type: 'Person'
}
})
}
});
const api = new ActivityPubAPI(
new URL('https://activitypub.api'),
new URL('https://auth.api'),
'index',
fakeFetch
);
const actual = await api.getFollowers();
const expected: Activity[] = [
{
type: 'Person'
}
];
expect(actual).toEqual(expected);
});
});
describe('follow', function () {

View File

@ -45,7 +45,7 @@ export class ActivityPubAPI {
return [];
}
if ('items' in json) {
return Array.isArray(json?.items) ? json.items : [];
return Array.isArray(json.items) ? json.items : [json.items];
}
return [];
}
@ -60,7 +60,7 @@ export class ActivityPubAPI {
return [];
}
if ('items' in json) {
return Array.isArray(json?.items) ? json.items : [];
return Array.isArray(json.items) ? json.items : [json.items];
}
return [];
}
@ -86,7 +86,7 @@ export class ActivityPubAPI {
return [];
}
if ('items' in json) {
return Array.isArray(json?.items) ? json.items : [];
return Array.isArray(json.items) ? json.items : [json.items];
}
return [];
}