mirror of
https://github.com/aljazceru/ditto.git
synced 2026-01-30 18:44:20 +01:00
Merge remote-tracking branch 'origin/main' into tag-queries
This commit is contained in:
@@ -1,14 +1,18 @@
|
||||
import { NostrEvent, NostrFilter } from '@nostrify/nostrify';
|
||||
import { NostrEvent, NostrFilter, NSchema as n } from '@nostrify/nostrify';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { AppController } from '@/app.ts';
|
||||
import { Conf } from '@/config.ts';
|
||||
import { booleanParamSchema } from '@/schema.ts';
|
||||
import { AdminSigner } from '@/signers/AdminSigner.ts';
|
||||
import { booleanParamSchema } from '@/schema.ts';
|
||||
import { Conf } from '@/config.ts';
|
||||
import { Storages } from '@/storages.ts';
|
||||
import { hydrateEvents } from '@/storages/hydrate.ts';
|
||||
import { createEvent, paginated, paginationSchema } from '@/utils/api.ts';
|
||||
import { createEvent, paginated, paginationSchema, parseBody } from '@/utils/api.ts';
|
||||
import { renderNameRequest } from '@/views/ditto.ts';
|
||||
import { getZapSplits } from '@/utils/zap-split.ts';
|
||||
import { updateListAdminEvent } from '@/utils/api.ts';
|
||||
import { addTag } from '@/utils/tags.ts';
|
||||
import { deleteTag } from '@/utils/tags.ts';
|
||||
|
||||
const markerSchema = z.enum(['read', 'write']);
|
||||
|
||||
@@ -148,3 +152,74 @@ export const nameRequestsController: AppController = async (c) => {
|
||||
|
||||
return paginated(c, orig, nameRequests);
|
||||
};
|
||||
|
||||
const zapSplitSchema = z.record(
|
||||
n.id(),
|
||||
z.object({
|
||||
amount: z.number().int().min(1).max(100),
|
||||
message: z.string().max(500),
|
||||
}),
|
||||
);
|
||||
|
||||
export const updateZapSplitsController: AppController = async (c) => {
|
||||
const body = await parseBody(c.req.raw);
|
||||
const result = zapSplitSchema.safeParse(body);
|
||||
const store = c.get('store');
|
||||
|
||||
if (!result.success) {
|
||||
return c.json({ error: result.error }, 400);
|
||||
}
|
||||
|
||||
const zap_split = await getZapSplits(store, Conf.pubkey);
|
||||
if (!zap_split) {
|
||||
return c.json({ error: 'Zap split not activated, restart the server.' }, 404);
|
||||
}
|
||||
|
||||
const { data } = result;
|
||||
const pubkeys = Object.keys(data);
|
||||
|
||||
if (pubkeys.length < 1) {
|
||||
return c.json(200);
|
||||
}
|
||||
|
||||
await updateListAdminEvent(
|
||||
{ kinds: [30078], authors: [Conf.pubkey], '#d': ['pub.ditto.zapSplits'], limit: 1 },
|
||||
(tags) =>
|
||||
pubkeys.reduce((accumulator, pubkey) => {
|
||||
return addTag(accumulator, ['p', pubkey, data[pubkey].amount.toString(), data[pubkey].message]);
|
||||
}, tags),
|
||||
c,
|
||||
);
|
||||
|
||||
return c.json(200);
|
||||
};
|
||||
|
||||
const deleteZapSplitSchema = z.array(n.id()).min(1);
|
||||
|
||||
export const deleteZapSplitsController: AppController = async (c) => {
|
||||
const body = await parseBody(c.req.raw);
|
||||
const result = deleteZapSplitSchema.safeParse(body);
|
||||
const store = c.get('store');
|
||||
|
||||
if (!result.success) {
|
||||
return c.json({ error: result.error }, 400);
|
||||
}
|
||||
|
||||
const zap_split = await getZapSplits(store, Conf.pubkey);
|
||||
if (!zap_split) {
|
||||
return c.json({ error: 'Zap split not activated, restart the server.' }, 404);
|
||||
}
|
||||
|
||||
const { data } = result;
|
||||
|
||||
await updateListAdminEvent(
|
||||
{ kinds: [30078], authors: [Conf.pubkey], '#d': ['pub.ditto.zapSplits'], limit: 1 },
|
||||
(tags) =>
|
||||
data.reduce((accumulator, currentValue) => {
|
||||
return deleteTag(accumulator, ['p', currentValue]);
|
||||
}, tags),
|
||||
c,
|
||||
);
|
||||
|
||||
return c.json(200);
|
||||
};
|
||||
|
||||
@@ -4,12 +4,16 @@ import { AppController } from '@/app.ts';
|
||||
import { Conf } from '@/config.ts';
|
||||
import { Storages } from '@/storages.ts';
|
||||
import { getInstanceMetadata } from '@/utils/instance.ts';
|
||||
import { DittoZapSplits, getZapSplits } from '@/utils/zap-split.ts';
|
||||
|
||||
const version = `3.0.0 (compatible; Ditto ${denoJson.version})`;
|
||||
|
||||
const instanceV1Controller: AppController = async (c) => {
|
||||
const { host, protocol } = Conf.url;
|
||||
const meta = await getInstanceMetadata(await Storages.db(), c.req.raw.signal);
|
||||
const store = c.get('store');
|
||||
|
||||
const zap_split: DittoZapSplits | undefined = await getZapSplits(store, Conf.pubkey) ?? {};
|
||||
|
||||
/** Protocol to use for WebSocket URLs, depending on the protocol of the `LOCAL_DOMAIN`. */
|
||||
const wsProtocol = protocol === 'http:' ? 'ws:' : 'wss:';
|
||||
@@ -68,6 +72,9 @@ const instanceV1Controller: AppController = async (c) => {
|
||||
},
|
||||
},
|
||||
rules: [],
|
||||
ditto: {
|
||||
zap_split,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -6,10 +6,15 @@ import { nip19 } from 'nostr-tools';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { type AppController } from '@/app.ts';
|
||||
import { accountFromPubkey, renderAccount } from '@/views/mastodon/accounts.ts';
|
||||
import { addTag, deleteTag } from '@/utils/tags.ts';
|
||||
import { asyncReplaceAll } from '@/utils/text.ts';
|
||||
import { Conf } from '@/config.ts';
|
||||
import { DittoDB } from '@/db/DittoDB.ts';
|
||||
import { DittoEvent } from '@/interfaces/DittoEvent.ts';
|
||||
import { getAncestors, getAuthor, getDescendants, getEvent } from '@/queries.ts';
|
||||
import { getUnattachedMediaByIds } from '@/db/unattached-media.ts';
|
||||
import { lookupPubkey } from '@/utils/lookup.ts';
|
||||
import { renderEventAccounts } from '@/views.ts';
|
||||
import { renderReblog, renderStatus } from '@/views/mastodon/statuses.ts';
|
||||
import { Storages } from '@/storages.ts';
|
||||
@@ -24,11 +29,7 @@ import {
|
||||
updateListEvent,
|
||||
} from '@/utils/api.ts';
|
||||
import { getInvoice, getLnurl } from '@/utils/lnurl.ts';
|
||||
import { lookupPubkey } from '@/utils/lookup.ts';
|
||||
import { addTag, deleteTag } from '@/utils/tags.ts';
|
||||
import { asyncReplaceAll } from '@/utils/text.ts';
|
||||
import { DittoEvent } from '@/interfaces/DittoEvent.ts';
|
||||
import { accountFromPubkey, renderAccount } from '@/views/mastodon/accounts.ts';
|
||||
import { getZapSplits } from '@/utils/zap-split.ts';
|
||||
|
||||
const createStatusSchema = z.object({
|
||||
in_reply_to_id: n.id().nullish(),
|
||||
@@ -71,6 +72,7 @@ const createStatusController: AppController = async (c) => {
|
||||
const body = await parseBody(c.req.raw);
|
||||
const result = createStatusSchema.safeParse(body);
|
||||
const kysely = await DittoDB.getInstance();
|
||||
const store = c.get('store');
|
||||
|
||||
if (!result.success) {
|
||||
return c.json({ error: 'Bad request', schema: result.error }, 400);
|
||||
@@ -173,14 +175,28 @@ const createStatusController: AppController = async (c) => {
|
||||
const quoteCompat = data.quote_id ? `\n\nnostr:${nip19.noteEncode(data.quote_id)}` : '';
|
||||
const mediaCompat = mediaUrls.length ? `\n\n${mediaUrls.join('\n')}` : '';
|
||||
|
||||
const author = await getAuthor(await c.get('signer')?.getPublicKey()!);
|
||||
|
||||
const meta = n.json().pipe(n.metadata()).catch({}).parse(author?.content);
|
||||
const lnurl = getLnurl(meta);
|
||||
const zap_split = await getZapSplits(store, Conf.pubkey);
|
||||
if (lnurl && zap_split) {
|
||||
let totalSplit = 0;
|
||||
for (const pubkey in zap_split) {
|
||||
totalSplit += zap_split[pubkey].amount;
|
||||
tags.push(['zap', pubkey, Conf.relay, zap_split[pubkey].amount.toString()]);
|
||||
}
|
||||
if (totalSplit) {
|
||||
tags.push(['zap', author?.pubkey as string, Conf.relay, Math.max(0, 100 - totalSplit).toString()]);
|
||||
}
|
||||
}
|
||||
|
||||
const event = await createEvent({
|
||||
kind: 1,
|
||||
content: content + quoteCompat + mediaCompat,
|
||||
tags,
|
||||
}, c);
|
||||
|
||||
const author = await getAuthor(event.pubkey);
|
||||
|
||||
if (data.quote_id) {
|
||||
await hydrateEvents({
|
||||
events: [event],
|
||||
@@ -189,7 +205,7 @@ const createStatusController: AppController = async (c) => {
|
||||
});
|
||||
}
|
||||
|
||||
return c.json(await renderStatus({ ...event, author }, { viewerPubkey: await c.get('signer')?.getPublicKey() }));
|
||||
return c.json(await renderStatus({ ...event, author }, { viewerPubkey: author?.pubkey }));
|
||||
};
|
||||
|
||||
const deleteStatusController: AppController = async (c) => {
|
||||
|
||||
Reference in New Issue
Block a user