From e4952f0c2137ed513e165314c42131f50f800f15 Mon Sep 17 00:00:00 2001 From: "P. Reis" Date: Wed, 8 May 2024 20:10:09 -0300 Subject: [PATCH 1/3] feat: create updateListAdminEvent() & updateAdminEvent() --- src/utils/api.ts | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/utils/api.ts b/src/utils/api.ts index 72f4c3e..cba7c66 100644 --- a/src/utils/api.ts +++ b/src/utils/api.ts @@ -76,6 +76,29 @@ async function createAdminEvent(t: EventStub, c: AppContext): Promise string[][], + c: AppContext, +): Promise { + return updateAdminEvent(filter, (prev) => ({ + kind: filter.kinds[0], + content: prev?.content ?? '', + tags: fn(prev?.tags ?? []), + }), c); +} + +/** Fetch existing event, update it, then publish the new admin event. */ +async function updateAdminEvent( + filter: UpdateEventFilter, + fn: (prev: NostrEvent | undefined) => E, + c: AppContext, +): Promise { + const [prev] = await Storages.db.query([filter], { limit: 1, signal: c.req.raw.signal }); + return createAdminEvent(fn(prev), c); +} + /** Push the event through the pipeline, rethrowing any RelayError. */ async function publishEvent(event: NostrEvent, c: AppContext): Promise { debug('EVENT', event); @@ -185,5 +208,6 @@ export { paginationSchema, parseBody, updateEvent, + updateListAdminEvent, updateListEvent, }; From 9e2225873d5869722d5728cf9eb250a040d79336 Mon Sep 17 00:00:00 2001 From: "P. Reis" Date: Wed, 8 May 2024 20:08:44 -0300 Subject: [PATCH 2/3] feat: implement action against an account - Action of deactivating an account by muting it in the entire server --- src/app.ts | 4 +++- src/controllers/api/admin.ts | 40 ++++++++++++++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/app.ts b/src/app.ts index a3f6a43..344c52a 100644 --- a/src/app.ts +++ b/src/app.ts @@ -25,7 +25,7 @@ import { updateCredentialsController, verifyCredentialsController, } from '@/controllers/api/accounts.ts'; -import { adminAccountsController } from '@/controllers/api/admin.ts'; +import { adminAccountAction, adminAccountsController } from '@/controllers/api/admin.ts'; import { appCredentialsController, createAppController } from '@/controllers/api/apps.ts'; import { blocksController } from '@/controllers/api/blocks.ts'; import { bookmarksController } from '@/controllers/api/bookmarks.ts'; @@ -222,6 +222,8 @@ app.post( adminReportResolveController, ); +app.post('/api/v1/admin/accounts/:id{[0-9a-f]{64}}/action', requirePubkey, requireRole('admin'), adminAccountAction); + // Not (yet) implemented. app.get('/api/v1/custom_emojis', emptyArrayController); app.get('/api/v1/filters', emptyArrayController); diff --git a/src/controllers/api/admin.ts b/src/controllers/api/admin.ts index 1542056..97e28b4 100644 --- a/src/controllers/api/admin.ts +++ b/src/controllers/api/admin.ts @@ -5,7 +5,8 @@ import { Conf } from '@/config.ts'; import { booleanParamSchema } from '@/schema.ts'; import { Storages } from '@/storages.ts'; import { renderAdminAccount } from '@/views/mastodon/admin-accounts.ts'; -import { paginated, paginationSchema } from '@/utils/api.ts'; +import { paginated, paginationSchema, parseBody, updateListAdminEvent } from '@/utils/api.ts'; +import { addTag } from '@/tags.ts'; const adminAccountQuerySchema = z.object({ local: booleanParamSchema.optional(), @@ -57,4 +58,39 @@ const adminAccountsController: AppController = async (c) => { return paginated(c, events, accounts); }; -export { adminAccountsController }; +const adminAccountActionSchema = z.object({ + type: z.enum(['none', 'sensitive', 'disable', 'silence', 'suspend']), +}); + +const adminAccountAction: AppController = async (c) => { + const body = await parseBody(c.req.raw); + const result = adminAccountActionSchema.safeParse(body); + const authorId = c.req.param('id'); + const store = c.get('store'); + const { signal } = c.req.raw; + + if (!result.success) { + return c.json({ error: 'This action is not allowed' }, 403); + } + + const { data } = result; + + if (data.type !== 'disable') { + return c.json({ error: 'Record invalid' }, 422); + } + + const [event] = await store.query([{ kinds: [0], authors: [authorId], limit: 1 }], { signal }); + if (!event) { + return c.json({ error: 'Record not found' }, 404); + } + + await updateListAdminEvent( + { kinds: [10000], authors: [Conf.pubkey] }, + (tags) => addTag(tags, ['p', event.pubkey]), + c, + ); + + return c.json({}, 200); +}; + +export { adminAccountAction, adminAccountsController }; From 4fa6b96d15cfc88f37a85a8990c82db2dd88eb49 Mon Sep 17 00:00:00 2001 From: "P. Reis" Date: Thu, 9 May 2024 13:44:05 -0300 Subject: [PATCH 3/3] refactor(admin action): mute account even if it doesn't have a kind 0 --- src/controllers/api/admin.ts | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/controllers/api/admin.ts b/src/controllers/api/admin.ts index 97e28b4..99a8e5b 100644 --- a/src/controllers/api/admin.ts +++ b/src/controllers/api/admin.ts @@ -66,8 +66,6 @@ const adminAccountAction: AppController = async (c) => { const body = await parseBody(c.req.raw); const result = adminAccountActionSchema.safeParse(body); const authorId = c.req.param('id'); - const store = c.get('store'); - const { signal } = c.req.raw; if (!result.success) { return c.json({ error: 'This action is not allowed' }, 403); @@ -79,14 +77,9 @@ const adminAccountAction: AppController = async (c) => { return c.json({ error: 'Record invalid' }, 422); } - const [event] = await store.query([{ kinds: [0], authors: [authorId], limit: 1 }], { signal }); - if (!event) { - return c.json({ error: 'Record not found' }, 404); - } - await updateListAdminEvent( { kinds: [10000], authors: [Conf.pubkey] }, - (tags) => addTag(tags, ['p', event.pubkey]), + (tags) => addTag(tags, ['p', authorId]), c, );