Merge branch 'replaceable-update' into 'main'

Throw when creating a replaceable event that doesn't exist yet

See merge request soapbox-pub/ditto!458
This commit is contained in:
Alex Gleason 2024-08-15 23:14:13 +00:00
commit b6f32c4d0f
3 changed files with 64 additions and 45 deletions

View file

@ -9,7 +9,7 @@ import { booleanParamSchema, fileSchema } from '@/schema.ts';
import { Storages } from '@/storages.ts'; import { Storages } from '@/storages.ts';
import { uploadFile } from '@/utils/upload.ts'; import { uploadFile } from '@/utils/upload.ts';
import { nostrNow } from '@/utils.ts'; import { nostrNow } from '@/utils.ts';
import { createEvent, paginated, parseBody, updateListEvent } from '@/utils/api.ts'; import { createEvent, paginated, parseBody, updateEvent, updateListEvent } from '@/utils/api.ts';
import { extractIdentifier, lookupAccount, lookupPubkey } from '@/utils/lookup.ts'; import { extractIdentifier, lookupAccount, lookupPubkey } from '@/utils/lookup.ts';
import { renderAccounts, renderEventAccounts, renderStatuses } from '@/views.ts'; import { renderAccounts, renderEventAccounts, renderStatuses } from '@/views.ts';
import { accountFromPubkey, renderAccount } from '@/views/mastodon/accounts.ts'; import { accountFromPubkey, renderAccount } from '@/views/mastodon/accounts.ts';
@ -269,9 +269,10 @@ const updateCredentialsController: AppController = async (c) => {
return c.json(result.error, 422); return c.json(result.error, 422);
} }
const author = await getAuthor(pubkey); const event = await updateEvent(
const meta = author ? n.json().pipe(n.metadata()).catch({}).parse(author.content) : {}; { kinds: [0], authors: [pubkey], limit: 1 },
async (prev) => {
const meta = n.json().pipe(n.metadata()).catch({}).parse(prev.content);
const { const {
avatar: avatarFile, avatar: avatarFile,
header: headerFile, header: headerFile,
@ -303,11 +304,14 @@ const updateCredentialsController: AppController = async (c) => {
if (lud16 === '') delete meta.lud16; if (lud16 === '') delete meta.lud16;
if (website === '') delete meta.website; if (website === '') delete meta.website;
const event = await createEvent({ return {
kind: 0, kind: 0,
content: JSON.stringify(meta), content: JSON.stringify(meta),
tags: [], tags: [],
}, c); };
},
c,
);
const account = await renderAccount(event, { withSource: true }); const account = await renderAccount(event, { withSource: true });
const settingsStore = result.data.pleroma_settings_store; const settingsStore = result.data.pleroma_settings_store;

View file

@ -3,8 +3,12 @@ import { HTTPException } from '@hono/hono/http-exception';
export const errorHandler: ErrorHandler = (err, c) => { export const errorHandler: ErrorHandler = (err, c) => {
if (err instanceof HTTPException) { if (err instanceof HTTPException) {
if (err.res) {
return err.res;
} else {
return c.json({ error: err.message }, err.status); return c.json({ error: err.message }, err.status);
} }
}
if (err.message === 'canceling statement due to statement timeout') { if (err.message === 'canceling statement due to statement timeout') {
return c.json({ error: 'The server was unable to respond in a timely manner' }, 500); return c.json({ error: 'The server was unable to respond in a timely manner' }, 500);

View file

@ -46,27 +46,38 @@ interface UpdateEventFilter extends NostrFilter {
limit: 1; limit: 1;
} }
/** Fetch existing event, update it, then publish the new event. */ /** Update a replaceable event, or throw if no event exists yet. */
async function updateEvent<E extends EventStub>( async function updateEvent<E extends EventStub>(
filter: UpdateEventFilter, filter: UpdateEventFilter,
fn: (prev: NostrEvent | undefined) => E, fn: (prev: NostrEvent) => E | Promise<E>,
c: AppContext, c: AppContext,
): Promise<NostrEvent> { ): Promise<NostrEvent> {
const store = await Storages.db(); const store = await Storages.db();
const [prev] = await store.query([filter], { signal: c.req.raw.signal });
return createEvent(fn(prev), c); const [prev] = await store.query(
[filter],
{ signal: c.req.raw.signal },
);
if (prev) {
return createEvent(await fn(prev), c);
} else {
throw new HTTPException(422, {
message: 'No event to update',
});
}
} }
/** Fetch existing event, update its tags, then publish the new event. */ /** Update a replaceable list event, or throw if no event exists yet. */
function updateListEvent( function updateListEvent(
filter: UpdateEventFilter, filter: UpdateEventFilter,
fn: (tags: string[][]) => string[][], fn: (tags: string[][]) => string[][],
c: AppContext, c: AppContext,
): Promise<NostrEvent> { ): Promise<NostrEvent> {
return updateEvent(filter, (prev) => ({ return updateEvent(filter, ({ content, tags }) => ({
kind: filter.kinds[0], kind: filter.kinds[0],
content: prev?.content ?? '', content,
tags: fn(prev?.tags ?? []), tags: fn(tags),
}), c); }), c);
} }