Skip to content

Commit 66f3051

Browse files
authored
Added endpoint for updating an account information (#524)
Ref https://linear.app/ghost/issue/AP-1076/ - Added a new endpoint to update account information. - Right now, it doesn't perform the actual update, just returns 200
1 parent 5eb7fba commit 66f3051

File tree

4 files changed

+72
-1
lines changed

4 files changed

+72
-1
lines changed

features/account-update.feature

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
Feature: Update account information
2+
3+
Scenario: Update account information
4+
When an authenticated "put" request is made to "/.ghost/activitypub/account" with data:
5+
"""
6+
{
7+
"name": "Updated Name",
8+
"bio": "Updated bio",
9+
"username": "updatedUsername",
10+
"avatarUrl": "https://example.com/avatar.jpg",
11+
"bannerImageUrl": "https://example.com/banner.jpg"
12+
}
13+
"""
14+
Then the request is accepted with a 200

features/step_definitions/stepdefs.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -645,7 +645,7 @@ When('we request the outbox', async function () {
645645
});
646646

647647
When(
648-
/an authenticated (\"(delete|get|post|put)\"\s)?request is made to "(.*)"/,
648+
/an authenticated (\"(delete|get|post|put)\"\s)?request is made to "(.*)"$/,
649649
async function (method, path) {
650650
const requestMethod = method || 'get';
651651
let requestPath = path;
@@ -682,6 +682,23 @@ When(
682682
},
683683
);
684684

685+
When(
686+
/^an authenticated (\"(post|put)\"\s)?request is made to "(.*)" with data:$/,
687+
async function (method, path, data) {
688+
this.response = await fetchActivityPub(
689+
`http://fake-ghost-activitypub${path}`,
690+
{
691+
method: method,
692+
headers: {
693+
Accept: 'application/ld+json',
694+
'Content-Type': 'application/json',
695+
},
696+
body: data,
697+
},
698+
);
699+
},
700+
);
701+
685702
When('an unauthenticated request is made to {string}', async function (path) {
686703
this.response = await fetchActivityPub(
687704
`http://fake-ghost-activitypub${path}`,

src/app.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ import {
109109
createGetThreadHandler,
110110
createPostPublishedWebhookHandler,
111111
createSearchHandler,
112+
createUpdateAccountHandler,
112113
handleCreateNote,
113114
handleWebhookSiteChanged,
114115
} from './http/api';
@@ -965,6 +966,11 @@ app.get(
965966
createGetAccountHandler(accountService, accountRepository, fedify),
966967
),
967968
);
969+
app.put(
970+
'/.ghost/activitypub/account',
971+
requireRole(GhostRole.Owner, GhostRole.Administrator),
972+
spanWrapper(createUpdateAccountHandler(accountService)),
973+
);
968974
app.get(
969975
'/.ghost/activitypub/posts/:handle',
970976
requireRole(GhostRole.Owner, GhostRole.Administrator),

src/http/api/account.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type { AppContext, ContextData } from 'app';
77
import { isHandle } from 'helpers/activitypub/actor';
88
import { lookupAPIdByHandle } from 'lookup-helpers';
99
import type { GetProfileDataResult, PostService } from 'post/post.service';
10+
import { z } from 'zod';
1011
import {
1112
getAccountDTOByHandle,
1213
getAccountDTOFromAccount,
@@ -17,6 +18,14 @@ import type {
1718
AccountFollowsView,
1819
} from './views/account.follows.view';
1920

21+
const UpdateAccountSchema = z.object({
22+
name: z.string(),
23+
bio: z.string(),
24+
username: z.string(),
25+
avatarUrl: z.string(),
26+
bannerImageUrl: z.string(),
27+
});
28+
2029
/**
2130
* Default number of posts to return in a profile
2231
*/
@@ -361,3 +370,28 @@ export function createGetAccountLikedPostsHandler(
361370
);
362371
};
363372
}
373+
374+
/**
375+
* Create a handler to handle a request for an account update
376+
*/
377+
export function createUpdateAccountHandler(accountService: AccountService) {
378+
return async function handleUpdateAccount(ctx: AppContext) {
379+
const account = await accountService.getAccountForSite(ctx.get('site'));
380+
381+
if (!account) {
382+
return new Response(null, { status: 404 });
383+
}
384+
385+
let data: z.infer<typeof UpdateAccountSchema>;
386+
387+
try {
388+
data = UpdateAccountSchema.parse((await ctx.req.json()) as unknown);
389+
} catch (err) {
390+
return new Response(JSON.stringify({}), { status: 400 });
391+
}
392+
393+
//Todo: Update the account with the new data
394+
395+
return new Response(JSON.stringify({}), { status: 200 });
396+
};
397+
}

0 commit comments

Comments
 (0)