From 0f3fbbcb28b6dcfbc474cc2096cf4c1224476103 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 3 May 2024 18:21:40 -0500 Subject: [PATCH] Start suggestions API --- src/app.ts | 4 +++ src/controllers/api/suggestions.ts | 50 ++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 src/controllers/api/suggestions.ts diff --git a/src/app.ts b/src/app.ts index b382cea..ddc902f 100644 --- a/src/app.ts +++ b/src/app.ts @@ -63,6 +63,7 @@ import { zapController, } from '@/controllers/api/statuses.ts'; import { streamingController } from '@/controllers/api/streaming.ts'; +import { suggestionsV1Controller, suggestionsV2Controller } from '@/controllers/api/suggestions.ts'; import { hashtagTimelineController, homeTimelineController, @@ -186,6 +187,9 @@ app.get('/api/pleroma/frontend_configurations', frontendConfigController); app.get('/api/v1/trends/tags', cache({ cacheName: 'web', expires: Time.minutes(15) }), trendingTagsController); app.get('/api/v1/trends', cache({ cacheName: 'web', expires: Time.minutes(15) }), trendingTagsController); +app.get('/api/v1/suggestions', suggestionsV1Controller); +app.get('/api/v2/suggestions', suggestionsV2Controller); + app.get('/api/v1/notifications', requirePubkey, notificationsController); app.get('/api/v1/favourites', requirePubkey, favouritesController); app.get('/api/v1/bookmarks', requirePubkey, bookmarksController); diff --git a/src/controllers/api/suggestions.ts b/src/controllers/api/suggestions.ts new file mode 100644 index 0000000..b85f05d --- /dev/null +++ b/src/controllers/api/suggestions.ts @@ -0,0 +1,50 @@ +import { NStore } from '@nostrify/nostrify'; + +import { AppController } from '@/app.ts'; +import { Conf } from '@/config.ts'; +import { getTagSet } from '@/tags.ts'; +import { hydrateEvents } from '@/storages/hydrate.ts'; +import { accountFromPubkey, renderAccount } from '@/views/mastodon/accounts.ts'; + +export const suggestionsV1Controller: AppController = async (c) => { + const store = c.get('store'); + const signal = c.req.raw.signal; + const accounts = await renderSuggestedAccounts(store, signal); + + return c.json(accounts); +}; + +export const suggestionsV2Controller: AppController = async (c) => { + const store = c.get('store'); + const signal = c.req.raw.signal; + const accounts = await renderSuggestedAccounts(store, signal); + + const suggestions = accounts.map((account) => ({ + source: 'staff', + account, + })); + + return c.json(suggestions); +}; + +async function renderSuggestedAccounts(store: NStore, signal?: AbortSignal) { + const [follows] = await store.query( + [{ kinds: [3], authors: [Conf.pubkey], limit: 1 }], + { signal }, + ); + + const pubkeys = [...getTagSet(follows?.tags ?? [], 'p')]; + + const profiles = await store.query( + [{ kinds: [1], authors: pubkeys }], + { signal }, + ) + .then((events) => hydrateEvents({ events, storage: store, signal })); + + const accounts = await Promise.all(pubkeys.map((pubkey) => { + const profile = profiles.find((event) => event.pubkey === pubkey); + return profile ? renderAccount(profile) : accountFromPubkey(pubkey); + })); + + return accounts.filter(Boolean); +}