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 { GetPostsDto } from '@gitroom/nestjs-libraries/dtos/posts/get.posts.dto'; import dayjs from 'dayjs'; import isoWeek from 'dayjs/plugin/isoWeek'; import weekOfYear from 'dayjs/plugin/weekOfYear'; import { v4 as uuidv4 } from 'uuid'; dayjs.extend(isoWeek); dayjs.extend(weekOfYear); @Injectable() export class PostsRepository { constructor( private _post: PrismaRepository<'post'>, private _popularPosts: PrismaRepository<'popularPosts'>, private _comments: PrismaRepository<'comments'> ) {} getOldPosts(orgId: string, date: string) { return this._post.model.post.findMany({ where: { organizationId: orgId, publishDate: { lte: dayjs(date).toDate(), }, deletedAt: null, parentPostId: null, }, orderBy: { publishDate: 'desc', }, select: { id: true, content: true, publishDate: true, releaseURL: true, state: true, integration: { select: { id: true, name: true, providerIdentifier: true, picture: true, type: true, }, }, }, }); } getPostUrls(orgId: string, ids: string[]) { return this._post.model.post.findMany({ where: { organizationId: orgId, id: { in: ids, }, }, select: { id: true, releaseURL: true, }, }); } getPosts(orgId: string, query: GetPostsDto) { const dateYear = dayjs().year(query.year); const date = query.display === 'day' ? dateYear.isoWeek(query.week).day(query.day) : query.display === 'week' ? dateYear.isoWeek(query.week) : dateYear.month(query.month - 1); const startDate = ( query.display === 'day' ? date.startOf('day') : query.display === 'week' ? date.startOf('isoWeek') : date.startOf('month') ) .subtract(2, 'hours') .toDate(); const endDate = ( query.display === 'day' ? date.endOf('day') : query.display === 'week' ? date.endOf('isoWeek') : date.endOf('month') ) .add(2, 'hours') .toDate(); return this._post.model.post.findMany({ where: { OR: [ { organizationId: orgId, }, { submittedForOrganizationId: orgId, }, ], publishDate: { gte: startDate, lte: endDate, }, deletedAt: null, parentPostId: null, ...query.customer ? { integration: { customerId: query.customer, } }: {}, }, select: { id: true, content: true, publishDate: true, releaseURL: true, submittedForOrganizationId: true, submittedForOrderId: true, state: true, integration: { select: { id: true, providerIdentifier: true, name: true, picture: true, }, }, }, }); } async deletePost(orgId: string, group: string) { await this._post.model.post.updateMany({ where: { organizationId: orgId, group, }, data: { deletedAt: new Date(), }, }); return this._post.model.post.findFirst({ where: { organizationId: orgId, group, parentPostId: null, }, select: { id: true, }, }); } getPost( id: string, includeIntegration = false, orgId?: string, isFirst?: boolean ) { return this._post.model.post.findUnique({ where: { id, ...(orgId ? { organizationId: orgId } : {}), deletedAt: null, }, include: { ...(includeIntegration ? { integration: true, } : {}), childrenPost: true, }, }); } updatePost(id: string, postId: string, releaseURL: string) { return this._post.model.post.update({ where: { id, }, data: { state: 'PUBLISHED', releaseURL, releaseId: postId, }, }); } changeState(id: string, state: State, err?: string) { return this._post.model.post.update({ where: { id, }, data: { state, error: typeof err === 'string' ? err : JSON.stringify(err), }, }); } async changeDate(orgId: string, id: string, date: string) { return this._post.model.post.update({ where: { organizationId: orgId, id, }, data: { publishDate: dayjs(date).toDate(), }, }); } countPostsFromDay(orgId: string, date: Date) { return this._post.model.post.count({ where: { organizationId: orgId, publishDate: { gte: date, }, OR: [ { deletedAt: null, state: { in: ['QUEUE'], }, }, { state: 'PUBLISHED', }, ], }, }); } async createOrUpdatePost( state: 'draft' | 'schedule' | 'now', orgId: string, date: string, body: PostBody ) { const posts: Post[] = []; const uuid = uuidv4(); for (const value of body.value) { const updateData = (type: 'create' | 'update') => ({ publishDate: dayjs(date).toDate(), integration: { connect: { id: body.integration.id, organizationId: orgId, }, }, ...(posts?.[posts.length - 1]?.id ? { parentPost: { connect: { id: posts[posts.length - 1]?.id, }, }, } : type === 'update' ? { parentPost: { disconnect: true, }, } : {}), content: value.content, group: uuid, approvedSubmitForOrder: APPROVED_SUBMIT_FOR_ORDER.NO, state: state === 'draft' ? ('DRAFT' as const) : ('QUEUE' as const), image: JSON.stringify(value.image), settings: JSON.stringify(body.settings), organization: { connect: { id: orgId, }, }, }); posts.push( await this._post.model.post.upsert({ where: { id: value.id || uuidv4(), }, create: { ...updateData('create') }, update: { ...updateData('update'), lastMessage: { disconnect: true, }, submittedForOrder: { disconnect: true, }, }, }) ); } const previousPost = body.group ? ( await this._post.model.post.findFirst({ where: { group: body.group, deletedAt: null, parentPostId: null, }, select: { id: true, }, }) )?.id! : undefined; if (body.group) { await this._post.model.post.updateMany({ where: { group: body.group, deletedAt: null, }, data: { parentPostId: null, deletedAt: new Date(), }, }); } return { previousPost, posts }; } async submit(id: string, order: string, buyerOrganizationId: string) { return this._post.model.post.update({ where: { id, }, data: { submittedForOrderId: order, approvedSubmitForOrder: 'WAITING_CONFIRMATION', submittedForOrganizationId: buyerOrganizationId, }, select: { id: true, description: true, submittedForOrder: { select: { messageGroupId: true, }, }, }, }); } updateMessage(id: string, messageId: string) { return this._post.model.post.update({ where: { id, }, data: { lastMessageId: messageId, }, }); } getPostById(id: string, org?: string) { return this._post.model.post.findUnique({ where: { id, ...(org ? { organizationId: org } : {}), }, include: { integration: true, submittedForOrder: { include: { posts: { where: { state: 'PUBLISHED', }, }, ordersItems: true, seller: { select: { id: true, account: true, }, }, }, }, }, }); } findAllExistingCategories() { return this._popularPosts.model.popularPosts.findMany({ select: { category: true, }, distinct: ['category'], }); } findAllExistingTopicsOfCategory(category: string) { return this._popularPosts.model.popularPosts.findMany({ where: { category, }, select: { topic: true, }, distinct: ['topic'], }); } findPopularPosts(category: string, topic?: string) { return this._popularPosts.model.popularPosts.findMany({ where: { category, ...(topic ? { topic } : {}), }, select: { content: true, hook: true, }, }); } createPopularPosts(post: { category: string; topic: string; content: string; hook: string; }) { return this._popularPosts.model.popularPosts.create({ data: { category: 'category', topic: 'topic', content: 'content', hook: 'hook', }, }); } async getPostsCountsByDates( orgId: string, times: number[], date: dayjs.Dayjs ) { const dates = await this._post.model.post.findMany({ where: { deletedAt: null, organizationId: orgId, publishDate: { in: times.map((time) => { return date.clone().add(time, 'minutes').toDate(); }), }, }, }); return times.filter( (time) => date.clone().add(time, 'minutes').isAfter(dayjs.utc()) && !dates.find((dateFind) => { return ( dayjs .utc(dateFind.publishDate) .diff(date.clone().startOf('day'), 'minutes') == time ); }) ); } async getComments(postId: string) { return this._comments.model.comments.findMany({ where: { postId, }, orderBy: { createdAt: 'asc', }, }); } createComment( orgId: string, userId: string, postId: string, content: string ) { return this._comments.model.comments.create({ data: { organizationId: orgId, userId, postId, content, }, }); } }