diff --git a/src/plugins/api/posts.ts b/src/plugins/api/posts.ts index 7f2d3ed..ffcb4c9 100644 --- a/src/plugins/api/posts.ts +++ b/src/plugins/api/posts.ts @@ -37,7 +37,6 @@ import { GroupItemType, Installation, App, - Group, } from '../../types/collections' import { PluginOptions } from '../../types' @@ -45,22 +44,25 @@ import { PluginOptions } from '../../types' interface PostBody { text?: string cover?: string + installation: string visible: boolean status?: Status attachments: PostAttachment[] + data: object parent: string } const postBodySchema = { type: 'object', - required: ['visible'], + required: ['installation', 'visible'], properties: { + installation: { type: 'string' }, + visible: { type: 'boolean' }, text: { type: 'string' }, cover: { type: 'string', maxLength: SHORT_TEXT_LENGTH, }, - visible: { type: 'boolean' }, status: { type: 'object', required: ['date'], @@ -77,10 +79,10 @@ const postBodySchema = { type: 'array', items: { type: 'object', - required: ['imageUrl'], + required: ['url'], properties: { - imageUrl: { type: 'string' }, - caption: { + url: { type: 'string' }, + text: { type: 'string', maxLength: SHORT_TEXT_LENGTH, }, @@ -91,11 +93,14 @@ const postBodySchema = { }, }, }, + data: { + type: 'object', + }, parent: { type: 'string' }, }, } -async function createPost(client: CosmosClient, userId: string, body: PostBody, reply: FastifyReply, logger: Logger) { +async function createPost(client: CosmosClient, userId: string, appId: string, body: PostBody, reply: FastifyReply, logger: Logger) { let newPostRelationship: PostRelationship | undefined const postContainer = containerFor(client, 'Posts') @@ -111,7 +116,8 @@ async function createPost(client: CosmosClient, userId: string, body: PostBody, const postId = createPostId() if (body.parent) { - const parent = await getItem({ container: postContainer, id: body.parent }) + const parentItem = postContainer.item(body.parent, body.parent) + const { resource: parent } = await parentItem.read() if (!parent) return badRequestFormError(reply, 'parent', 'Invalid parent') const parentRelationship = await getItem({ @@ -130,6 +136,13 @@ async function createPost(client: CosmosClient, userId: string, body: PostBody, parent.id, ] } + + if (body.visible) { + await parentItem.replace({ + ...parent, + replies: parent.replies + 1, + }) + } } const post: Post = { @@ -137,13 +150,16 @@ async function createPost(client: CosmosClient, userId: string, body: PostBody, pk: postId, t: PostItemType.Post, userId, + appId, root: newPostRelationship ? newPostRelationship.pk : postId, parents: newPostRelationship ? newPostRelationship.parents : [], text: trimContent(body.text, 1000), cover: trimContent(body.cover), visible: body.visible, - attachments: [], + attachments: body.attachments, + data: body.data, awards: 0, + replies: 0, latestAwards: [], created: Date.now(), } @@ -169,8 +185,6 @@ async function createPost(client: CosmosClient, userId: string, body: PostBody, logger, }) - logger.debug('subscribers', subscribers) - for (const uid of [userId, ...subscribers.map(s => s.userId)]) { await userContainer.items.create({ id: postId, @@ -205,13 +219,32 @@ function createPostRoute(server: FastifyInstance({ + container, + id: installationId, + partitionKey: INSTALLATION_PARTITION_KEY, + }) + + if (!installation) return badRequestError(reply, 'Installation not found') + if (installation.userId !== request.viewer.id) return badRequestError(reply) + + const app = await getItem({ + container, + id: installation.appId, + partitionKey: APP_PARTITION_KEY, + }) + + if (!app) return serverError(reply) + + return await createPost(server.database.client, request.viewer.id, app.id, request.body, reply, request.log) }) } function createAppPostRoute(server: FastifyInstance) { interface Headers { - installation: string timestamp: string signature: string } @@ -221,7 +254,6 @@ function createAppPostRoute(server: FastifyInstance('/api/app/post', options, async (request, reply) => { if (!server.database) return serverError(reply) - const { installation: installationId, timestamp, signature } = request.headers + const { timestamp, signature } = request.headers - if (!installationId) return badRequestError(reply, '"installation" header required') if (!timestamp) return badRequestError(reply, '"timestamp" header required') if (!signature) return badRequestError(reply, '"signature" header required') + const installationId = request.body.installation + const container = containerFor(server.database.client, 'Apps') const installation = await getItem({ container, @@ -269,7 +302,7 @@ function createAppPostRoute(server: FastifyInstance({ container: containerFor(server.database.client, 'Groups'), query: blockQuery, - logger: request.log + logger: request.log, }) const blockedUserIds = blocks.map(b => b.userId) @@ -547,16 +581,16 @@ function postRoute(server: FastifyInstance !blockedUserIds.includes(p.userId)), - ancestors: ancestors.filter(p => !blockedUserIds.includes(p.userId)), + children: descendants.filter(p => !blockedUserIds.includes(p.userId)), + parents: ancestors.filter(p => !blockedUserIds.includes(p.userId)), users: users.filter(u => !blockedUserIds.includes(u.id)), } } return { post, - descendants, - ancestors, + children: descendants, + parents: ancestors, users, } }) diff --git a/src/schemas.ts b/src/schemas.ts index 60bb01c..4aa605a 100644 --- a/src/schemas.ts +++ b/src/schemas.ts @@ -78,10 +78,28 @@ export const postSchema: JSONSchema = { type: 'object', properties: { id: { type: 'string' }, + userId: { type: 'string' }, + appId: { type: 'string' }, user: userSchema, text: { type: 'string' }, cover: { type: 'string' }, + attachments: { + type: 'array', + items: { + type: 'object', + properties: { + url: { type: 'string' }, + text: { type: 'string' }, + cover: { type: 'string' }, + }, + }, + }, + data: { + type: 'object', + additionalProperties: true, + }, visible: { type: 'boolean' }, + replies: { type: 'number' }, created: { type: 'number' }, }, } diff --git a/src/types/collections.ts b/src/types/collections.ts index 6e5f834..c525f1d 100644 --- a/src/types/collections.ts +++ b/src/types/collections.ts @@ -260,8 +260,8 @@ export interface UserTimelinePost { } export interface PostAttachment { - imageUrl: string - caption?: string + url: string + text?: string cover?: string } @@ -288,6 +288,7 @@ export interface Post { status?: Status data?: PostData visible: boolean + replies: number awards: number latestAwards: PostAwardPartial[] created: number