From 3c79e9dc89cec560077f6e2ec818a01cb7734798 Mon Sep 17 00:00:00 2001 From: rotorsoft Date: Tue, 22 Oct 2024 13:41:11 -0400 Subject: [PATCH] refactor get active threads --- libs/model/src/models/topic.ts | 2 +- .../src/thread/GetActiveThreads.query.ts | 77 +++++++++ libs/model/src/thread/index.ts | 1 + libs/schemas/src/queries/thread.schemas.ts | 9 ++ .../client/scripts/models/MinimumProfile.tsx | 2 +- .../controllers/server_threads_controller.ts | 12 -- .../get_active_threads.ts | 148 ------------------ .../routes/threads/get_threads_handler.ts | 11 +- 8 files changed, 96 insertions(+), 166 deletions(-) create mode 100644 libs/model/src/thread/GetActiveThreads.query.ts delete mode 100644 packages/commonwealth/server/controllers/server_threads_methods/get_active_threads.ts diff --git a/libs/model/src/models/topic.ts b/libs/model/src/models/topic.ts index fa2289b9b30..5bdfd12b459 100644 --- a/libs/model/src/models/topic.ts +++ b/libs/model/src/models/topic.ts @@ -8,7 +8,7 @@ import type { ModelInstance } from './types'; export type TopicAttributes = z.infer & { // associations community?: CommunityAttributes; - threads?: ThreadAttributes[] | TopicAttributes['id'][]; + threads?: ThreadAttributes[]; }; export type TopicInstance = ModelInstance; diff --git a/libs/model/src/thread/GetActiveThreads.query.ts b/libs/model/src/thread/GetActiveThreads.query.ts new file mode 100644 index 00000000000..af1a9a8faa3 --- /dev/null +++ b/libs/model/src/thread/GetActiveThreads.query.ts @@ -0,0 +1,77 @@ +import { Query } from '@hicommonwealth/core'; +import * as schemas from '@hicommonwealth/schemas'; +import { models } from '../database'; + +export function GetActiveThreads(): Query { + return { + ...schemas.GetActiveThreads, + auth: [], + secure: false, + body: async ({ payload }) => { + const { community_id, threads_per_topic, withXRecentComments } = payload; + + const topThreadsByTopic = await models.Topic.findAll({ + where: { community_id }, + include: [ + { + model: models.Thread, + as: 'threads', + required: true, + order: [ + ['created_at', 'DESC'], + ['last_commented_on', 'DESC'], + ], + limit: threads_per_topic ?? 3, + include: [ + { + model: models.Address, + as: 'Address', + attributes: ['id', 'address', 'community_id'], + include: [ + { + model: models.User, + attributes: ['id', 'profile'], + }, + ], + }, + { model: models.Address, as: 'collaborators' }, + { model: models.Topic, as: 'topic', required: true }, + { + model: models.Comment, + limit: Math.min(withXRecentComments ?? 0, 10), // cap to 10 + order: [['created_at', 'DESC']], + attributes: [ + 'id', + 'address_id', + 'text', + 'created_at', + 'updated_at', + 'deleted_at', + 'marked_as_spam_at', + 'discord_meta', + 'content_url', + ], + include: [ + { + model: models.Address, + as: 'Address', + attributes: ['address'], + include: [ + { + model: models.User, + attributes: ['id', 'profile'], + }, + ], + }, + ], + }, + ], + }, + ], + }); + return topThreadsByTopic + .map((topic) => topic.toJSON().threads ?? []) + .flat(); + }, + }; +} diff --git a/libs/model/src/thread/index.ts b/libs/model/src/thread/index.ts index 343214bb3e2..134ce13719d 100644 --- a/libs/model/src/thread/index.ts +++ b/libs/model/src/thread/index.ts @@ -1,5 +1,6 @@ export * from './CreateThread.command'; export * from './CreateThreadReaction.command'; export * from './DeleteThread.command'; +export * from './GetActiveThreads.query'; export * from './GetThreads.query'; export * from './UpdateThread.command'; diff --git a/libs/schemas/src/queries/thread.schemas.ts b/libs/schemas/src/queries/thread.schemas.ts index 560793e6470..1c8da2d3c75 100644 --- a/libs/schemas/src/queries/thread.schemas.ts +++ b/libs/schemas/src/queries/thread.schemas.ts @@ -164,3 +164,12 @@ export const DEPRECATED_GetBulkThreads = z.object({ status: z.string().optional(), withXRecentComments: z.coerce.number().optional(), }); + +export const GetActiveThreads = { + input: z.object({ + community_id: z.string(), + threads_per_topic: z.coerce.number().min(0).max(10).optional(), + withXRecentComments: z.coerce.number().optional(), + }), + output: z.array(Thread), +}; diff --git a/packages/commonwealth/client/scripts/models/MinimumProfile.tsx b/packages/commonwealth/client/scripts/models/MinimumProfile.tsx index 41139d60d35..1ef8ef8c8b7 100644 --- a/packages/commonwealth/client/scripts/models/MinimumProfile.tsx +++ b/packages/commonwealth/client/scripts/models/MinimumProfile.tsx @@ -15,7 +15,7 @@ export function addressToUserProfile( address: z.infer, ): UserProfile { return { - userId: address.user_id!, + userId: address.user_id ?? address.User?.id ?? 0, avatarUrl: address.User?.profile.avatar_url ?? '', name: address.User?.profile.name ?? DEFAULT_NAME, address: address?.address, diff --git a/packages/commonwealth/server/controllers/server_threads_controller.ts b/packages/commonwealth/server/controllers/server_threads_controller.ts index 1386b768d83..34ccb787f97 100644 --- a/packages/commonwealth/server/controllers/server_threads_controller.ts +++ b/packages/commonwealth/server/controllers/server_threads_controller.ts @@ -9,11 +9,6 @@ import { CreateThreadPollResult, __createThreadPoll, } from './server_threads_methods/create_thread_poll'; -import { - GetActiveThreadsOptions, - GetActiveThreadsResult, - __getActiveThreads, -} from './server_threads_methods/get_active_threads'; import { GetThreadPollsOptions, GetThreadPollsResult, @@ -43,13 +38,6 @@ export class ServerThreadsController { return __getThreadsById.call(this, options); } - async getActiveThreads( - this: ServerThreadsController, - options: GetActiveThreadsOptions, - ): Promise { - return __getActiveThreads.call(this, options); - } - async searchThreads( this: ServerThreadsController, options: SearchThreadsOptions, diff --git a/packages/commonwealth/server/controllers/server_threads_methods/get_active_threads.ts b/packages/commonwealth/server/controllers/server_threads_methods/get_active_threads.ts deleted file mode 100644 index 5627bcf4e37..00000000000 --- a/packages/commonwealth/server/controllers/server_threads_methods/get_active_threads.ts +++ /dev/null @@ -1,148 +0,0 @@ -import { ThreadAttributes, TopicAttributes } from '@hicommonwealth/model'; -import { Includeable, WhereOptions } from 'sequelize'; -import { ServerThreadsController } from '../server_threads_controller'; - -const MIN_THREADS_PER_TOPIC = 0; -const MAX_THREADS_PER_TOPIC = 10; - -export type GetActiveThreadsOptions = { - communityId: string; - threadsPerTopic: number; - withXRecentComments?: number; -}; - -export type GetActiveThreadsResult = ThreadAttributes[]; - -export async function __getActiveThreads( - this: ServerThreadsController, - { - communityId, - threadsPerTopic, - withXRecentComments = 0, - }: GetActiveThreadsOptions, -): Promise { - const allThreads = []; - if ( - !threadsPerTopic || - Number.isNaN(threadsPerTopic) || - threadsPerTopic < MIN_THREADS_PER_TOPIC || - threadsPerTopic > MAX_THREADS_PER_TOPIC - ) { - threadsPerTopic = 3; - } - - const communityWhere: WhereOptions = { - community_id: communityId, - }; - const communityTopics = await this.models.Topic.findAll({ - where: communityWhere, - }); - - const threadInclude: Includeable[] = [ - { - model: this.models.Address, - as: 'Address', - attributes: ['id', 'address', 'community_id'], - include: [ - { - model: this.models.User, - attributes: ['id', 'profile'], - }, - ], - }, - { model: this.models.Address, as: 'collaborators' }, - { model: this.models.Topic, as: 'topic', required: true }, - ]; - - if (withXRecentComments) { - threadInclude.push({ - model: this.models.Comment, - limit: withXRecentComments > 10 ? 10 : withXRecentComments, // cap to 10, - order: [['created_at', 'DESC']], - attributes: [ - 'id', - 'address_id', - 'text', - 'created_at', - 'updated_at', - 'deleted_at', - 'marked_as_spam_at', - 'discord_meta', - 'content_url', - ], - include: [ - { - model: this.models.Address, - as: 'Address', - attributes: ['address'], - include: [ - { - model: this.models.User, - attributes: ['id', 'profile'], - }, - ], - }, - ], - }); - } - - let allRecentTopicThreadsRaw = []; - // @ts-expect-error StrictNullChecks - allRecentTopicThreadsRaw = await Promise.all( - communityTopics.map(async (topic) => { - return await this.models.Thread.findAll({ - where: { - topic_id: topic.id, - }, - include: threadInclude, - limit: threadsPerTopic, - order: [ - ['created_at', 'DESC'], - ['last_commented_on', 'DESC'], - ], - }); - }), - ); - - allRecentTopicThreadsRaw = allRecentTopicThreadsRaw.flat(); - - const allRecentTopicThreads = allRecentTopicThreadsRaw.map((thread) => { - // @ts-expect-error StrictNullChecks - const tempThread = thread.toJSON(); - tempThread.numberOfComments = tempThread.comment_count || 0; - if (tempThread.Address.User) { - tempThread.user_id = tempThread.Address.User.id; - tempThread.profile_name = tempThread.Address.User.profile.name; - tempThread.avatar_url = tempThread.Address.User.profile.avatar_url; - delete tempThread.Address.User; - } - - if (withXRecentComments) { - tempThread.recentComments = (tempThread.Comments || []).map((c) => { - const temp = { - ...c, - address: c?.Address?.address || '', - }; - if (temp.Address) { - temp.user_id = temp.Address.User?.id; - temp.profile_name = temp.Address.User?.profile.name; - temp.profile_avatar = temp.Address.User?.profile.avatar_url; - delete temp.Address; - } - return temp; - }); - delete tempThread.Comments; - } - return tempThread; - }); - - communityTopics.forEach((topic) => { - const threadsWithCommentsCount = allRecentTopicThreads.filter( - (thread) => thread.topic_id === topic.id, - ); - // @ts-expect-error StrictNullChecks - allThreads.push(...(threadsWithCommentsCount || [])); - }); - - return allThreads; -} diff --git a/packages/commonwealth/server/routes/threads/get_threads_handler.ts b/packages/commonwealth/server/routes/threads/get_threads_handler.ts index 84794ffa161..18f26c4953b 100644 --- a/packages/commonwealth/server/routes/threads/get_threads_handler.ts +++ b/packages/commonwealth/server/routes/threads/get_threads_handler.ts @@ -147,10 +147,13 @@ export const getThreadsHandler = async ( const { threads_per_topic, withXRecentComments } = req.query as ActiveThreadsRequestQuery; - const activeThreads = await controllers.threads.getActiveThreads({ - communityId: community_id, - threadsPerTopic: parseInt(threads_per_topic, 10), - withXRecentComments, + const activeThreads = await query(Thread.GetActiveThreads(), { + actor: { user: { email: '' } }, + payload: { + community_id, + threads_per_topic: parseInt(threads_per_topic, 10), + withXRecentComments, + }, }); return success(res, activeThreads); }