diff --git a/apps/backend/src/api/routes/posts.controller.ts b/apps/backend/src/api/routes/posts.controller.ts index 790df94f..14756ce2 100644 --- a/apps/backend/src/api/routes/posts.controller.ts +++ b/apps/backend/src/api/routes/posts.controller.ts @@ -175,7 +175,7 @@ export class PostsController { ) { console.log(JSON.stringify(rawBody, null, 2)); const body = await this._postsService.mapTypeToPost(rawBody, org.id); - return this._postsService.createPost(org.id, body); + return this._postsService.createPost(org.id, body, 'WEB'); } @Post('/generator/draft') diff --git a/apps/backend/src/public-api/routes/v1/public.integrations.controller.ts b/apps/backend/src/public-api/routes/v1/public.integrations.controller.ts index 38ce060b..0b6d8338 100644 --- a/apps/backend/src/public-api/routes/v1/public.integrations.controller.ts +++ b/apps/backend/src/public-api/routes/v1/public.integrations.controller.ts @@ -188,8 +188,15 @@ export class PublicIntegrationsController { ); } + const allowedCreationMethods = ['CLI', 'API'] as const; + const creationMethod = allowedCreationMethods.includes( + rawBody.creationMethod + ) + ? (rawBody.creationMethod as 'CLI' | 'API') + : 'API'; + console.log(JSON.stringify(body, null, 2)); - return this._postsService.createPost(org.id, body); + return this._postsService.createPost(org.id, body, creationMethod); } @Delete('/posts/:id') diff --git a/apps/frontend/src/app/(app)/(preview)/p/[id]/page.tsx b/apps/frontend/src/app/(app)/(preview)/p/[id]/page.tsx index fb12181d..f5dc7b46 100644 --- a/apps/frontend/src/app/(app)/(preview)/p/[id]/page.tsx +++ b/apps/frontend/src/app/(app)/(preview)/p/[id]/page.tsx @@ -12,6 +12,7 @@ import { VideoOrImage } from '@gitroom/react/helpers/video.or.image'; import { CopyClient } from '@gitroom/frontend/components/preview/copy.client'; import { getT } from '@gitroom/react/translation/get.translation.service.backend'; import { RenderPreviewDateClient } from '@gitroom/frontend/components/preview/render.preview.date.client'; +import { CreationMethodBadge } from '@gitroom/frontend/components/launches/creation.method.badge'; dayjs.extend(utc); export const metadata: Metadata = { @@ -142,6 +143,12 @@ export default async function Auth( @{post[0].integration.profile} + {index === 0 && ( + + )}
{ window.open(`/p/` + post.id + '?share=true', '_blank'); }, [post]); @@ -1044,6 +1050,14 @@ const CalendarItem: FC<{ !
)} + {showCreationMethodBadge && ( +
+ +
+ )}
+ m === 'AUTOPOST' ? 'Auto-posted by system' : `Created via ${m}`; + +export const CreationMethodBadge: FC = ({ + creationMethod, + size = 'xs', + className, + ringColor, +}) => { + if (!creationMethod || creationMethod === 'UNKNOWN') return null; + + const sizeClasses = + size === 'xs' + ? 'h-[12px] px-[4px] text-[7px]' + : size === 'md' + ? 'h-[22px] px-[10px] text-[12px]' + : 'h-[18px] px-[8px] text-[10px]'; + + return ( +
+ {creationMethod} +
+ ); +}; diff --git a/apps/frontend/src/components/new-launch/manage.modal.tsx b/apps/frontend/src/components/new-launch/manage.modal.tsx index f8edb218..3b4cd464 100644 --- a/apps/frontend/src/components/new-launch/manage.modal.tsx +++ b/apps/frontend/src/components/new-launch/manage.modal.tsx @@ -33,6 +33,7 @@ import { SelectCustomer } from '@gitroom/frontend/components/launches/select.cus import { CopilotPopup } from '@copilotkit/react-ui'; import { DummyCodeComponent } from '@gitroom/frontend/components/new-launch/dummy.code.component'; import { stripHtmlValidation } from '@gitroom/helpers/utils/strip.html.validation'; +import { CreationMethodBadge } from '@gitroom/frontend/components/launches/creation.method.badge'; import { SettingsIcon, ChevronDownIcon, @@ -450,8 +451,12 @@ export const ManageModal: FC = (props) => {
-
+
{t('create_post_title', 'Create Post')} +
{ const fetch = useFetch(); const { backendUrl } = useVariables(); @@ -30,6 +31,7 @@ export const PreviewWrapper = ({ children }: { children: ReactNode }) => { > + {children} diff --git a/libraries/helpers/src/utils/posts.list.minify.ts b/libraries/helpers/src/utils/posts.list.minify.ts index cebe1497..f5847b9d 100644 --- a/libraries/helpers/src/utils/posts.list.minify.ts +++ b/libraries/helpers/src/utils/posts.list.minify.ts @@ -25,6 +25,7 @@ const POST_ITEM_KEYS: Record = { integration: 'n', intervalInDays: 'iv', actualDate: 'ad', + creationMethod: 'cm', }; const INTEGRATION_KEYS: Record = { diff --git a/libraries/nestjs-libraries/src/chat/tools/integration.schedule.post.ts b/libraries/nestjs-libraries/src/chat/tools/integration.schedule.post.ts index dc3c3f52..b2983de7 100644 --- a/libraries/nestjs-libraries/src/chat/tools/integration.schedule.post.ts +++ b/libraries/nestjs-libraries/src/chat/tools/integration.schedule.post.ts @@ -223,7 +223,7 @@ If the tools return errors, you would need to rerun it with the right parameters })), }, ], - }); + }, 'MCP'); finalOutput.push(...output); } diff --git a/libraries/nestjs-libraries/src/database/prisma/autopost/autopost.service.ts b/libraries/nestjs-libraries/src/database/prisma/autopost/autopost.service.ts index 5964983a..c8132847 100644 --- a/libraries/nestjs-libraries/src/database/prisma/autopost/autopost.service.ts +++ b/libraries/nestjs-libraries/src/database/prisma/autopost/autopost.service.ts @@ -303,7 +303,7 @@ export class AutopostService { }, ], })), - }); + }, 'AUTOPOST'); } async updateUrl(state: WorkflowChannelsState) { diff --git a/libraries/nestjs-libraries/src/database/prisma/posts/posts.repository.ts b/libraries/nestjs-libraries/src/database/prisma/posts/posts.repository.ts index 261f2628..84767937 100644 --- a/libraries/nestjs-libraries/src/database/prisma/posts/posts.repository.ts +++ b/libraries/nestjs-libraries/src/database/prisma/posts/posts.repository.ts @@ -1,7 +1,12 @@ import { PrismaRepository } from '@gitroom/nestjs-libraries/database/prisma/prisma.service'; import { Injectable } from '@nestjs/common'; import { Post as PostBody } from '@gitroom/nestjs-libraries/dtos/posts/create.post.dto'; -import { APPROVED_SUBMIT_FOR_ORDER, Post, State } from '@prisma/client'; +import { + APPROVED_SUBMIT_FOR_ORDER, + CreationMethod, + Post, + State, +} from '@prisma/client'; import { GetPostsDto } from '@gitroom/nestjs-libraries/dtos/posts/get.posts.dto'; import { GetPostsListDto } from '@gitroom/nestjs-libraries/dtos/posts/get.posts.list.dto'; import dayjs from 'dayjs'; @@ -174,6 +179,7 @@ export class PostsRepository { state: true, intervalInDays: true, group: true, + creationMethod: true, tags: { select: { tag: true, @@ -261,6 +267,7 @@ export class PostsRepository { releaseId: true, state: true, group: true, + creationMethod: true, tags: { select: { tag: true, @@ -484,6 +491,7 @@ export class PostsRepository { date: string, body: PostBody, tags: { value: string; label: string }[], + creationMethod: CreationMethod, inter?: number ) { const posts: Post[] = []; @@ -518,6 +526,7 @@ export class PostsRepository { group: uuid, intervalInDays: inter ? +inter : null, approvedSubmitForOrder: APPROVED_SUBMIT_FOR_ORDER.NO, + ...(type === 'create' ? { creationMethod } : {}), ...(state === 'update' ? {} : { diff --git a/libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts b/libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts index 5f4694ba..0e8100ef 100644 --- a/libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts +++ b/libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts @@ -7,7 +7,14 @@ import { PostsRepository } from '@gitroom/nestjs-libraries/database/prisma/posts import { CreatePostDto } from '@gitroom/nestjs-libraries/dtos/posts/create.post.dto'; import dayjs from 'dayjs'; import { IntegrationManager } from '@gitroom/nestjs-libraries/integrations/integration.manager'; -import { Integration, Post, Media, From, State } from '@prisma/client'; +import { + Integration, + Post, + Media, + From, + CreationMethod, + State, +} from '@prisma/client'; import { GetPostsDto } from '@gitroom/nestjs-libraries/dtos/posts/get.posts.dto'; import { GetPostsListDto } from '@gitroom/nestjs-libraries/dtos/posts/get.posts.list.dto'; import { shuffle } from 'lodash'; @@ -740,7 +747,11 @@ export class PostsService { } catch (err) {} } - async createPost(orgId: string, body: CreatePostDto): Promise { + async createPost( + orgId: string, + body: CreatePostDto, + creationMethod: CreationMethod + ): Promise { const postList = []; for (const post of body.posts) { const provider = this._integrationManager.getSocialIntegration( @@ -769,6 +780,7 @@ export class PostsService { body.type === 'now' ? dayjs().format('YYYY-MM-DDTHH:mm:00') : body.date, post, body.tags, + creationMethod, body.inter ); @@ -902,43 +914,47 @@ export class PostsService { const group = makeId(10); const randomDate = findTime(); - await this.createPost(orgId, { - type: 'draft', - date: randomDate, - order: '', - shortLink: false, - tags: [], - posts: [ - { - group, - integration: { - id: integration.id, - }, - settings: { - __type: integration.providerIdentifier as any, - title: '', - tags: [], - subreddit: [], - }, - value: [ - ...toPost.list.map((l) => ({ - id: '', - content: l.post, - delay: 0, - image: [], - })), - { - id: '', - delay: 0, - content: `Check out the full story here:\n${ - body.postId || body.url - }`, - image: [], + await this.createPost( + orgId, + { + type: 'draft', + date: randomDate, + order: '', + shortLink: false, + tags: [], + posts: [ + { + group, + integration: { + id: integration.id, }, - ], - }, - ], - }); + settings: { + __type: integration.providerIdentifier as any, + title: '', + tags: [], + subreddit: [], + }, + value: [ + ...toPost.list.map((l) => ({ + id: '', + content: l.post, + delay: 0, + image: [], + })), + { + id: '', + delay: 0, + content: `Check out the full story here:\n${ + body.postId || body.url + }`, + image: [], + }, + ], + }, + ], + }, + 'WEB' + ); } } } diff --git a/libraries/nestjs-libraries/src/database/prisma/schema.prisma b/libraries/nestjs-libraries/src/database/prisma/schema.prisma index a005ed80..7f48b7bf 100644 --- a/libraries/nestjs-libraries/src/database/prisma/schema.prisma +++ b/libraries/nestjs-libraries/src/database/prisma/schema.prisma @@ -409,6 +409,7 @@ model Post { submittedForOrderId String? submittedForOrganizationId String? approvedSubmitForOrder APPROVED_SUBMIT_FOR_ORDER @default(NO) + creationMethod CreationMethod @default(UNKNOWN) lastMessageId String? intervalInDays Int? error String? @@ -436,6 +437,7 @@ model Post { @@index([submittedForOrderId]) @@index([intervalInDays]) @@index([approvedSubmitForOrder]) + @@index([creationMethod]) @@index([lastMessageId]) @@index([createdAt]) @@index([updatedAt]) @@ -938,6 +940,15 @@ enum APPROVED_SUBMIT_FOR_ORDER { YES } +enum CreationMethod { + UNKNOWN + WEB + MCP + API + AUTOPOST + CLI +} + enum ShortLinkPreference { ASK YES