From 342ba7d4b1181317a9aa24dccc8e2a0e0a6c04f2 Mon Sep 17 00:00:00 2001 From: "P. Reis" Date: Fri, 29 Nov 2024 11:49:37 -0300 Subject: [PATCH 1/5] fix(updateCredentialsController): stop overwriting kind 0 unnecessarily --- src/controllers/api/accounts.ts | 107 +++++++++++++++++++------------- 1 file changed, 63 insertions(+), 44 deletions(-) diff --git a/src/controllers/api/accounts.ts b/src/controllers/api/accounts.ts index d5beac03..a880e98c 100644 --- a/src/controllers/api/accounts.ts +++ b/src/controllers/api/accounts.ts @@ -1,4 +1,4 @@ -import { NostrFilter, NSchema as n } from '@nostrify/nostrify'; +import { NostrEvent, NostrFilter, NSchema as n } from '@nostrify/nostrify'; import { nip19 } from 'nostr-tools'; import { z } from 'zod'; @@ -288,59 +288,78 @@ const updateCredentialsController: AppController = async (c) => { const pubkey = await signer.getPublicKey(); const body = await parseBody(c.req.raw); const result = updateCredentialsSchema.safeParse(body); + const store = await Storages.db(); if (!result.success) { return c.json(result.error, 422); } - const event = await updateEvent( - { kinds: [0], authors: [pubkey], limit: 1 }, - async (prev) => { - const meta = n.json().pipe(metadataSchema).catch({}).parse(prev.content); - const { - avatar: avatarFile, - header: headerFile, - display_name, - fields_attributes, - note, - nip05, - lud16, - website, - bot, - } = result.data; + const kind0fields = { + avatar: result.data.avatar, + header: result.data.header, + display_name: result.data.display_name, + fields_attributes: result.data.fields_attributes, + note: result.data.note, + nip05: result.data.nip05, + lud16: result.data.lud16, + website: result.data.website, + bot: result.data.bot, + }; + const values = Object.values(kind0fields).filter((value) => value !== undefined); + let event: NostrEvent; - const [avatar, header] = await Promise.all([ - avatarFile ? uploadFile(c, avatarFile, { pubkey }) : undefined, - headerFile ? uploadFile(c, headerFile, { pubkey }) : undefined, - ]); + if (values.length) { + event = await updateEvent( + { kinds: [0], authors: [pubkey], limit: 1 }, + async (prev) => { + const meta = n.json().pipe(metadataSchema).catch({}).parse(prev.content); + const { + avatar: avatarFile, + header: headerFile, + display_name, + fields_attributes, + note, + nip05, + lud16, + website, + bot, + } = kind0fields; - meta.name = display_name ?? meta.name; - meta.about = note ?? meta.about; - meta.picture = avatar?.url ?? meta.picture; - meta.banner = header?.url ?? meta.banner; - meta.nip05 = nip05 ?? meta.nip05; - meta.lud16 = lud16 ?? meta.lud16; - meta.website = website ?? meta.website; - meta.bot = bot ?? meta.bot; + const [avatar, header] = await Promise.all([ + avatarFile ? uploadFile(c, avatarFile, { pubkey }) : undefined, + headerFile ? uploadFile(c, headerFile, { pubkey }) : undefined, + ]); - if (avatarFile === '') delete meta.picture; - if (headerFile === '') delete meta.banner; - if (nip05 === '') delete meta.nip05; - if (lud16 === '') delete meta.lud16; - if (website === '') delete meta.website; + meta.name = display_name ?? meta.name; + meta.about = note ?? meta.about; + meta.picture = avatar?.url ?? meta.picture; + meta.banner = header?.url ?? meta.banner; + meta.nip05 = nip05 ?? meta.nip05; + meta.lud16 = lud16 ?? meta.lud16; + meta.website = website ?? meta.website; + meta.bot = bot ?? meta.bot; - if (fields_attributes) { - meta.fields = fields_attributes.map(({ name, value }) => [name, value]); - } + if (avatarFile === '') delete meta.picture; + if (headerFile === '') delete meta.banner; + if (nip05 === '') delete meta.nip05; + if (lud16 === '') delete meta.lud16; + if (website === '') delete meta.website; - return { - kind: 0, - content: JSON.stringify(meta), - tags: [], - }; - }, - c, - ); + if (fields_attributes) { + meta.fields = fields_attributes.map(({ name, value }) => [name, value]); + } + + return { + kind: 0, + content: JSON.stringify(meta), + tags: [], + }; + }, + c, + ); + } else { + [event] = await store.query([{ kinds: [0], authors: [pubkey] }]); + } const settingsStore = result.data.pleroma_settings_store; const account = await renderAccount(event, { withSource: true, settingsStore }); From b45fcdde69f33d1cace34d22f72d78ec64208306 Mon Sep 17 00:00:00 2001 From: "P. Reis" Date: Tue, 3 Dec 2024 14:23:00 -0300 Subject: [PATCH 2/5] Revert "fix(updateCredentialsController): stop overwriting kind 0 unnecessarily" This reverts commit 342ba7d4b1181317a9aa24dccc8e2a0e0a6c04f2. --- src/controllers/api/accounts.ts | 107 +++++++++++++------------------- 1 file changed, 44 insertions(+), 63 deletions(-) diff --git a/src/controllers/api/accounts.ts b/src/controllers/api/accounts.ts index a880e98c..d5beac03 100644 --- a/src/controllers/api/accounts.ts +++ b/src/controllers/api/accounts.ts @@ -1,4 +1,4 @@ -import { NostrEvent, NostrFilter, NSchema as n } from '@nostrify/nostrify'; +import { NostrFilter, NSchema as n } from '@nostrify/nostrify'; import { nip19 } from 'nostr-tools'; import { z } from 'zod'; @@ -288,78 +288,59 @@ const updateCredentialsController: AppController = async (c) => { const pubkey = await signer.getPublicKey(); const body = await parseBody(c.req.raw); const result = updateCredentialsSchema.safeParse(body); - const store = await Storages.db(); if (!result.success) { return c.json(result.error, 422); } - const kind0fields = { - avatar: result.data.avatar, - header: result.data.header, - display_name: result.data.display_name, - fields_attributes: result.data.fields_attributes, - note: result.data.note, - nip05: result.data.nip05, - lud16: result.data.lud16, - website: result.data.website, - bot: result.data.bot, - }; - const values = Object.values(kind0fields).filter((value) => value !== undefined); - let event: NostrEvent; + const event = await updateEvent( + { kinds: [0], authors: [pubkey], limit: 1 }, + async (prev) => { + const meta = n.json().pipe(metadataSchema).catch({}).parse(prev.content); + const { + avatar: avatarFile, + header: headerFile, + display_name, + fields_attributes, + note, + nip05, + lud16, + website, + bot, + } = result.data; - if (values.length) { - event = await updateEvent( - { kinds: [0], authors: [pubkey], limit: 1 }, - async (prev) => { - const meta = n.json().pipe(metadataSchema).catch({}).parse(prev.content); - const { - avatar: avatarFile, - header: headerFile, - display_name, - fields_attributes, - note, - nip05, - lud16, - website, - bot, - } = kind0fields; + const [avatar, header] = await Promise.all([ + avatarFile ? uploadFile(c, avatarFile, { pubkey }) : undefined, + headerFile ? uploadFile(c, headerFile, { pubkey }) : undefined, + ]); - const [avatar, header] = await Promise.all([ - avatarFile ? uploadFile(c, avatarFile, { pubkey }) : undefined, - headerFile ? uploadFile(c, headerFile, { pubkey }) : undefined, - ]); + meta.name = display_name ?? meta.name; + meta.about = note ?? meta.about; + meta.picture = avatar?.url ?? meta.picture; + meta.banner = header?.url ?? meta.banner; + meta.nip05 = nip05 ?? meta.nip05; + meta.lud16 = lud16 ?? meta.lud16; + meta.website = website ?? meta.website; + meta.bot = bot ?? meta.bot; - meta.name = display_name ?? meta.name; - meta.about = note ?? meta.about; - meta.picture = avatar?.url ?? meta.picture; - meta.banner = header?.url ?? meta.banner; - meta.nip05 = nip05 ?? meta.nip05; - meta.lud16 = lud16 ?? meta.lud16; - meta.website = website ?? meta.website; - meta.bot = bot ?? meta.bot; + if (avatarFile === '') delete meta.picture; + if (headerFile === '') delete meta.banner; + if (nip05 === '') delete meta.nip05; + if (lud16 === '') delete meta.lud16; + if (website === '') delete meta.website; - if (avatarFile === '') delete meta.picture; - if (headerFile === '') delete meta.banner; - if (nip05 === '') delete meta.nip05; - if (lud16 === '') delete meta.lud16; - if (website === '') delete meta.website; + if (fields_attributes) { + meta.fields = fields_attributes.map(({ name, value }) => [name, value]); + } - if (fields_attributes) { - meta.fields = fields_attributes.map(({ name, value }) => [name, value]); - } - - return { - kind: 0, - content: JSON.stringify(meta), - tags: [], - }; - }, - c, - ); - } else { - [event] = await store.query([{ kinds: [0], authors: [pubkey] }]); - } + return { + kind: 0, + content: JSON.stringify(meta), + tags: [], + }; + }, + c, + ); const settingsStore = result.data.pleroma_settings_store; const account = await renderAccount(event, { withSource: true, settingsStore }); From 30d7f1a053eee037147e5e6a9dcfb7a53ead0ee1 Mon Sep 17 00:00:00 2001 From: "P. Reis" Date: Tue, 3 Dec 2024 14:33:04 -0300 Subject: [PATCH 3/5] refactor(updateCredentialsController): stop overwriting kind 0 unnecessarily --- src/controllers/api/accounts.ts | 96 ++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 44 deletions(-) diff --git a/src/controllers/api/accounts.ts b/src/controllers/api/accounts.ts index d5beac03..ba8590a4 100644 --- a/src/controllers/api/accounts.ts +++ b/src/controllers/api/accounts.ts @@ -1,4 +1,4 @@ -import { NostrFilter, NSchema as n } from '@nostrify/nostrify'; +import { NostrEvent, NostrFilter, NSchema as n } from '@nostrify/nostrify'; import { nip19 } from 'nostr-tools'; import { z } from 'zod'; @@ -288,59 +288,67 @@ const updateCredentialsController: AppController = async (c) => { const pubkey = await signer.getPublicKey(); const body = await parseBody(c.req.raw); const result = updateCredentialsSchema.safeParse(body); + const store = await Storages.db(); if (!result.success) { return c.json(result.error, 422); } - const event = await updateEvent( - { kinds: [0], authors: [pubkey], limit: 1 }, - async (prev) => { - const meta = n.json().pipe(metadataSchema).catch({}).parse(prev.content); - const { - avatar: avatarFile, - header: headerFile, - display_name, - fields_attributes, - note, - nip05, - lud16, - website, - bot, - } = result.data; + const keys = Object.keys(result.data); + let event: NostrEvent; - const [avatar, header] = await Promise.all([ - avatarFile ? uploadFile(c, avatarFile, { pubkey }) : undefined, - headerFile ? uploadFile(c, headerFile, { pubkey }) : undefined, - ]); + if (keys.length === 1 && keys[0] === 'pleroma_settings_store') { + event = (await store.query([{ kinds: [0], authors: [pubkey] }]))[0]; + } else { + event = await updateEvent( + { kinds: [0], authors: [pubkey], limit: 1 }, + async (prev) => { + const meta = n.json().pipe(metadataSchema).catch({}).parse(prev.content); + const { + avatar: avatarFile, + header: headerFile, + display_name, + fields_attributes, + note, + nip05, + lud16, + website, + bot, + } = result.data; - meta.name = display_name ?? meta.name; - meta.about = note ?? meta.about; - meta.picture = avatar?.url ?? meta.picture; - meta.banner = header?.url ?? meta.banner; - meta.nip05 = nip05 ?? meta.nip05; - meta.lud16 = lud16 ?? meta.lud16; - meta.website = website ?? meta.website; - meta.bot = bot ?? meta.bot; + const [avatar, header] = await Promise.all([ + avatarFile ? uploadFile(c, avatarFile, { pubkey }) : undefined, + headerFile ? uploadFile(c, headerFile, { pubkey }) : undefined, + ]); - if (avatarFile === '') delete meta.picture; - if (headerFile === '') delete meta.banner; - if (nip05 === '') delete meta.nip05; - if (lud16 === '') delete meta.lud16; - if (website === '') delete meta.website; + meta.name = display_name ?? meta.name; + meta.about = note ?? meta.about; + meta.picture = avatar?.url ?? meta.picture; + meta.banner = header?.url ?? meta.banner; + meta.nip05 = nip05 ?? meta.nip05; + meta.lud16 = lud16 ?? meta.lud16; + meta.website = website ?? meta.website; + meta.bot = bot ?? meta.bot; - if (fields_attributes) { - meta.fields = fields_attributes.map(({ name, value }) => [name, value]); - } + if (avatarFile === '') delete meta.picture; + if (headerFile === '') delete meta.banner; + if (nip05 === '') delete meta.nip05; + if (lud16 === '') delete meta.lud16; + if (website === '') delete meta.website; - return { - kind: 0, - content: JSON.stringify(meta), - tags: [], - }; - }, - c, - ); + if (fields_attributes) { + meta.fields = fields_attributes.map(({ name, value }) => [name, value]); + } + + return { + kind: 0, + content: JSON.stringify(meta), + tags: [], + }; + }, + c, + ); + } const settingsStore = result.data.pleroma_settings_store; const account = await renderAccount(event, { withSource: true, settingsStore }); From dfff24d3b2783821627a66ee3bac470d3997902d Mon Sep 17 00:00:00 2001 From: "P. Reis" Date: Tue, 3 Dec 2024 15:22:37 -0300 Subject: [PATCH 4/5] refactor(updateCredentialsController): return error if event is undefined --- src/controllers/api/accounts.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/controllers/api/accounts.ts b/src/controllers/api/accounts.ts index ba8590a4..3dc1e815 100644 --- a/src/controllers/api/accounts.ts +++ b/src/controllers/api/accounts.ts @@ -295,7 +295,7 @@ const updateCredentialsController: AppController = async (c) => { } const keys = Object.keys(result.data); - let event: NostrEvent; + let event: NostrEvent | undefined; if (keys.length === 1 && keys[0] === 'pleroma_settings_store') { event = (await store.query([{ kinds: [0], authors: [pubkey] }]))[0]; @@ -350,6 +350,10 @@ const updateCredentialsController: AppController = async (c) => { ); } + if (!event) { + return c.json({ error: 'Account not found.' }, 400); + } + const settingsStore = result.data.pleroma_settings_store; const account = await renderAccount(event, { withSource: true, settingsStore }); From 2b6bf125e19e7ea63e074002526c90b269b3f37d Mon Sep 17 00:00:00 2001 From: "P. Reis" Date: Tue, 3 Dec 2024 18:23:13 -0300 Subject: [PATCH 5/5] refactor(updateCredentialsController): accountFromPubkey if the user has no kind 0 --- src/controllers/api/accounts.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/controllers/api/accounts.ts b/src/controllers/api/accounts.ts index 3dc1e815..3e054581 100644 --- a/src/controllers/api/accounts.ts +++ b/src/controllers/api/accounts.ts @@ -20,6 +20,7 @@ import { hydrateEvents } from '@/storages/hydrate.ts'; import { bech32ToPubkey } from '@/utils.ts'; import { addTag, deleteTag, findReplyTag, getTagSet } from '@/utils/tags.ts'; import { getPubkeysBySearch } from '@/utils/search.ts'; +import { MastodonAccount } from '@/entities/MastodonAccount.ts'; const usernameSchema = z .string().min(1).max(30) @@ -350,12 +351,14 @@ const updateCredentialsController: AppController = async (c) => { ); } - if (!event) { - return c.json({ error: 'Account not found.' }, 400); - } - const settingsStore = result.data.pleroma_settings_store; - const account = await renderAccount(event, { withSource: true, settingsStore }); + + let account: MastodonAccount; + if (event) { + account = await renderAccount(event, { withSource: true, settingsStore }); + } else { + account = await accountFromPubkey(pubkey, { withSource: true, settingsStore }); + } if (settingsStore) { await createEvent({