From 5e4fd9ad1c77cfe303bfc0bce2262a120c19f7e3 Mon Sep 17 00:00:00 2001 From: Timothee Legros <62490329+timolegros@users.noreply.github.com> Date: Fri, 5 Jan 2024 23:12:08 +0100 Subject: [PATCH] Comment model semantics (#6199) * init migration + model index fixes * update Sequelize model + fix type errors on server * more fixes * raw queries * raw queries * fix unit test + skip legacy TBC unit test * fix stats * update getCommentDepth to use recursive query rather than recursive function with multiple queries * remove todo from migration * down migration * fix unit tests * getcommentDepth integration tests * remove .only * remove .skip since TBC removal was merged --- knowledge_base/Over-Fetching.md | 2 +- .../client/scripts/models/Comment.ts | 13 +-- .../models/NotificationSubscription.ts | 7 +- .../components/Profile/ProfileActivityRow.tsx | 9 +- .../discussions/CommentTree/CommentTree.tsx | 2 +- .../CommentTree/usePrepareCommentsList.tsx | 20 ++-- .../helper_components.tsx | 2 +- .../pages/notification_settings/index.tsx | 4 +- .../server_admin_methods/get_stats.ts | 2 +- .../search_comments.ts | 2 +- .../server_comments_methods/update_comment.ts | 4 +- .../delete_community.ts | 4 +- .../create_thread_comment.ts | 17 ++-- .../20240103232009-comment-model-semantics.js | 97 +++++++++++++++++++ .../commonwealth/server/models/comment.ts | 12 +-- .../commonwealth/server/models/community.ts | 2 +- .../server/routes/bulkOffchain.ts | 14 ++- .../server/routes/comments/getComments.ts | 2 +- .../server/routes/communityStats.ts | 6 +- .../server/routes/exportMembersList.ts | 2 +- .../server/routes/spam/markCommentAsSpam.ts | 8 +- .../server/routes/spam/unmarkCommentAsSpam.ts | 8 +- packages/commonwealth/server/routes/status.ts | 19 ++-- .../routes/subscription/createSubscription.ts | 5 +- .../routes/threadsUsersCountAndAvatars.ts | 22 ++--- .../server/routes/viewComments.ts | 4 +- .../commonwealth/server/routing/external.ts | 4 +- .../server/scripts/emailDigest.ts | 2 +- .../server/scripts/emitWebhook.ts | 2 +- .../server/util/getCommentDepth.ts | 60 ++++++++---- .../test/e2e/hooks/e2eDbEntityHooks.spec.ts | 4 +- .../api/external/dbEntityHooks.spec.ts | 4 +- .../api/external/getComments.spec.ts | 14 +-- .../api/external/getCommunities.spec.ts | 2 +- .../api/external/getReactions.spec.ts | 2 +- .../api/external/getThreads.spec.ts | 2 +- .../integration/api/recomputeCount.spec.ts | 2 +- .../integration/emitNotifications.spec.ts | 2 +- .../test/integration/getCommentDepth.spec.ts | 62 ++++++++++++ .../server_comments_controller.spec.ts | 6 +- .../server_threads_controller.spec.ts | 1 + .../unit/server_util/getCommentDepth.spec.ts | 65 ------------- 42 files changed, 321 insertions(+), 202 deletions(-) create mode 100644 packages/commonwealth/server/migrations/20240103232009-comment-model-semantics.js create mode 100644 packages/commonwealth/test/integration/getCommentDepth.spec.ts delete mode 100644 packages/commonwealth/test/unit/server_util/getCommentDepth.spec.ts diff --git a/knowledge_base/Over-Fetching.md b/knowledge_base/Over-Fetching.md index a6d74b1a99a..f1aaadf4c93 100644 --- a/knowledge_base/Over-Fetching.md +++ b/knowledge_base/Over-Fetching.md @@ -96,7 +96,7 @@ SELECT "Thread->Address"."wallet_id" AS "Thread.Address.wallet_id", "Thread->Address"."user_id" AS "Thread.Address.UserId", "Comment"."id" AS "Comment.id", - "Comment"."chain" AS "Comment.chain", + "Comment"."community_id" AS "Comment.community_id", "Comment"."thread_id" AS "Comment.thread_id", "Comment"."parent_id" AS "Comment.parent_id", "Comment"."address_id" AS "Comment.address_id", diff --git a/packages/commonwealth/client/scripts/models/Comment.ts b/packages/commonwealth/client/scripts/models/Comment.ts index 18427602e14..acc2cbe4412 100644 --- a/packages/commonwealth/client/scripts/models/Comment.ts +++ b/packages/commonwealth/client/scripts/models/Comment.ts @@ -7,26 +7,23 @@ import type { IUniqueId } from './interfaces'; // eslint-disable-next-line @typescript-eslint/no-unused-vars export class Comment { - [x: string]: any; - - public readonly chain: string; + public readonly communityId: string; public readonly author: string; public readonly Address: AddressInfo; public readonly text: string; public readonly plaintext: string; public readonly reactions: Reaction[]; public readonly id: number; - public readonly created_at: momentType.Moment; + public readonly createdAt: momentType.Moment; public readonly authorChain?: string; public readonly parentComment: number; public readonly threadId: number; - public readonly version_history: VersionHistory[]; + public readonly versionHistory: VersionHistory[]; public readonly lastEdited: string; public markedAsSpamAt: momentType.Moment; public readonly deleted: boolean; public readonly rootThread: string; public readonly parentId: number; - public readonly deletedAt: any; public readonly canvasAction: string; public readonly canvasSession: string; @@ -36,7 +33,7 @@ export class Comment { constructor({ id, text, - chain, + community_id, author, Address, thread_id, @@ -74,7 +71,7 @@ export class Comment { }) : []; - this.chain = chain; + this.communityId = community_id; this.author = Address?.address || author; this.text = deleted_at?.length > 0 ? '[deleted]' : decodeURIComponent(text); this.plaintext = deleted_at?.length > 0 ? '[deleted]' : plaintext; diff --git a/packages/commonwealth/client/scripts/models/NotificationSubscription.ts b/packages/commonwealth/client/scripts/models/NotificationSubscription.ts index 220a923f7f0..9bb07d039d5 100644 --- a/packages/commonwealth/client/scripts/models/NotificationSubscription.ts +++ b/packages/commonwealth/client/scripts/models/NotificationSubscription.ts @@ -1,8 +1,7 @@ import moment from 'moment'; -import type { SubscriptionInstance } from 'server/models/subscription'; import type ChainInfo from './ChainInfo'; -import { default as CommentT } from './Comment'; +import { Comment as CommentT } from './Comment'; import { Thread as ThreadT } from './Thread'; import type { IUniqueId } from './interfaces'; @@ -95,7 +94,7 @@ class NotificationSubscription { } } -export const modelFromServer = (subscription: SubscriptionInstance) => { +export const modelFromServer = (subscription) => { const { id, category_id, @@ -125,7 +124,7 @@ export const modelFromServer = (subscription: SubscriptionInstance) => { if (Comment) { try { - modeledComment = new CommentT({ ...Comment } as any); + modeledComment = new CommentT({ ...Comment }); } catch (e) { console.log('error', e); } diff --git a/packages/commonwealth/client/scripts/views/components/Profile/ProfileActivityRow.tsx b/packages/commonwealth/client/scripts/views/components/Profile/ProfileActivityRow.tsx index 4c8555784b9..52e69ba40ae 100644 --- a/packages/commonwealth/client/scripts/views/components/Profile/ProfileActivityRow.tsx +++ b/packages/commonwealth/client/scripts/views/components/Profile/ProfileActivityRow.tsx @@ -22,12 +22,11 @@ type ProfileActivityRowProps = { const ProfileActivityRow = ({ activity }: ProfileActivityRowProps) => { const navigate = useCommonNavigate(); - const { createdAt, author, title, id, body } = activity; - let communityId: string; + const { communityId, createdAt, author, id } = activity; + let title: string, body: string; if (activity instanceof Thread) { - communityId = activity.communityId; - } else { - communityId = activity.chain; + title = activity.title; + body = activity.body; } const isThread = !!(activity as Thread).kind; const comment = activity as CommentWithAssociatedThread; diff --git a/packages/commonwealth/client/scripts/views/pages/discussions/CommentTree/CommentTree.tsx b/packages/commonwealth/client/scripts/views/pages/discussions/CommentTree/CommentTree.tsx index 5367614f40d..6b8f435442e 100644 --- a/packages/commonwealth/client/scripts/views/pages/discussions/CommentTree/CommentTree.tsx +++ b/packages/commonwealth/client/scripts/views/pages/discussions/CommentTree/CommentTree.tsx @@ -172,7 +172,7 @@ export const CommentTree = ({ try { await deleteComment({ commentId: comment.id, - canvasHash: comment.canvas_hash, + canvasHash: comment.canvasHash, communityId: app.activeChainId(), address: app.user.activeAccount.address, existingNumberOfComments: thread.numberOfComments, diff --git a/packages/commonwealth/client/scripts/views/pages/discussions/CommentTree/usePrepareCommentsList.tsx b/packages/commonwealth/client/scripts/views/pages/discussions/CommentTree/usePrepareCommentsList.tsx index 0d1a17077bd..e12ffc8f64a 100644 --- a/packages/commonwealth/client/scripts/views/pages/discussions/CommentTree/usePrepareCommentsList.tsx +++ b/packages/commonwealth/client/scripts/views/pages/discussions/CommentTree/usePrepareCommentsList.tsx @@ -1,7 +1,8 @@ import { commentsByDate } from 'helpers/dates'; +import type { IUniqueId } from 'models/interfaces'; +import { CommentsFeaturedFilterTypes } from 'models/types'; import app from 'state'; import type { Comment as CommentType } from '../../../../models/Comment'; -import { CommentsFeaturedFilterTypes } from 'models/types'; const MAX_THREAD_LEVEL = 8; @@ -10,7 +11,7 @@ type ExtendedComment = { isCommentAuthor: boolean; maxReplyLimitReached: boolean; replyBtnVisible: boolean; - children: CommentType & ExtendedComment; + children: Array & ExtendedComment>; }; interface UsePrepareCommentsListProps { @@ -39,7 +40,7 @@ const usePrepareCommentsList = ({ }: UsePrepareCommentsListProps) => { const isLivingCommentTree = ( comment: CommentType, - children: Array> + children: Array>, ) => { if (!comment.deleted) { return true; @@ -57,7 +58,7 @@ const usePrepareCommentsList = ({ } const grandchildren = allComments.filter( - (c) => c.threadId === threadId && c.parentComment === comment.id + (c) => c.threadId === threadId && c.parentComment === comment.id, ); for (let j = 0; j < grandchildren.length; j++) { @@ -79,7 +80,7 @@ const usePrepareCommentsList = ({ // This functions creates recursively a tree of zero level comments and their nested children (replies) const recursivelyGatherComments = ( _levelZeroComments: Array>, - threadLevel: number + threadLevel: number, ): Array & ExtendedComment> => { const canContinueThreading = threadLevel <= MAX_THREAD_LEVEL; @@ -94,7 +95,7 @@ const usePrepareCommentsList = ({ const children = allComments // take only comments that are direct children of current comment .filter( - (c) => c.threadId === threadId && c.parentComment === comment.id + (c) => c.threadId === threadId && c.parentComment === comment.id, ) // sorts comments and nested comments according to user selection from dropdown .sort((a, b) => commentsByDate(a, b, commentSortType)); @@ -134,11 +135,12 @@ const usePrepareCommentsList = ({ // This functions transforms nested list of comments created by "recursivelyGatherComments" // into flat list which is exactly in the order how user would see this in the UI const getFlattenComments = ( - _comments: Array & ExtendedComment> + _comments: Array & ExtendedComment>, ) => { - const flattenedComments: Array & ExtendedComment> = []; + const flattenedComments: Array & ExtendedComment> = + []; - const flatten = (comment: CommentType & ExtendedComment) => { + const flatten = (comment: CommentType & ExtendedComment) => { flattenedComments.push(comment); if (comment.children && comment.children.length > 0) { diff --git a/packages/commonwealth/client/scripts/views/pages/notification_settings/helper_components.tsx b/packages/commonwealth/client/scripts/views/pages/notification_settings/helper_components.tsx index c1dfa94799d..46c49a2b8e5 100644 --- a/packages/commonwealth/client/scripts/views/pages/notification_settings/helper_components.tsx +++ b/packages/commonwealth/client/scripts/views/pages/notification_settings/helper_components.tsx @@ -76,7 +76,7 @@ const getTextRows = ( ' diff --git a/packages/commonwealth/client/scripts/views/pages/notification_settings/index.tsx b/packages/commonwealth/client/scripts/views/pages/notification_settings/index.tsx index 88af30172ef..b228fb559e7 100644 --- a/packages/commonwealth/client/scripts/views/pages/notification_settings/index.tsx +++ b/packages/commonwealth/client/scripts/views/pages/notification_settings/index.tsx @@ -473,11 +473,11 @@ const NotificationSettingsPage = () => { userCommunityId={sub.Thread.communityId} /> ); - } else if (sub.Comment?.chain) { + } else if (sub.Comment?.communityId) { return ( ); } else { diff --git a/packages/commonwealth/server/controllers/server_admin_methods/get_stats.ts b/packages/commonwealth/server/controllers/server_admin_methods/get_stats.ts index c949f8ce823..bb789640ae4 100644 --- a/packages/commonwealth/server/controllers/server_admin_methods/get_stats.ts +++ b/packages/commonwealth/server/controllers/server_admin_methods/get_stats.ts @@ -83,7 +83,7 @@ export async function __getStats( { type: QueryTypes.SELECT }, ), this.models.Comment.count({ - where: whereChain, + where: whereCommunityId, }), this.models.Thread.count({ where: whereCommunityId, diff --git a/packages/commonwealth/server/controllers/server_comments_methods/search_comments.ts b/packages/commonwealth/server/controllers/server_comments_methods/search_comments.ts index cb82ec01134..f1dcbb0d7d1 100644 --- a/packages/commonwealth/server/controllers/server_comments_methods/search_comments.ts +++ b/packages/commonwealth/server/controllers/server_comments_methods/search_comments.ts @@ -79,7 +79,7 @@ export async function __searchComments( } const communityWhere = bind.community - ? '"Comments".chain = $community AND' + ? '"Comments".community_id = $community AND' : ''; const sqlBaseQuery = ` diff --git a/packages/commonwealth/server/controllers/server_comments_methods/update_comment.ts b/packages/commonwealth/server/controllers/server_comments_methods/update_comment.ts index 93db5f9c4ac..c658679b955 100644 --- a/packages/commonwealth/server/controllers/server_comments_methods/update_comment.ts +++ b/packages/commonwealth/server/controllers/server_comments_methods/update_comment.ts @@ -128,7 +128,7 @@ export async function __updateComment( root_type: ProposalType.Thread, comment_id: +finalComment.id, comment_text: finalComment.text, - chain_id: finalComment.chain, + chain_id: finalComment.community_id, author_address: finalComment.Address.address, author_chain: finalComment.Address.community_id, }, @@ -191,7 +191,7 @@ export async function __updateComment( root_type: ProposalType.Thread, comment_id: +finalComment.id, comment_text: finalComment.text, - chain_id: finalComment.chain, + chain_id: finalComment.community_id, author_address: finalComment.Address.address, author_chain: finalComment.Address.community_id, }, diff --git a/packages/commonwealth/server/controllers/server_communities_methods/delete_community.ts b/packages/commonwealth/server/controllers/server_communities_methods/delete_community.ts index de6dbefe422..ccea6390032 100644 --- a/packages/commonwealth/server/controllers/server_communities_methods/delete_community.ts +++ b/packages/commonwealth/server/controllers/server_communities_methods/delete_community.ts @@ -69,12 +69,12 @@ export async function __deleteCommunity( await sequelize.query( `UPDATE "Comments" SET created_by = (SELECT address FROM "Addresses" WHERE "Comments".address_id = "Addresses".id) - WHERE chain = '${community.id}'`, + WHERE community_id = '${community.id}'`, { transaction: t }, ); await this.models.Comment.destroy({ - where: { chain: community.id }, + where: { community_id: community.id }, transaction: t, }); diff --git a/packages/commonwealth/server/controllers/server_threads_methods/create_thread_comment.ts b/packages/commonwealth/server/controllers/server_threads_methods/create_thread_comment.ts index 17069025730..775403dd854 100644 --- a/packages/commonwealth/server/controllers/server_threads_methods/create_thread_comment.ts +++ b/packages/commonwealth/server/controllers/server_threads_methods/create_thread_comment.ts @@ -103,7 +103,7 @@ export async function __createThreadComment( parentComment = await this.models.Comment.findOne({ where: { id: parentId, - chain: community.id, + community_id: community.id, }, include: [this.models.Address], }); @@ -164,18 +164,19 @@ export async function __createThreadComment( body: decodeURIComponent(text), }; const version_history: string[] = [JSON.stringify(firstVersion)]; - const commentContent = { + const commentContent: CommentAttributes = { thread_id: `${threadId}`, text, plaintext, version_history, address_id: address.id, - chain: community.id, + community_id: community.id, parent_id: null, canvas_action: canvasAction, canvas_session: canvasSession, canvas_hash: canvasHash, discord_meta: discordMeta, + reaction_count: 0, }; if (parentId) { Object.assign(commentContent, { parent_id: parentId }); @@ -196,7 +197,7 @@ export async function __createThreadComment( { subscriber_id: user.id, category_id: NotificationCategories.NewReaction, - chain_id: finalComment.chain || null, + chain_id: finalComment.community_id || null, comment_id: finalComment.id, is_active: true, }, @@ -206,7 +207,7 @@ export async function __createThreadComment( { subscriber_id: user.id, category_id: NotificationCategories.NewComment, - chain_id: finalComment.chain || null, + chain_id: finalComment.community_id || null, comment_id: finalComment.id, is_active: true, }, @@ -267,7 +268,7 @@ export async function __createThreadComment( root_type: ProposalType.Thread, comment_id: +finalComment.id, comment_text: finalComment.text, - chain_id: finalComment.chain, + chain_id: finalComment.community_id, author_address: finalComment.Address.address, author_chain: finalComment.Address.community_id, }, @@ -289,7 +290,7 @@ export async function __createThreadComment( comment_text: finalComment.text, parent_comment_id: +parentId, parent_comment_text: parentComment.text, - chain_id: finalComment.chain, + chain_id: finalComment.community_id, author_address: finalComment.Address.address, author_chain: finalComment.Address.community_id, }, @@ -316,7 +317,7 @@ export async function __createThreadComment( root_type: ProposalType.Thread, comment_id: +finalComment.id, comment_text: finalComment.text, - chain_id: finalComment.chain, + chain_id: finalComment.community_id, author_address: finalComment.Address.address, author_chain: finalComment.Address.community_id, }, diff --git a/packages/commonwealth/server/migrations/20240103232009-comment-model-semantics.js b/packages/commonwealth/server/migrations/20240103232009-comment-model-semantics.js new file mode 100644 index 00000000000..8623b2517d8 --- /dev/null +++ b/packages/commonwealth/server/migrations/20240103232009-comment-model-semantics.js @@ -0,0 +1,97 @@ +'use strict'; + +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.sequelize.transaction(async (transaction) => { + await queryInterface.renameColumn('Comments', 'chain', 'community_id', { + transaction, + }); + // these are both indexes on Comments.id which is already covered by the primary key index + await queryInterface.removeIndex('Comments', 'offchain_comments_id', { + transaction, + }); + await queryInterface.removeIndex('Comments', 'comments_id', { + transaction, + }); + + // unused index on (chain, parent_id) + await queryInterface.removeIndex( + 'Comments', + 'offchain_comments_chain_object_id', + { transaction }, + ); + + // duplicate of 'comments_address_id' index on Comments.address_id + await queryInterface.removeIndex( + 'Comments', + 'offchain_comments_address_id', + { transaction }, + ); + + await queryInterface.sequelize.query( + ` + ALTER INDEX "OffchainComments_search" RENAME TO "comments_search" + `, + { transaction }, + ); + await queryInterface.sequelize.query( + ` + ALTER INDEX "offchain_comments_chain_created_at" RENAME TO "comments_community_id_created_at" + `, + { transaction }, + ); + await queryInterface.sequelize.query( + ` + ALTER INDEX "offchain_comments_chain_updated_at" RENAME TO "comments_community_id_updated_at" + `, + { transaction }, + ); + }); + }, + + down: async (queryInterface, Sequelize) => { + await queryInterface.sequelize.transaction(async (transaction) => { + await queryInterface.renameColumn('Comments', 'community_id', 'chain', { + transaction, + }); + await queryInterface.addIndex('Comments', { + fields: ['id'], + name: 'offchain_comments_id', + transaction, + }); + await queryInterface.addIndex('Comments', { + fields: ['id'], + name: 'comments_id', + transaction, + }); + await queryInterface.addIndex('Comments', { + fields: ['chain', 'parent_id'], + name: 'offchain_comments_chain_object_id', + transaction, + }); + await queryInterface.addIndex('Comments', { + fields: ['address_id'], + name: 'offchain_comments_address_id', + transaction, + }); + await queryInterface.sequelize.query( + ` + ALTER INDEX "comments_search" RENAME TO "OffchainComments_search" + `, + { transaction }, + ); + await queryInterface.sequelize.query( + ` + ALTER INDEX "comments_community_id_created_at" RENAME TO "offchain_comments_chain_created_at" + `, + { transaction }, + ); + await queryInterface.sequelize.query( + ` + ALTER INDEX "comments_community_id_updated_at" RENAME TO "offchain_comments_chain_updated_at" + `, + { transaction }, + ); + }); + }, +}; diff --git a/packages/commonwealth/server/models/comment.ts b/packages/commonwealth/server/models/comment.ts index 04a3a7bdec3..23bf3785ba0 100644 --- a/packages/commonwealth/server/models/comment.ts +++ b/packages/commonwealth/server/models/comment.ts @@ -16,7 +16,7 @@ export type CommentAttributes = { text: string; plaintext: string; id?: number; - chain: string; + community_id: string; parent_id?: string; version_history?: string[]; @@ -50,7 +50,7 @@ export default ( 'Comment', { id: { type: dataTypes.INTEGER, autoIncrement: true, primaryKey: true }, - chain: { type: dataTypes.STRING, allowNull: false }, + community_id: { type: dataTypes.STRING, allowNull: false }, thread_id: { type: dataTypes.INTEGER, allowNull: false, @@ -140,19 +140,17 @@ export default ( paranoid: true, indexes: [ { fields: ['id'] }, - { fields: ['chain', 'thread_id'] }, { fields: ['address_id'] }, - { fields: ['chain', 'created_at'] }, - { fields: ['chain', 'updated_at'] }, + { fields: ['community_id', 'created_at'] }, + { fields: ['community_id', 'updated_at'] }, { fields: ['thread_id'] }, - { fields: ['canvas_hash'] }, ], }, ); Comment.associate = (models) => { models.Comment.belongsTo(models.Community, { - foreignKey: 'chain', + foreignKey: 'community_id', targetKey: 'id', }); models.Comment.belongsTo(models.Address, { diff --git a/packages/commonwealth/server/models/community.ts b/packages/commonwealth/server/models/community.ts index 2f1d2aa76a9..ca03cba85da 100644 --- a/packages/commonwealth/server/models/community.ts +++ b/packages/commonwealth/server/models/community.ts @@ -180,7 +180,7 @@ export default ( foreignKey: 'community_id', }); models.Community.hasMany(models.Thread, { foreignKey: 'community_id' }); - models.Community.hasMany(models.Comment, { foreignKey: 'chain' }); + models.Community.hasMany(models.Comment, { foreignKey: 'community_id' }); models.Community.hasMany(models.StarredCommunity, { foreignKey: 'chain' }); models.Community.belongsToMany(models.Contract, { through: models.CommunityContract, diff --git a/packages/commonwealth/server/routes/bulkOffchain.ts b/packages/commonwealth/server/routes/bulkOffchain.ts index 2a5e8107f74..a4474246ec9 100644 --- a/packages/commonwealth/server/routes/bulkOffchain.ts +++ b/packages/commonwealth/server/routes/bulkOffchain.ts @@ -62,19 +62,17 @@ const bulkOffchain = async (models: DB, req: Request, res: Response) => { (new Date() as any) - 1000 * 24 * 60 * 60 * 30, ); const activeUsers = {}; + const where = { + updated_at: { [Op.gt]: thirtyDaysAgo }, + community_id: chain.id, + }; const monthlyComments = await models.Comment.findAll({ - where: { - updated_at: { [Op.gt]: thirtyDaysAgo }, - chain: chain.id, - }, + where, include: [models.Address], }); const monthlyThreads = await models.Thread.findAll({ - where: { - updated_at: { [Op.gt]: thirtyDaysAgo }, - community_id: chain.id, - }, + where, attributes: { exclude: ['version_history'] }, include: [{ model: models.Address, as: 'Address' }], }); diff --git a/packages/commonwealth/server/routes/comments/getComments.ts b/packages/commonwealth/server/routes/comments/getComments.ts index 3a427546453..a456aefec9c 100644 --- a/packages/commonwealth/server/routes/comments/getComments.ts +++ b/packages/commonwealth/server/routes/comments/getComments.ts @@ -30,7 +30,7 @@ export const getComments = async ( const { community_id, addresses, thread_ids, count_only } = req.query; - const where: WhereOptions = { chain: community_id }; + const where: WhereOptions = { community_id: community_id }; // if address is included, find which addressIds they correspond to. if (addresses) { diff --git a/packages/commonwealth/server/routes/communityStats.ts b/packages/commonwealth/server/routes/communityStats.ts index daddce1d668..9cb418dc292 100644 --- a/packages/commonwealth/server/routes/communityStats.ts +++ b/packages/commonwealth/server/routes/communityStats.ts @@ -49,7 +49,7 @@ ORDER BY seq.date DESC;`, }; const roles = await newObjectsQuery('"Addresses"', 'community_id'); const threads = await newObjectsQuery('"Threads"', 'community_id'); - const comments = await newObjectsQuery('"Comments"', 'chain'); + const comments = await newObjectsQuery('"Comments"', 'community_id'); // get total number of roles, threads, and comments const totalObjectsQuery = async (table, chainName) => { @@ -63,7 +63,7 @@ ORDER BY seq.date DESC;`, }; const totalRoles = await totalObjectsQuery('"Addresses"', 'community_id'); const totalThreads = await totalObjectsQuery('"Threads"', 'community_id'); - const totalComments = await totalObjectsQuery('"Comments"', 'chain'); + const totalComments = await totalObjectsQuery('"Comments"', 'community_id'); // get number of active accounts by day const activeAccounts = await models.sequelize.query( @@ -75,7 +75,7 @@ LEFT JOIN ( AND community_id = :chainOrCommunity UNION SELECT address_id, created_at FROM "Comments" WHERE created_at > CURRENT_DATE - ${numberOfPrevDays} - AND ${chain ? 'chain' : 'community'} = :chainOrCommunity + AND community_id = :chainOrCommunity UNION SELECT address_id, created_at FROM "Reactions" WHERE created_at > CURRENT_DATE - ${numberOfPrevDays} AND ${chain ? 'chain' : 'community'} = :chainOrCommunity diff --git a/packages/commonwealth/server/routes/exportMembersList.ts b/packages/commonwealth/server/routes/exportMembersList.ts index d0b31d81c2a..37fd6e63c97 100644 --- a/packages/commonwealth/server/routes/exportMembersList.ts +++ b/packages/commonwealth/server/routes/exportMembersList.ts @@ -57,7 +57,7 @@ const exportMembersList = async ( LEFT JOIN "Threads" "t" ON "a"."id" = "t"."address_id" AND "t"."community_id" = :chainId LEFT JOIN - "Comments" "c" ON "a"."id" = "c"."address_id" AND "c"."chain" = :chainId + "Comments" "c" ON "a"."id" = "c"."address_id" AND "c"."community_id" = :chainId LEFT JOIN "Reactions" "r" ON "a"."id" = "r"."address_id" AND "r"."chain" = :chainId WHERE diff --git a/packages/commonwealth/server/routes/spam/markCommentAsSpam.ts b/packages/commonwealth/server/routes/spam/markCommentAsSpam.ts index bb2f8790c77..ade2e101982 100644 --- a/packages/commonwealth/server/routes/spam/markCommentAsSpam.ts +++ b/packages/commonwealth/server/routes/spam/markCommentAsSpam.ts @@ -1,7 +1,7 @@ import { AppError } from 'common-common/src/errors'; import type { Request, Response } from 'express'; -import type { DB } from '../../models'; import { Op, Sequelize } from 'sequelize'; +import type { DB } from '../../models'; import { success } from '../../types'; import { findAllRoles } from '../../util/roles'; @@ -38,11 +38,11 @@ export default async (models: DB, req: Request, res: Response) => { const roles = await findAllRoles( models, { where: { address_id: { [Op.in]: userOwnedAddressIds } } }, - comment.chain, - ['admin', 'moderator'] + comment.community_id, + ['admin', 'moderator'], ); const role = roles.find((r) => { - return r.chain_id === comment.chain; + return r.chain_id === comment.community_id; }); if (!role) { throw new AppError(Errors.NotAdmin); diff --git a/packages/commonwealth/server/routes/spam/unmarkCommentAsSpam.ts b/packages/commonwealth/server/routes/spam/unmarkCommentAsSpam.ts index 65877f65012..2ce50feb8ff 100644 --- a/packages/commonwealth/server/routes/spam/unmarkCommentAsSpam.ts +++ b/packages/commonwealth/server/routes/spam/unmarkCommentAsSpam.ts @@ -1,7 +1,7 @@ import { AppError } from 'common-common/src/errors'; import type { Request, Response } from 'express'; -import type { DB } from '../../models'; import { Op } from 'sequelize'; +import type { DB } from '../../models'; import { success } from '../../types'; import { findAllRoles } from '../../util/roles'; @@ -38,11 +38,11 @@ export default async (models: DB, req: Request, res: Response) => { const roles = await findAllRoles( models, { where: { address_id: { [Op.in]: userOwnedAddressIds } } }, - comment.chain, - ['admin', 'moderator'] + comment.community_id, + ['admin', 'moderator'], ); const role = roles.find((r) => { - return r.chain_id === comment.chain; + return r.chain_id === comment.community_id; }); if (!role) { throw new AppError(Errors.NotAdmin); diff --git a/packages/commonwealth/server/routes/status.ts b/packages/commonwealth/server/routes/status.ts index f17586ed777..e2f453493f9 100644 --- a/packages/commonwealth/server/routes/status.ts +++ b/packages/commonwealth/server/routes/status.ts @@ -200,12 +200,12 @@ export const getUserStatus = async (models: DB, user: UserInstance) => { // add the chain and timestamp to replacements so that we can safely populate the query with dynamic parameters replacements.push(name, date); // append the SELECT query - query += `SELECT thread_id, chain FROM "Comments" WHERE chain = ? AND created_at > ?`; + query += `SELECT thread_id, community_id FROM "Comments" WHERE community_id = ? AND created_at > ?`; if (i === commsAndChains.length - 1) query += ';'; } // populate query and execute - const commentNum: { thread_id: string; chain: string }[] = ( + const commentNum: { thread_id: string; community_id: string }[] = ( await sequelize.query(query, { raw: true, type: QueryTypes.SELECT, @@ -215,14 +215,15 @@ export const getUserStatus = async (models: DB, user: UserInstance) => { // iterates through the retrieved comments and adds each thread id to the activePosts set for (const comment of commentNum) { - if (!unseenPosts[comment.chain]) unseenPosts[comment.chain] = {}; + if (!unseenPosts[comment.community_id]) + unseenPosts[comment.community_id] = {}; const id = comment.thread_id; - unseenPosts[comment.chain].activePosts - ? unseenPosts[comment.chain].activePosts.add(id) - : (unseenPosts[comment.chain].activePosts = new Set([id])); - unseenPosts[comment.chain].comments - ? unseenPosts[comment.chain].comments++ - : (unseenPosts[comment.chain].comments = 1); + unseenPosts[comment.community_id].activePosts + ? unseenPosts[comment.community_id].activePosts.add(id) + : (unseenPosts[comment.community_id].activePosts = new Set([id])); + unseenPosts[comment.community_id].comments + ? unseenPosts[comment.community_id].comments++ + : (unseenPosts[comment.community_id].comments = 1); } // set the activePosts to num in set diff --git a/packages/commonwealth/server/routes/subscription/createSubscription.ts b/packages/commonwealth/server/routes/subscription/createSubscription.ts index c37bea4d2e7..c70f246b93e 100644 --- a/packages/commonwealth/server/routes/subscription/createSubscription.ts +++ b/packages/commonwealth/server/routes/subscription/createSubscription.ts @@ -85,7 +85,10 @@ export default async ( where: { id: req.body.comment_id }, }); if (!comment) return next(new AppError(Errors.NoComment)); - obj = { comment_id: req.body.comment_id, chain_id: comment.chain }; + obj = { + comment_id: req.body.comment_id, + chain_id: comment.community_id, + }; } break; } diff --git a/packages/commonwealth/server/routes/threadsUsersCountAndAvatars.ts b/packages/commonwealth/server/routes/threadsUsersCountAndAvatars.ts index 33e08d8198e..c1e42d14238 100644 --- a/packages/commonwealth/server/routes/threadsUsersCountAndAvatars.ts +++ b/packages/commonwealth/server/routes/threadsUsersCountAndAvatars.ts @@ -1,9 +1,9 @@ +import { factory, formatFilename } from 'common-common/src/logging'; import type { Request, Response } from 'express'; -import { QueryTypes } from 'sequelize'; import { groupBy } from 'lodash'; -import { factory, formatFilename } from 'common-common/src/logging'; -import type { DB } from '../models'; +import { QueryTypes } from 'sequelize'; import { sequelize } from '../database'; +import type { DB } from '../models'; const log = factory.getLogger(formatFilename(__filename)); @@ -16,15 +16,15 @@ type UniqueAddresses = { const fetchUniqueAddressesByThreadIds = async ( models: DB, - { chain, thread_ids } + { chain, thread_ids }, ) => { return sequelize.query( ` - SELECT distinct cts.address_id, address, thread_id, cts.chain + SELECT distinct cts.address_id, address, thread_id, cts.community_id FROM "Comments" cts INNER JOIN "Addresses" adr ON adr.id = cts.address_id WHERE thread_id = ANY($thread_ids) - AND cts.chain = $chain + AND cts.community_id = $chain AND deleted_at IS NULL ORDER BY thread_id `, @@ -34,7 +34,7 @@ const fetchUniqueAddressesByThreadIds = async ( thread_ids, chain, }, - } + }, ); }; @@ -49,7 +49,7 @@ is wildly unclear and wildly inconsistent. We should standardize + clarify. const threadsUsersCountAndAvatar = async ( models: DB, req: Request, - res: Response + res: Response, ) => { const { chain, threads = [] } = req.body; try { @@ -57,11 +57,11 @@ const threadsUsersCountAndAvatar = async ( const thread_ids = threads.map(({ thread_id }) => thread_id); const uniqueAddressesByRootIds = await fetchUniqueAddressesByThreadIds( models, - { chain, thread_ids } + { chain, thread_ids }, ); const uniqueAddressesByThread = groupBy( uniqueAddressesByRootIds, - ({ thread_id }) => thread_id + ({ thread_id }) => thread_id, ); return res.json( threads.map(({ thread_id: thread_id, author: authorAddress }) => { @@ -83,7 +83,7 @@ const threadsUsersCountAndAvatar = async ( addresses, count: addressesCount > 2 ? addressesCount - 2 : 0, }; - }) + }), ); } return res.json([]); diff --git a/packages/commonwealth/server/routes/viewComments.ts b/packages/commonwealth/server/routes/viewComments.ts index 8872f407aad..21bec74681e 100644 --- a/packages/commonwealth/server/routes/viewComments.ts +++ b/packages/commonwealth/server/routes/viewComments.ts @@ -11,7 +11,7 @@ const viewComments = async ( models: DB, req: Request, res: Response, - next: NextFunction + next: NextFunction, ) => { const chain = req.chain; @@ -20,7 +20,7 @@ const viewComments = async ( } const comments = await models.Comment.findAll({ - where: { chain: chain.id, thread_id: req.query.thread_id }, + where: { community_id: chain.id, thread_id: req.query.thread_id }, include: [ models.Address, { diff --git a/packages/commonwealth/server/routing/external.ts b/packages/commonwealth/server/routing/external.ts index dff278d9ac1..eab3695c56d 100644 --- a/packages/commonwealth/server/routing/external.ts +++ b/packages/commonwealth/server/routing/external.ts @@ -54,7 +54,7 @@ export function addExternalRoutes( putCommentsValidation, addEntities.bind( this, - 'chain', + 'community_id', models, (a) => models.Comment.bulkCreate(a), (req: TypedRequest) => req.body.comments, @@ -64,7 +64,7 @@ export function addExternalRoutes( '/comments', passport.authenticate('jwt', { session: false }), onlyIds, - deleteEntities.bind(this, 'chain', models, models.Comment), + deleteEntities.bind(this, 'community_id', models, models.Comment), ); router.get( diff --git a/packages/commonwealth/server/scripts/emailDigest.ts b/packages/commonwealth/server/scripts/emailDigest.ts index c477adac372..bfd0c45bdad 100644 --- a/packages/commonwealth/server/scripts/emailDigest.ts +++ b/packages/commonwealth/server/scripts/emailDigest.ts @@ -147,7 +147,7 @@ const getActivityCounts = async (communityId: string) => { COUNT(DISTINCT c.id) AS comment_count FROM "Comments" c WHERE - c.chain='${communityId}' AND + c.community_id='${communityId}' AND c.created_at > NOW() - INTERVAL '1 WEEK'`); const totalComments = (commentCounts[1] as any)?.rows?.[0] diff --git a/packages/commonwealth/server/scripts/emitWebhook.ts b/packages/commonwealth/server/scripts/emitWebhook.ts index 1818b76cb69..8409935f19e 100644 --- a/packages/commonwealth/server/scripts/emitWebhook.ts +++ b/packages/commonwealth/server/scripts/emitWebhook.ts @@ -167,7 +167,7 @@ async function main() { ) { const [comment] = await models.Comment.findOrCreate({ where: { - chain: community.id, + community_id: community.id, thread_id: thread.id, }, defaults: { diff --git a/packages/commonwealth/server/util/getCommentDepth.ts b/packages/commonwealth/server/util/getCommentDepth.ts index d97f71cc212..d8b0e355b10 100644 --- a/packages/commonwealth/server/util/getCommentDepth.ts +++ b/packages/commonwealth/server/util/getCommentDepth.ts @@ -1,29 +1,55 @@ +import { QueryTypes } from 'sequelize'; import { DB } from 'server/models'; +import { CommentInstance } from '../models/comment'; // getCommentDepth recursively calculates the depth of a comment, // then returns if the depth exceeds max, and the depth level export const getCommentDepth = async ( models: DB, - comment, + comment: CommentInstance, maxIterations: number, - n?: number ): Promise<[exceeded: boolean, depth: number]> => { - if (!n) { - n = 0; - } - if (!comment.parent_id) { - return [false, n]; + return [false, 0]; } - if (n >= maxIterations) { - return [true, maxIterations]; - } - const parentComment = await models.Comment.findOne({ - where: { - id: comment.parent_id, - chain: comment.chain, - }, - }); - return getCommentDepth(models, parentComment, maxIterations, n + 1); + const result: Array<{ comment_depth: number; max_depth_reached: boolean }> = + await models.sequelize.query( + ` + WITH RECURSIVE CommentDepth AS ( + SELECT id, parent_id, 0 AS depth, false AS max_depth_reached + FROM "Comments" + WHERE parent_id = :parentCommentId AND community_id = :communityId + + UNION ALL + + SELECT c.id, c.parent_id, cd.depth + 1, + CASE + WHEN cd.depth + 1 > :maxDepth THEN true + ELSE false + END AS max_depth_reached + FROM "Comments" c + INNER JOIN CommentDepth cd ON c.id = cd.parent_id::INTEGER + WHERE cd.depth <= :maxDepth and community_id = :communityId + ) + SELECT + CASE + WHEN bool_or(max_depth_reached) THEN :maxDepth + ELSE MAX(depth) + END AS comment_depth, + bool_or(max_depth_reached) AS max_depth_reached + FROM CommentDepth; + `, + { + type: QueryTypes.SELECT, + raw: true, + replacements: { + parentCommentId: comment.parent_id, + maxDepth: maxIterations, + communityId: comment.community_id, + }, + }, + ); + + return [result[0].max_depth_reached, result[0].comment_depth]; }; diff --git a/packages/commonwealth/test/e2e/hooks/e2eDbEntityHooks.spec.ts b/packages/commonwealth/test/e2e/hooks/e2eDbEntityHooks.spec.ts index e9ec3ed7170..385ab928fac 100644 --- a/packages/commonwealth/test/e2e/hooks/e2eDbEntityHooks.spec.ts +++ b/packages/commonwealth/test/e2e/hooks/e2eDbEntityHooks.spec.ts @@ -356,7 +356,7 @@ export async function createTestEntities() { await models.Comment.findOrCreate({ where: { id: -i - 1, - chain: 'cmntest', + community_id: 'cmntest', address_id: -1, text: '', thread_id: -1, @@ -375,7 +375,7 @@ export async function createTestEntities() { await models.Comment.findOrCreate({ where: { id: -i - 1 - 2, - chain: 'cmntest', + community_id: 'cmntest', address_id: -2, text: '', thread_id: -2, diff --git a/packages/commonwealth/test/integration/api/external/dbEntityHooks.spec.ts b/packages/commonwealth/test/integration/api/external/dbEntityHooks.spec.ts index 9a927da538b..e894e8cb1ea 100644 --- a/packages/commonwealth/test/integration/api/external/dbEntityHooks.spec.ts +++ b/packages/commonwealth/test/integration/api/external/dbEntityHooks.spec.ts @@ -267,7 +267,7 @@ export async function createTestEntities() { await models.Comment.findOrCreate({ where: { id: -i - 1, - chain: 'cmntest', + community_id: 'cmntest', address_id: -1, text: '', thread_id: -1, @@ -286,7 +286,7 @@ export async function createTestEntities() { await models.Comment.findOrCreate({ where: { id: -i - 1 - 2, - chain: 'cmntest', + community_id: 'cmntest', address_id: -2, text: '', thread_id: -2, diff --git a/packages/commonwealth/test/integration/api/external/getComments.spec.ts b/packages/commonwealth/test/integration/api/external/getComments.spec.ts index 1043230eed2..0752018ffc0 100644 --- a/packages/commonwealth/test/integration/api/external/getComments.spec.ts +++ b/packages/commonwealth/test/integration/api/external/getComments.spec.ts @@ -12,7 +12,7 @@ chai.use(chaiHttp); describe('getComments Tests', () => { it('should return comments with specified community_id correctly', async () => { const r: GetCommentsReq = { - community_id: testComments[0].chain, + community_id: testComments[0].community_id, count_only: false, }; const resp = await get('/api/comments', r); @@ -22,7 +22,7 @@ describe('getComments Tests', () => { it('should return count only when specified correctly', async () => { const r: GetCommentsReq = { - community_id: testComments[0].chain, + community_id: testComments[0].community_id, count_only: true, }; const resp = await get('/api/comments', r); @@ -33,7 +33,7 @@ describe('getComments Tests', () => { it('should return comments with specified addresses correctly', async () => { const r: GetCommentsReq = { - community_id: testComments[0].chain, + community_id: testComments[0].community_id, addresses: ['testAddress-1'], }; @@ -49,7 +49,7 @@ describe('getComments Tests', () => { it('should return comments with specified thread_id correctly', async () => { const r: GetCommentsReq = { - community_id: testComments[0].chain, + community_id: testComments[0].community_id, thread_ids: [parseInt(testComments[0].thread_id)], }; @@ -65,7 +65,7 @@ describe('getComments Tests', () => { it('should paginate correctly', async () => { const r: GetCommentsReq = { - community_id: testComments[0].chain, + community_id: testComments[0].community_id, addresses: ['testAddress-2'], limit: 2, }; @@ -86,7 +86,7 @@ describe('getComments Tests', () => { it('should order correctly', async () => { const r: GetCommentsReq = { - community_id: testComments[0].chain, + community_id: testComments[0].community_id, addresses: ['testAddress-2'], sort: OrderByOptions.CREATED, }; @@ -123,7 +123,7 @@ describe('getComments Tests', () => { resp = await get( '/api/comments', - { community_id: testComments[0].chain, count_only: 3 }, + { community_id: testComments[0].community_id, count_only: 3 }, true, ); diff --git a/packages/commonwealth/test/integration/api/external/getCommunities.spec.ts b/packages/commonwealth/test/integration/api/external/getCommunities.spec.ts index 1c673eb4b17..94b83d2abdd 100644 --- a/packages/commonwealth/test/integration/api/external/getCommunities.spec.ts +++ b/packages/commonwealth/test/integration/api/external/getCommunities.spec.ts @@ -44,7 +44,7 @@ describe('getCommunities Tests', () => { resp = await get( '/api/communities', - { community_id: testComments[0].chain, count_only: 3 }, + { community_id: testComments[0].community_id, count_only: 3 }, true, ); diff --git a/packages/commonwealth/test/integration/api/external/getReactions.spec.ts b/packages/commonwealth/test/integration/api/external/getReactions.spec.ts index 1e13b94187a..2eceada33b4 100644 --- a/packages/commonwealth/test/integration/api/external/getReactions.spec.ts +++ b/packages/commonwealth/test/integration/api/external/getReactions.spec.ts @@ -92,7 +92,7 @@ describe('getReactions Tests', () => { resp = await get( '/api/reactions', - { community_id: testComments[0].chain, count_only: 3 }, + { community_id: testComments[0].community_id, count_only: 3 }, true, ); diff --git a/packages/commonwealth/test/integration/api/external/getThreads.spec.ts b/packages/commonwealth/test/integration/api/external/getThreads.spec.ts index e346616370e..5524e87e9db 100644 --- a/packages/commonwealth/test/integration/api/external/getThreads.spec.ts +++ b/packages/commonwealth/test/integration/api/external/getThreads.spec.ts @@ -123,7 +123,7 @@ describe('getThreads Tests', () => { resp = await get( '/api/threads', - { community_id: testComments[0].chain, count_only: 3 }, + { community_id: testComments[0].community_id, count_only: 3 }, true, ); diff --git a/packages/commonwealth/test/integration/api/recomputeCount.spec.ts b/packages/commonwealth/test/integration/api/recomputeCount.spec.ts index 43e6e2ef14f..c2e130fb2c8 100644 --- a/packages/commonwealth/test/integration/api/recomputeCount.spec.ts +++ b/packages/commonwealth/test/integration/api/recomputeCount.spec.ts @@ -221,7 +221,7 @@ async function getCountsAll() { async function createCommentRaw() { const chain = testThreads[0].community_id; await models.sequelize.query(` - INSERT INTO "Comments" ("id", "chain", "address_id", "text", "thread_id", "plaintext", "created_at", "updated_at") + INSERT INTO "Comments" ("id", "community_id", "address_id", "text", "thread_id", "plaintext", "created_at", "updated_at") VALUES (-300, '${chain}', '${testAddresses[0].id}', '', ${testThreads[0].id}, '',now(),now()), (-400, '${chain}', '${testAddresses[0].id}', '', ${testThreads[0].id}, '',now(),now()), diff --git a/packages/commonwealth/test/integration/emitNotifications.spec.ts b/packages/commonwealth/test/integration/emitNotifications.spec.ts index fb8b28daf57..e68e1ccd06f 100644 --- a/packages/commonwealth/test/integration/emitNotifications.spec.ts +++ b/packages/commonwealth/test/integration/emitNotifications.spec.ts @@ -99,7 +99,7 @@ describe('emitNotifications tests', () => { thread_id: thread.id, address_id: userAddressId2, text: commentBody, - chain, + community_id: chain, }); //reaction = await models.Reaction.create({ diff --git a/packages/commonwealth/test/integration/getCommentDepth.spec.ts b/packages/commonwealth/test/integration/getCommentDepth.spec.ts new file mode 100644 index 00000000000..09c248e28be --- /dev/null +++ b/packages/commonwealth/test/integration/getCommentDepth.spec.ts @@ -0,0 +1,62 @@ +import { expect } from 'chai'; +import { getCommentDepth } from 'server/util/getCommentDepth'; +import models from '../../server/database'; +import { CommentInstance } from '../../server/models/comment'; +import { resetDatabase } from '../util/resetDatabase'; + +describe('getCommentDepth', () => { + const community_id = 'ethereum'; + const comments: CommentInstance[] = []; + const maxDepth = 8; + + before(async () => { + await resetDatabase(); + const address = await models.Address.findOne({ + where: { + community_id, + }, + }); + const thread = await models.Thread.create({ + community_id, + address_id: address.id, + title: 'Testing', + plaintext: '', + kind: 'discussion', + }); + let comment: CommentInstance; + for (let i = 0; i < maxDepth; i++) { + const result = await models.Comment.create({ + community_id, + thread_id: String(thread.id), + parent_id: comment ? String(comment.id) : undefined, + address_id: address.id, + text: String(i), + }); + comments.push(result); + comment = result; + } + }); + + it('should correctly calculate comment depth (recursion terminated naturally)', async () => { + for (let i = 0; i < maxDepth; i++) { + const [exceeded, depth] = await getCommentDepth( + models, + comments[i], + maxDepth, + ); + expect(exceeded).to.be.false; + expect(depth).to.equal(i); + } + }); + + it('should correctly calculate comment depth (recursion depth exceeded)', async () => { + const maxIterations = 2; + const [exceeded, depth] = await getCommentDepth( + models, + comments[comments.length - 1], + maxIterations, + ); + expect(exceeded).to.be.true; + expect(depth).to.equal(maxIterations); + }); +}); diff --git a/packages/commonwealth/test/unit/server_controllers/server_comments_controller.spec.ts b/packages/commonwealth/test/unit/server_controllers/server_comments_controller.spec.ts index ab4050fa5a0..2a495b68f6a 100644 --- a/packages/commonwealth/test/unit/server_controllers/server_comments_controller.spec.ts +++ b/packages/commonwealth/test/unit/server_controllers/server_comments_controller.spec.ts @@ -526,7 +526,7 @@ describe('ServerCommentsController', () => { thread_id: 2, text: 'Wasup', version_history: ['{"body":""}'], - chain: 'ethereum', + community_id: 'ethereum', Address: { address: '0x123', community_id: 'ethereum', @@ -625,7 +625,7 @@ describe('ServerCommentsController', () => { thread_id: 2, text: 'Wasup', version_history: ['{"body":""}'], - chain: 'ethereum', + community_id: 'ethereum', Address: { address: '0x123', community_id: 'ethereum', @@ -690,7 +690,7 @@ describe('ServerCommentsController', () => { thread_id: 2, text: 'Wasup', version_history: ['{"body":""}'], - chain: 'ethereum', + community_id: 'ethereum', Address: { address: '0x123', community_id: 'ethereum', diff --git a/packages/commonwealth/test/unit/server_controllers/server_threads_controller.spec.ts b/packages/commonwealth/test/unit/server_controllers/server_threads_controller.spec.ts index acb399fd181..83a8943c00e 100644 --- a/packages/commonwealth/test/unit/server_controllers/server_threads_controller.spec.ts +++ b/packages/commonwealth/test/unit/server_controllers/server_threads_controller.spec.ts @@ -1005,6 +1005,7 @@ describe('ServerThreadsController', () => { rollback: async () => ({}), commit: async () => ({}), }), + query: async () => [{ max_depth_reached: true, comment_depth: 8 }], }, Comment: { create: async () => ({}), diff --git a/packages/commonwealth/test/unit/server_util/getCommentDepth.spec.ts b/packages/commonwealth/test/unit/server_util/getCommentDepth.spec.ts deleted file mode 100644 index 7e3cbb41121..00000000000 --- a/packages/commonwealth/test/unit/server_util/getCommentDepth.spec.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { expect } from 'chai'; -import { getCommentDepth } from 'server/util/getCommentDepth'; -import Sinon from 'sinon'; - -const COMMENTS = { - // this initial comment is provided externally, - // so it will NOT invoke Comment.findOne in this test - '4': { - id: '4', - parent_id: '3', - }, - // --- - '3': { - id: '3', - parent_id: '2', - }, - '2': { - id: '2', - parent_id: '1', - }, - '1': { - id: '1', - parent_id: null, - }, -}; - -describe('getCommentDepth', () => { - it('should correctly calculate comment depth (recursion terminated naturally)', async () => { - const sandbox = Sinon.createSandbox(); - const db = { - Comment: { - findOne: sandbox.fake(async ({ where: { id } }) => COMMENTS[id]), - }, - }; - const comment = COMMENTS['4']; - const maxIterations = 5; - const [exceeded, depth] = await getCommentDepth( - db as any, - comment, - maxIterations - ); - expect(exceeded).to.be.false; - expect(depth).to.equal(3); - expect(db.Comment.findOne.callCount).to.equal(3); - }); - - it('should correctly calculate comment depth (recursion depth exceeded)', async () => { - const sandbox = Sinon.createSandbox(); - const db = { - Comment: { - findOne: sandbox.fake(async ({ where: { id } }) => COMMENTS[id]), - }, - }; - const comment = COMMENTS['4']; - const maxIterations = 2; - const [exceeded, depth] = await getCommentDepth( - db as any, - comment, - maxIterations - ); - expect(exceeded).to.be.true; - expect(depth).to.equal(2); - expect(db.Comment.findOne.callCount).to.equal(2); - }); -});