diff --git a/common/src/microblog/reader.ts b/common/src/microblog/reader.ts index 54d0126f754..a815ae71f0d 100644 --- a/common/src/microblog/reader.ts +++ b/common/src/microblog/reader.ts @@ -2,7 +2,14 @@ import axios, { AxiosResponse } from 'axios' import TID from '../repo/tid.js' import { z } from 'zod' -import { Post, Like, schema, AccountInfo, Timeline } from './types.js' +import { + Post, + Like, + schema, + AccountInfo, + Timeline, + TimelinePost, +} from './types.js' import { schema as repoSchema } from '../repo/types.js' import * as check from '../common/check.js' import { assureAxiosError } from '../network/util.js' @@ -81,6 +88,24 @@ export class MicroblogReader { } } + async getPostInfo(username: string, tid: TID): Promise { + const { hostUrl } = this.normalizeUsername(username) + const did = await this.resolveDid(username) + const params = { did, namespace: this.namespace, tid: tid.toString() } + try { + const res = await axios.get(`${hostUrl}/indexer/post-info`, { + params, + }) + return check.assure(schema.timelinePost, res.data) + } catch (e) { + const err = assureAxiosError(e) + if (err.response?.status === 404) { + return null + } + throw new Error(err.message) + } + } + async getPostFromUser(username: string, tid: TID): Promise { const { hostUrl } = this.normalizeUsername(username) const did = await this.resolveDid(username) diff --git a/server/src/db/index.ts b/server/src/db/index.ts index 1b88efc194a..8f211c1c0ec 100644 --- a/server/src/db/index.ts +++ b/server/src/db/index.ts @@ -1,4 +1,10 @@ -import { Like, Post, Timeline, AccountInfo } from '@bluesky/common' +import { + Like, + Post, + Timeline, + AccountInfo, + TimelinePost, +} from '@bluesky/common' import { Follow } from '@bluesky/common/dist/repo/types' import knex from 'knex' import { CID } from 'multiformats' @@ -248,6 +254,27 @@ export class Database { // INDEXER // ----------- + async retrievePostInfo( + tid: string, + author: string, + namespace: string, + ): Promise { + const row = await this.db('posts') + .join('user_dids', 'posts.author', '=', 'user_dids.did') + .select('*') + .where({ tid, author, namespace }) + if (row.length < 1) return null + const p = row[0] + return { + tid: p.tid, + author: p.author, + author_name: `${p.username}@${p.host}`, + text: p.text, + time: p.time, + likes: await this.likeCount(p.author, p.namespace, p.tid), + } + } + async retrieveFeed( user: string, count: number, @@ -270,7 +297,7 @@ export class Database { feed.map(async (p) => ({ tid: p.tid, author: p.author, - author_name: username, + author_name: `${p.username}@${p.host}`, text: p.text, time: p.time, likes: await this.likeCount(p.author, p.namespace, p.tid), diff --git a/server/src/routes/indexer/index.ts b/server/src/routes/indexer/index.ts index 38dad106528..d1875ace36e 100644 --- a/server/src/routes/indexer/index.ts +++ b/server/src/routes/indexer/index.ts @@ -1,6 +1,7 @@ import express from 'express' import Timeline from './timeline.js' import Feed from './feed.js' +import PostInfo from './post-info.js' import Count from './count.js' import Followers from './followers.js' import AccountInfo from './account-info.js' @@ -9,6 +10,7 @@ const router = express.Router() router.use('/timeline', Timeline) router.use('/feed', Feed) +router.use('/post-info', PostInfo) router.use('/count', Count) router.use('/followers', Followers) router.use('/account-info', AccountInfo) diff --git a/server/src/routes/indexer/post-info.ts b/server/src/routes/indexer/post-info.ts new file mode 100644 index 00000000000..943ba5b12df --- /dev/null +++ b/server/src/routes/indexer/post-info.ts @@ -0,0 +1,26 @@ +import express from 'express' +import { z } from 'zod' +import { schema } from '@bluesky/common' +import * as util from '../../util.js' +import { ServerError } from '../../error.js' + +const router = express.Router() + +export const getPostInfoReq = z.object({ + did: z.string(), + namespace: z.string(), + tid: schema.repo.strToTid, +}) +export type getPostInfoReq = z.infer + +router.get('/', async (req, res) => { + const { did, namespace, tid } = util.checkReqBody(req.query, getPostInfoReq) + const db = util.getDB(res) + const post = await db.retrievePostInfo(tid.toString(), did, namespace) + if (!post) { + throw new ServerError(404, 'Could not find post') + } + res.status(200).send(post) +}) + +export default router