Merge branch 'local-suggested' into 'main'

Add local suggestions controller

See merge request soapbox-pub/ditto!631
This commit is contained in:
Alex Gleason 2025-01-31 03:19:35 +00:00
commit 7f71f6f50c
4 changed files with 34 additions and 7 deletions

View file

@ -109,7 +109,11 @@ import {
zappedByController, zappedByController,
} from '@/controllers/api/statuses.ts'; } from '@/controllers/api/statuses.ts';
import { streamingController } from '@/controllers/api/streaming.ts'; import { streamingController } from '@/controllers/api/streaming.ts';
import { suggestionsV1Controller, suggestionsV2Controller } from '@/controllers/api/suggestions.ts'; import {
localSuggestionsController,
suggestionsV1Controller,
suggestionsV2Controller,
} from '@/controllers/api/suggestions.ts';
import { import {
hashtagTimelineController, hashtagTimelineController,
homeTimelineController, homeTimelineController,
@ -166,7 +170,7 @@ export interface AppEnv extends HonoEnv {
type AppContext = Context<AppEnv>; type AppContext = Context<AppEnv>;
type AppMiddleware = MiddlewareHandler<AppEnv>; type AppMiddleware = MiddlewareHandler<AppEnv>;
type AppController = Handler<AppEnv, any, HonoInput, Response | Promise<Response>>; type AppController<P extends string = any> = Handler<AppEnv, P, HonoInput, Response | Promise<Response>>;
const app = new Hono<AppEnv>({ strict: false }); const app = new Hono<AppEnv>({ strict: false });
@ -348,6 +352,7 @@ app.get(
app.get('/api/v1/suggestions', suggestionsV1Controller); app.get('/api/v1/suggestions', suggestionsV1Controller);
app.get('/api/v2/suggestions', suggestionsV2Controller); app.get('/api/v2/suggestions', suggestionsV2Controller);
app.get('/api/v2/ditto/suggestions/local', localSuggestionsController);
app.get('/api/v1/notifications', rateLimitMiddleware(8, Time.seconds(30)), requireSigner, notificationsController); app.get('/api/v1/notifications', rateLimitMiddleware(8, Time.seconds(30)), requireSigner, notificationsController);
app.get('/api/v1/notifications/:id', requireSigner, notificationController); app.get('/api/v1/notifications/:id', requireSigner, notificationController);

View file

@ -4,7 +4,7 @@ import { matchFilter } from 'nostr-tools';
import { AppContext, AppController } from '@/app.ts'; import { AppContext, AppController } from '@/app.ts';
import { Conf } from '@/config.ts'; import { Conf } from '@/config.ts';
import { hydrateEvents } from '@/storages/hydrate.ts'; import { hydrateEvents } from '@/storages/hydrate.ts';
import { paginatedList } from '@/utils/api.ts'; import { paginated, paginatedList } from '@/utils/api.ts';
import { getTagSet } from '@/utils/tags.ts'; import { getTagSet } from '@/utils/tags.ts';
import { accountFromPubkey, renderAccount } from '@/views/mastodon/accounts.ts'; import { accountFromPubkey, renderAccount } from '@/views/mastodon/accounts.ts';
@ -87,3 +87,24 @@ async function renderV2Suggestions(c: AppContext, params: { offset: number; limi
}; };
})); }));
} }
export const localSuggestionsController: AppController = async (c) => {
const signal = c.req.raw.signal;
const params = c.get('pagination');
const store = c.get('store');
const events = await store.query(
[{ kinds: [0], search: `domain:${Conf.url.host}`, ...params }],
{ signal },
)
.then((events) => hydrateEvents({ store, events, signal }));
const suggestions = await Promise.all(events.map(async (event) => {
return {
source: 'global',
account: await renderAccount(event),
};
}));
return paginated(c, events, suggestions);
};

View file

@ -1,9 +1,9 @@
import { MiddlewareHandler } from '@hono/hono';
import { HTTPException } from '@hono/hono/http-exception'; import { HTTPException } from '@hono/hono/http-exception';
import { NostrSigner } from '@nostrify/nostrify';
import { AppMiddleware } from '@/app.ts';
/** Throw a 401 if a signer isn't set. */ /** Throw a 401 if a signer isn't set. */
export const requireSigner: AppMiddleware = async (c, next) => { export const requireSigner: MiddlewareHandler<{ Variables: { signer: NostrSigner } }> = async (c, next) => {
if (!c.get('signer')) { if (!c.get('signer')) {
throw new HTTPException(401, { message: 'No pubkey provided' }); throw new HTTPException(401, { message: 'No pubkey provided' });
} }

View file

@ -207,7 +207,8 @@ function buildLinkHeader(url: string, events: NostrEvent[]): string | undefined
return `<${next}>; rel="next", <${prev}>; rel="prev"`; return `<${next}>; rel="next", <${prev}>; rel="prev"`;
} }
type Entity = { id: string }; // deno-lint-ignore ban-types
type Entity = {};
type HeaderRecord = Record<string, string | string[]>; type HeaderRecord = Record<string, string | string[]>;
/** Return results with pagination headers. Assumes chronological sorting of events. */ /** Return results with pagination headers. Assumes chronological sorting of events. */