Create `updateListEvent` helper function

This commit is contained in:
Alex Gleason 2023-12-31 20:13:30 -06:00
parent 335f7dc281
commit dc27ee05d4
No known key found for this signature in database
GPG Key ID: 7211D1F99744FBB7
4 changed files with 35 additions and 16 deletions

View File

@ -7,9 +7,10 @@ import { type DittoFilter } from '@/filter.ts';
import { getAuthor, getFollowedPubkeys, getFollows } from '@/queries.ts'; import { getAuthor, getFollowedPubkeys, getFollows } from '@/queries.ts';
import { booleanParamSchema, fileSchema } from '@/schema.ts'; import { booleanParamSchema, fileSchema } from '@/schema.ts';
import { jsonMetaContentSchema } from '@/schemas/nostr.ts'; import { jsonMetaContentSchema } from '@/schemas/nostr.ts';
import { setTag } from '@/tags.ts';
import { uploadFile } from '@/upload.ts'; import { uploadFile } from '@/upload.ts';
import { isFollowing, lookupAccount, nostrNow } from '@/utils.ts'; import { isFollowing, lookupAccount, nostrNow } from '@/utils.ts';
import { paginated, paginationSchema, parseBody } from '@/utils/web.ts'; import { paginated, paginationSchema, parseBody, updateListEvent } from '@/utils/web.ts';
import { createEvent } from '@/utils/web.ts'; import { createEvent } from '@/utils/web.ts';
import { renderEventAccounts } from '@/views.ts'; import { renderEventAccounts } from '@/views.ts';
import { accountFromPubkey, renderAccount } from '@/views/mastodon/accounts.ts'; import { accountFromPubkey, renderAccount } from '@/views/mastodon/accounts.ts';
@ -219,14 +220,12 @@ const followController: AppController = async (c) => {
const source = await getFollows(sourcePubkey); const source = await getFollows(sourcePubkey);
if (!source || !isFollowing(source, targetPubkey)) { if (!source || !isFollowing(source, targetPubkey)) {
await createEvent({ await updateListEvent(
kind: 3, source ?? { kind: 3 },
content: '',
tags: [
...(source?.tags ?? []),
['p', targetPubkey], ['p', targetPubkey],
], setTag,
}, c); c,
);
} }
const relationship = await renderRelationship(sourcePubkey, targetPubkey); const relationship = await renderRelationship(sourcePubkey, targetPubkey);

View File

@ -11,6 +11,11 @@ function getTagSet(tags: string[][], tagName: string): Set<string> {
return set; return set;
} }
/** Check if the tag exists by its name and value. */
function hasTag(tags: string[][], tag: string[]): boolean {
return tags.some(([name, value]) => name === tag[0] && value === tag[1]);
}
/** Delete all occurences of the tag by its name/value pair. */ /** Delete all occurences of the tag by its name/value pair. */
function deleteTag(tags: readonly string[][], tag: string[]): string[][] { function deleteTag(tags: readonly string[][], tag: string[]): string[][] {
return tags.filter(([name, value]) => !(name === tag[0] && value === tag[1])); return tags.filter(([name, value]) => !(name === tag[0] && value === tag[1]));
@ -26,4 +31,4 @@ function setTag(tags: readonly string[][], tag: string[]): string[][] {
} }
} }
export { deleteTag, getTagSet, setTag }; export { deleteTag, getTagSet, hasTag, setTag };

View File

@ -1,5 +1,6 @@
import { type Event, type EventTemplate, getEventHash, nip19, z } from '@/deps.ts'; import { type Event, type EventTemplate, getEventHash, nip19, z } from '@/deps.ts';
import { getAuthor } from '@/queries.ts'; import { getAuthor } from '@/queries.ts';
import { hasTag } from '@/tags.ts';
import { lookupNip05Cached } from '@/utils/nip05.ts'; import { lookupNip05Cached } from '@/utils/nip05.ts';
import { nostrIdSchema } from '@/schemas/nostr.ts'; import { nostrIdSchema } from '@/schemas/nostr.ts';
@ -97,9 +98,7 @@ const isRelay = (relay: string): relay is `wss://${string}` => relaySchema.safeP
/** Check whether source is following target. */ /** Check whether source is following target. */
function isFollowing(source: Event<3>, targetPubkey: string): boolean { function isFollowing(source: Event<3>, targetPubkey: string): boolean {
return Boolean( return hasTag(source.tags, ['p', targetPubkey]);
source.tags.find(([tagName, tagValue]) => tagName === 'p' && tagValue === targetPubkey),
);
} }
/** Deduplicate events by ID. */ /** Deduplicate events by ID. */

View File

@ -1,13 +1,12 @@
import { type AppContext } from '@/app.ts';
import { Conf } from '@/config.ts'; import { Conf } from '@/config.ts';
import { type Context, type Event, EventTemplate, HTTPException, parseFormData, type TypeFest, z } from '@/deps.ts'; import { type Context, type Event, EventTemplate, HTTPException, parseFormData, type TypeFest, z } from '@/deps.ts';
import * as pipeline from '@/pipeline.ts'; import * as pipeline from '@/pipeline.ts';
import { signAdminEvent, signEvent } from '@/sign.ts'; import { signAdminEvent, signEvent } from '@/sign.ts';
import { nostrNow } from '@/utils.ts'; import { nostrNow } from '@/utils.ts';
import type { AppContext } from '@/app.ts';
/** EventTemplate with defaults. */ /** EventTemplate with defaults. */
type EventStub<K extends number = number> = TypeFest.SetOptional<EventTemplate<K>, 'created_at' | 'tags'>; type EventStub<K extends number = number> = TypeFest.SetOptional<EventTemplate<K>, 'content' | 'created_at' | 'tags'>;
/** Publish an event through the pipeline. */ /** Publish an event through the pipeline. */
async function createEvent<K extends number>(t: EventStub<K>, c: AppContext): Promise<Event<K>> { async function createEvent<K extends number>(t: EventStub<K>, c: AppContext): Promise<Event<K>> {
@ -18,6 +17,7 @@ async function createEvent<K extends number>(t: EventStub<K>, c: AppContext): Pr
} }
const event = await signEvent({ const event = await signEvent({
content: '',
created_at: nostrNow(), created_at: nostrNow(),
tags: [], tags: [],
...t, ...t,
@ -26,9 +26,24 @@ async function createEvent<K extends number>(t: EventStub<K>, c: AppContext): Pr
return publishEvent(event, c); return publishEvent(event, c);
} }
/** Add the tag to the list and then publish the new list, or throw if the tag already exists. */
function updateListEvent<K extends number, E extends EventStub<K>>(
t: E,
tag: string[],
fn: (tags: string[][], tag: string[]) => string[][],
c: AppContext,
): Promise<Event<K>> {
const { kind, content, tags = [] } = t;
return createEvent(
{ kind, content, tags: fn(tags, tag) },
c,
);
}
/** Publish an admin event through the pipeline. */ /** Publish an admin event through the pipeline. */
async function createAdminEvent<K extends number>(t: EventStub<K>, c: AppContext): Promise<Event<K>> { async function createAdminEvent<K extends number>(t: EventStub<K>, c: AppContext): Promise<Event<K>> {
const event = await signAdminEvent({ const event = await signAdminEvent({
content: '',
created_at: nostrNow(), created_at: nostrNow(),
tags: [], tags: [],
...t, ...t,
@ -139,4 +154,5 @@ export {
type PaginationParams, type PaginationParams,
paginationSchema, paginationSchema,
parseBody, parseBody,
updateListEvent,
}; };