Add preliminary nameRequestsController
This commit is contained in:
parent
a14515bbe0
commit
bd6424acf5
|
@ -30,7 +30,7 @@ import { adminAccountsController, adminActionController } from '@/controllers/ap
|
||||||
import { appCredentialsController, createAppController } from '@/controllers/api/apps.ts';
|
import { appCredentialsController, createAppController } from '@/controllers/api/apps.ts';
|
||||||
import { blocksController } from '@/controllers/api/blocks.ts';
|
import { blocksController } from '@/controllers/api/blocks.ts';
|
||||||
import { bookmarksController } from '@/controllers/api/bookmarks.ts';
|
import { bookmarksController } from '@/controllers/api/bookmarks.ts';
|
||||||
import { adminRelaysController, adminSetRelaysController, inviteRequestController } from '@/controllers/api/ditto.ts';
|
import { adminRelaysController, adminSetRelaysController, nameRequestController } from '@/controllers/api/ditto.ts';
|
||||||
import { emptyArrayController, emptyObjectController, notImplementedController } from '@/controllers/api/fallback.ts';
|
import { emptyArrayController, emptyObjectController, notImplementedController } from '@/controllers/api/fallback.ts';
|
||||||
import { instanceController } from '@/controllers/api/instance.ts';
|
import { instanceController } from '@/controllers/api/instance.ts';
|
||||||
import { markersController, updateMarkersController } from '@/controllers/api/markers.ts';
|
import { markersController, updateMarkersController } from '@/controllers/api/markers.ts';
|
||||||
|
@ -243,7 +243,7 @@ app.delete('/api/v1/pleroma/admin/statuses/:id', requireRole('admin'), pleromaAd
|
||||||
app.get('/api/v1/admin/ditto/relays', requireRole('admin'), adminRelaysController);
|
app.get('/api/v1/admin/ditto/relays', requireRole('admin'), adminRelaysController);
|
||||||
app.put('/api/v1/admin/ditto/relays', requireRole('admin'), adminSetRelaysController);
|
app.put('/api/v1/admin/ditto/relays', requireRole('admin'), adminSetRelaysController);
|
||||||
|
|
||||||
app.post('/api/v1/ditto/nip05', requireSigner, inviteRequestController);
|
app.post('/api/v1/ditto/names', requireSigner, nameRequestController);
|
||||||
app.post('/api/v1/ditto/zap', requireSigner, zapController);
|
app.post('/api/v1/ditto/zap', requireSigner, zapController);
|
||||||
|
|
||||||
app.post('/api/v1/reports', requireSigner, reportController);
|
app.post('/api/v1/reports', requireSigner, reportController);
|
||||||
|
|
|
@ -3,9 +3,11 @@ import { z } from 'zod';
|
||||||
|
|
||||||
import { AppController } from '@/app.ts';
|
import { AppController } from '@/app.ts';
|
||||||
import { Conf } from '@/config.ts';
|
import { Conf } from '@/config.ts';
|
||||||
import { Storages } from '@/storages.ts';
|
|
||||||
import { AdminSigner } from '@/signers/AdminSigner.ts';
|
import { AdminSigner } from '@/signers/AdminSigner.ts';
|
||||||
|
import { Storages } from '@/storages.ts';
|
||||||
|
import { hydrateEvents } from '@/storages/hydrate.ts';
|
||||||
import { createEvent } from '@/utils/api.ts';
|
import { createEvent } from '@/utils/api.ts';
|
||||||
|
import { renderNameRequest } from '@/views/ditto.ts';
|
||||||
|
|
||||||
const markerSchema = z.enum(['read', 'write']);
|
const markerSchema = z.enum(['read', 'write']);
|
||||||
|
|
||||||
|
@ -60,15 +62,15 @@ function renderRelays(event: NostrEvent): RelayEntity[] {
|
||||||
}, [] as RelayEntity[]);
|
}, [] as RelayEntity[]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const inviteRequestSchema = z.object({
|
const nameRequestSchema = z.object({
|
||||||
nip05: z.string().email(),
|
nip05: z.string().email(),
|
||||||
reason: z.string().max(500).optional(),
|
reason: z.string().max(500).optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const inviteRequestController: AppController = async (c) => {
|
export const nameRequestController: AppController = async (c) => {
|
||||||
const { nip05, reason } = inviteRequestSchema.parse(await c.req.json());
|
const { nip05, reason } = nameRequestSchema.parse(await c.req.json());
|
||||||
|
|
||||||
await createEvent({
|
const event = await createEvent({
|
||||||
kind: 3036,
|
kind: 3036,
|
||||||
content: reason,
|
content: reason,
|
||||||
tags: [
|
tags: [
|
||||||
|
@ -79,5 +81,20 @@ export const inviteRequestController: AppController = async (c) => {
|
||||||
],
|
],
|
||||||
}, c);
|
}, c);
|
||||||
|
|
||||||
return new Response(null, { status: 204 });
|
await hydrateEvents({ events: [event], store: await Storages.db() });
|
||||||
|
|
||||||
|
const nameRequest = await renderNameRequest(event);
|
||||||
|
return c.json(nameRequest);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const nameRequestsController: AppController = async (c) => {
|
||||||
|
const store = await Storages.db();
|
||||||
|
const signer = c.get('signer')!;
|
||||||
|
const pubkey = await signer.getPublicKey();
|
||||||
|
|
||||||
|
const events = await store.query([{ kinds: [3036], authors: [pubkey], limit: 20 }])
|
||||||
|
.then((events) => hydrateEvents({ events, store }));
|
||||||
|
|
||||||
|
const nameRequests = await Promise.all(events.map(renderNameRequest));
|
||||||
|
return c.json(nameRequests);
|
||||||
};
|
};
|
||||||
|
|
|
@ -34,4 +34,6 @@ export interface DittoEvent extends NostrEvent {
|
||||||
* https://github.com/nostr-protocol/nips/blob/master/56.md
|
* https://github.com/nostr-protocol/nips/blob/master/56.md
|
||||||
*/
|
*/
|
||||||
reported_notes?: DittoEvent[];
|
reported_notes?: DittoEvent[];
|
||||||
|
/** Admin event relationship. */
|
||||||
|
info?: DittoEvent;
|
||||||
}
|
}
|
||||||
|
|
|
@ -212,7 +212,7 @@ async function generateSetEvents(event: NostrEvent): Promise<void> {
|
||||||
['d', event.id],
|
['d', event.id],
|
||||||
['p', event.pubkey],
|
['p', event.pubkey],
|
||||||
['k', '3036'],
|
['k', '3036'],
|
||||||
['n', 'open'],
|
['n', 'pending'],
|
||||||
],
|
],
|
||||||
created_at: Math.floor(Date.now() / 1000),
|
created_at: Math.floor(Date.now() / 1000),
|
||||||
});
|
});
|
||||||
|
|
|
@ -44,6 +44,10 @@ async function hydrateEvents(opts: HydrateOpts): Promise<DittoEvent[]> {
|
||||||
cache.push(event);
|
cache.push(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const event of await gatherInfo({ events: cache, store, signal })) {
|
||||||
|
cache.push(event);
|
||||||
|
}
|
||||||
|
|
||||||
for (const event of await gatherReportedProfiles({ events: cache, store, signal })) {
|
for (const event of await gatherReportedProfiles({ events: cache, store, signal })) {
|
||||||
cache.push(event);
|
cache.push(event);
|
||||||
}
|
}
|
||||||
|
@ -83,6 +87,7 @@ export function assembleEvents(
|
||||||
for (const event of a) {
|
for (const event of a) {
|
||||||
event.author = b.find((e) => matchFilter({ kinds: [0], authors: [event.pubkey] }, e));
|
event.author = b.find((e) => matchFilter({ kinds: [0], authors: [event.pubkey] }, e));
|
||||||
event.user = b.find((e) => matchFilter({ kinds: [30382], authors: [admin], '#d': [event.pubkey] }, e));
|
event.user = b.find((e) => matchFilter({ kinds: [30382], authors: [admin], '#d': [event.pubkey] }, e));
|
||||||
|
event.info = b.find((e) => matchFilter({ kinds: [30383], authors: [admin], '#d': [event.id] }, e));
|
||||||
|
|
||||||
if (event.kind === 1) {
|
if (event.kind === 1) {
|
||||||
const id = findQuoteTag(event.tags)?.[1] || findQuoteInContent(event.content);
|
const id = findQuoteTag(event.tags)?.[1] || findQuoteInContent(event.content);
|
||||||
|
@ -106,20 +111,21 @@ export function assembleEvents(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.kind === 1984) {
|
if (event.kind === 1984) {
|
||||||
const targetAccountId = event.tags.find(([name]) => name === 'p')?.[1];
|
const pubkey = event.tags.find(([name]) => name === 'p')?.[1];
|
||||||
if (targetAccountId) {
|
if (pubkey) {
|
||||||
event.reported_profile = b.find((e) => matchFilter({ kinds: [0], authors: [targetAccountId] }, e));
|
event.reported_profile = b.find((e) => matchFilter({ kinds: [0], authors: [pubkey] }, e));
|
||||||
}
|
}
|
||||||
const reportedEvents: DittoEvent[] = [];
|
|
||||||
|
|
||||||
const status_ids = event.tags.filter(([name]) => name === 'e').map((tag) => tag[1]);
|
const reportedEvents: DittoEvent[] = [];
|
||||||
if (status_ids.length > 0) {
|
const ids = event.tags.filter(([name]) => name === 'e').map(([_name, value]) => value);
|
||||||
for (const id of status_ids) {
|
|
||||||
const reportedEvent = b.find((e) => matchFilter({ kinds: [1], ids: [id] }, e));
|
for (const id of ids) {
|
||||||
if (reportedEvent) reportedEvents.push(reportedEvent);
|
const reported = b.find((e) => matchFilter({ kinds: [1], ids: [id] }, e));
|
||||||
|
if (reported) {
|
||||||
|
reportedEvents.push(reported);
|
||||||
}
|
}
|
||||||
event.reported_notes = reportedEvents;
|
|
||||||
}
|
}
|
||||||
|
event.reported_notes = reportedEvents;
|
||||||
}
|
}
|
||||||
|
|
||||||
event.author_stats = stats.authors.find((stats) => stats.pubkey === event.pubkey);
|
event.author_stats = stats.authors.find((stats) => stats.pubkey === event.pubkey);
|
||||||
|
@ -206,6 +212,26 @@ function gatherUsers({ events, store, signal }: HydrateOpts): Promise<DittoEvent
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Collect info events from the events. */
|
||||||
|
function gatherInfo({ events, store, signal }: HydrateOpts): Promise<DittoEvent[]> {
|
||||||
|
const ids = new Set<string>();
|
||||||
|
|
||||||
|
for (const event of events) {
|
||||||
|
if (event.kind === 3036) {
|
||||||
|
ids.add(event.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ids.size) {
|
||||||
|
return Promise.resolve([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return store.query(
|
||||||
|
[{ ids: [...ids], limit: ids.size }],
|
||||||
|
{ signal },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/** Collect reported notes from the events. */
|
/** Collect reported notes from the events. */
|
||||||
function gatherReportedNotes({ events, store, signal }: HydrateOpts): Promise<DittoEvent[]> {
|
function gatherReportedNotes({ events, store, signal }: HydrateOpts): Promise<DittoEvent[]> {
|
||||||
const ids = new Set<string>();
|
const ids = new Set<string>();
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { DittoEvent } from '@/interfaces/DittoEvent.ts';
|
||||||
|
import { accountFromPubkey, renderAccount } from '@/views/mastodon/accounts.ts';
|
||||||
|
import { getTagSet } from '@/utils/tags.ts';
|
||||||
|
|
||||||
|
export async function renderNameRequest(event: DittoEvent) {
|
||||||
|
const n = getTagSet(event.info?.tags ?? [], 'n');
|
||||||
|
|
||||||
|
let approvalStatus = 'pending';
|
||||||
|
|
||||||
|
if (n.has('approved')) {
|
||||||
|
approvalStatus = 'approved';
|
||||||
|
}
|
||||||
|
if (n.has('rejected')) {
|
||||||
|
approvalStatus = 'rejected';
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: event.id,
|
||||||
|
account: event.author ? await renderAccount(event.author) : accountFromPubkey(event.pubkey),
|
||||||
|
name: event.tags.find(([name]) => name === 'r')?.[1] || '',
|
||||||
|
reason: event.content,
|
||||||
|
approval_status: approvalStatus,
|
||||||
|
created_at: new Date(event.created_at * 1000).toISOString(),
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue