Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor getTopics #9584

Merged
merged 12 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions libs/model/src/community/GetTopics.query.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { Query } from '@hicommonwealth/core';
import * as schemas from '@hicommonwealth/schemas';
import { QueryTypes } from 'sequelize';
import { z } from 'zod';
import { models } from '../database';

export function GetTopics(): Query<typeof schemas.GetTopics> {
return {
...schemas.GetTopics,
auth: [],
secure: false,
body: async ({ payload }) => {
const { community_id, with_contest_managers } = payload;

const contest_managers = with_contest_managers
? `
SELECT
td.*,
coalesce((
SELECT
jsonb_agg(jsonb_set(to_jsonb (cm), -- Convert the contest manager (cm) row to JSONB
'{content}', -- Set the 'content' key in the resulting JSONB
coalesce((
SELECT
jsonb_agg(ca) -- Aggregates the filtered actions into content
FROM "ContestActions" ca
WHERE
ca.contest_address = cm.contest_address
AND ca.action = 'added'
AND ca.created_at > co.start_time
AND ca.created_at < co.end_time), '[]'::jsonb) -- Use an empty array as fallback if no actions are found
))
FROM "ContestTopics" ct
LEFT JOIN "ContestManagers" cm ON cm.contest_address = ct.contest_address
JOIN (
-- Subquery to get the max contest_id, start_time, and end_time for each contest address
SELECT
contest_address,
max(contest_id) AS max_contest_id,
max(start_time) AS start_time,
max(end_time) AS end_time
FROM
"Contests"
GROUP BY
contest_address) co ON cm.contest_address = co.contest_address
WHERE
ct.topic_id = td.id
AND cm.community_id = :community_id
AND COALESCE(cm.cancelled, FALSE) = FALSE -- Exclude cancelled managers
AND (cm.interval = 0
AND now() < co.end_time -- Check if the interval is 0 and the contest is ongoing
OR cm.interval > 0 -- Or if there is a valid interval
)), '[]'::jsonb) AS active_contest_managers
FROM
topic_data td
`
: `SELECT *, '[]'::json as active_contest_managers FROM topic_data`;

const sql = `
WITH topic_data AS (
SELECT
id,
name,
community_id,
description,
telegram,
featured_in_sidebar,
featured_in_new_post,
default_offchain_template,
"order",
channel_id,
group_ids,
weighted_voting,
token_symbol,
vote_weight_multiplier,
created_at::text AS created_at,
updated_at::text AS updated_at,
deleted_at::text AS deleted_at,
(
SELECT
count(*)::int
FROM
"Threads"
WHERE
community_id = :community_id
AND topic_id = t.id
AND deleted_at IS NULL) AS total_threads
FROM
"Topics" t
WHERE
t.community_id = :community_id
AND t.deleted_at IS NULL
)
${contest_managers}
`;

return await models.sequelize.query<z.infer<typeof schemas.TopicView>>(
sql,
{
replacements: { community_id },
type: QueryTypes.SELECT,
raw: true,
},
);
},
};
}
1 change: 1 addition & 0 deletions libs/model/src/community/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export * from './GetCommunityStake.query';
export * from './GetMembers.query';
export * from './GetStakeHistoricalPrice.query';
export * from './GetStakeTransaction.query';
export * from './GetTopics.query';
export * from './JoinCommunity.command';
export * from './RefreshCommunityMemberships.command';
export * from './RefreshCustomDomain.query';
Expand Down
2 changes: 1 addition & 1 deletion libs/model/src/thread/CreateThread.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export function CreateThread(): Command<
...schemas.CreateThread,
auth: [
isAuthorized({
action: schemas.PermissionEnum.CREATE_THREAD
action: schemas.PermissionEnum.CREATE_THREAD,
}),
verifyThreadSignature,
],
Expand Down
35 changes: 28 additions & 7 deletions libs/model/test/community/community-lifecycle.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@ import {
dispose,
query,
} from '@hicommonwealth/core';
import {
PermissionEnum,
TopicWeightedVoting,
} from '@hicommonwealth/schemas';
import { PermissionEnum, TopicWeightedVoting } from '@hicommonwealth/schemas';
import { ChainBase, ChainType } from '@hicommonwealth/shared';
import { Chance } from 'chance';
import { CreateTopic } from 'model/src/community/CreateTopic.command';
Expand All @@ -25,6 +22,7 @@ import {
DeleteTopic,
GetCommunities,
GetMembers,
GetTopics,
JoinCommunity,
JoinCommunityErrors,
MAX_GROUPS_PER_COMMUNITY,
Expand Down Expand Up @@ -364,15 +362,30 @@ describe('Community lifecycle', () => {
payload: buildCreateGroupPayload(community.id, [
{
id: 1,
permissions: [PermissionEnum.CREATE_COMMENT, PermissionEnum.CREATE_THREAD, PermissionEnum.CREATE_COMMENT_REACTION,PermissionEnum.CREATE_THREAD_REACTION],
permissions: [
PermissionEnum.CREATE_COMMENT,
PermissionEnum.CREATE_THREAD,
PermissionEnum.CREATE_COMMENT_REACTION,
PermissionEnum.CREATE_THREAD_REACTION,
],
},
{
id: 2,
permissions: [PermissionEnum.CREATE_COMMENT, PermissionEnum.CREATE_THREAD, PermissionEnum.CREATE_COMMENT_REACTION,PermissionEnum.CREATE_THREAD_REACTION],
permissions: [
PermissionEnum.CREATE_COMMENT,
PermissionEnum.CREATE_THREAD,
PermissionEnum.CREATE_COMMENT_REACTION,
PermissionEnum.CREATE_THREAD_REACTION,
],
},
{
id: 3,
permissions: [PermissionEnum.CREATE_COMMENT, PermissionEnum.CREATE_THREAD, PermissionEnum.CREATE_COMMENT_REACTION,PermissionEnum.CREATE_THREAD_REACTION],
permissions: [
PermissionEnum.CREATE_COMMENT,
PermissionEnum.CREATE_THREAD,
PermissionEnum.CREATE_COMMENT_REACTION,
PermissionEnum.CREATE_THREAD_REACTION,
],
},
]),
}),
Expand Down Expand Up @@ -566,6 +579,14 @@ describe('Community lifecycle', () => {
}),
).rejects.toThrow(InvalidActor);
});

test('should get topics', async () => {
const topics = await query(GetTopics(), {
actor: superAdminActor,
payload: { community_id: community.id, with_contest_managers: false },
});
expect(topics?.length).toBe(4);
});
});

describe('updates', () => {
Expand Down
31 changes: 31 additions & 0 deletions libs/schemas/src/queries/community.schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ import {
Community,
CommunityMember,
CommunityStake,
ContestManager,
ExtendedCommunity,
Topic,
} from '../entities';
import * as projections from '../projections';
import { PG_INT } from '../utils';
import { PaginatedResultSchema, PaginationParamsSchema } from './pagination';

Expand Down Expand Up @@ -159,3 +162,31 @@ export const GetStakeHistoricalPrice = {
})
.array(),
};

export const ConstestManagerView = ContestManager.extend({
created_at: z.string(),
topics: z.undefined(),
contests: z.undefined(),
content: z.array(
projections.ContestAction.extend({
created_at: z.string(),
}),
),
});

export const TopicView = Topic.extend({
created_at: z.string(),
updated_at: z.string().nullish(),
deleted_at: z.string().nullish(),
contest_topics: z.undefined(),
total_threads: z.number(),
active_contest_managers: z.array(ConstestManagerView),
});

export const GetTopics = {
input: z.object({
community_id: z.string(),
with_contest_managers: z.boolean().optional(),
}),
output: z.array(TopicView),
};
2 changes: 1 addition & 1 deletion libs/schemas/src/queries/thread.schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { z } from 'zod';
import { Thread } from '../entities';
import {
DiscordMetaSchema,
PG_INT,
linksSchema,
paginationSchema,
PG_INT,
} from '../utils';

export const OrderByQueriesKeys = z.enum([
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ProposalType } from '@hicommonwealth/shared';
import type moment from 'moment';
import type Topic from './Topic';
import type { Topic } from './Topic';
import type { IUniqueId } from './interfaces';

class AbridgedThread implements IUniqueId {
Expand Down
5 changes: 2 additions & 3 deletions packages/commonwealth/client/scripts/models/Thread.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import moment, { Moment } from 'moment';
import { z } from 'zod';
import Comment from './Comment';
import type { ReactionType } from './Reaction';
import Topic from './Topic';
import type { Topic } from './Topic';
import type { IUniqueId } from './interfaces';
import type { ThreadKind, ThreadStage } from './types';

Expand Down Expand Up @@ -375,8 +375,7 @@ export class Thread implements IUniqueId {
this.identifier = `${id}`;
this.createdAt = moment(created_at);
this.updatedAt = moment(updated_at);
// @ts-expect-error StrictNullChecks
this.topic = topic?.id ? new Topic({ ...(topic || {}) } as any) : null;
this.topic = { ...topic };
mzparacha marked this conversation as resolved.
Show resolved Hide resolved
this.kind = kind;
this.stage = stage;
this.authorCommunity = Address?.community_id;
Expand Down
77 changes: 1 addition & 76 deletions packages/commonwealth/client/scripts/models/Topic.ts
Original file line number Diff line number Diff line change
@@ -1,79 +1,4 @@
import * as schemas from '@hicommonwealth/schemas';
import { z } from 'zod';

const ActiveContestManagers = z.object({
content: z.array(schemas.ContestAction),
contest_manager: schemas.ContestManager,
});

type TopicAttributesBase = z.infer<typeof schemas.Topic>;

type TopicAttributesExtended = TopicAttributesBase & {
active_contest_managers: Array<z.infer<typeof ActiveContestManagers>>;
total_threads: number;
};

export type TopicAttributes = TopicAttributesExtended;

class Topic {
public readonly name: TopicAttributes['name'];
public readonly id: TopicAttributes['id'];
public readonly description: TopicAttributes['description'];
public readonly telegram: TopicAttributes['telegram'];
public readonly communityId: TopicAttributes['community_id'];
public readonly channelId: TopicAttributes['channel_id'];
public readonly featuredInSidebar: TopicAttributes['featured_in_sidebar'];
public readonly featuredInNewPost: TopicAttributes['featured_in_new_post'];
public order: TopicAttributes['order'];
public readonly defaultOffchainTemplate: TopicAttributes['default_offchain_template'];
public totalThreads: TopicAttributes['total_threads'];
public readonly activeContestManagers: TopicAttributes['active_contest_managers'];
public readonly groupIds: TopicAttributes['group_ids'];
public readonly defaultOffchainTemplateBackup: TopicAttributes['default_offchain_template_backup'];
public readonly weightedVoting: TopicAttributes['weighted_voting'];
public readonly tokenAddress: TopicAttributes['token_address'];
public readonly tokenSymbol: TopicAttributes['token_symbol'];
public readonly voteWeightMultiplier: TopicAttributes['vote_weight_multiplier'];

constructor({
name,
id,
description,
telegram,
community_id,
featured_in_sidebar,
featured_in_new_post,
order,
default_offchain_template,
total_threads,
channel_id,
active_contest_managers,
group_ids,
default_offchain_template_backup,
weighted_voting,
token_address,
token_symbol,
vote_weight_multiplier,
}: TopicAttributes) {
this.name = name;
this.id = id;
this.description = description;
this.telegram = telegram;
this.communityId = community_id;
this.featuredInSidebar = featured_in_sidebar;
this.featuredInNewPost = featured_in_new_post;
this.order = order;
this.defaultOffchainTemplate = default_offchain_template;
this.totalThreads = total_threads || 0;
this.channelId = channel_id;
this.activeContestManagers = active_contest_managers || [];
this.groupIds = group_ids;
this.defaultOffchainTemplateBackup = default_offchain_template_backup;
this.weightedVoting = weighted_voting;
this.tokenAddress = token_address;
this.tokenSymbol = token_symbol;
this.voteWeightMultiplier = vote_weight_multiplier;
}
}

export default Topic;
export type Topic = z.infer<typeof schemas.TopicView>;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { AxiosResponse } from 'axios';
import Thread from 'models/Thread';
import Topic from 'models/Topic';
import type { Topic } from 'models/Topic';
import { ThreadKind, ThreadStage } from 'models/types';

type ActivityResponse = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { toCanvasSignedDataApiArgs } from '@hicommonwealth/shared';
import { signThread } from 'controllers/server/sessions';
import Topic from 'models/Topic';
import type { Topic } from 'models/Topic';
import { ThreadStage } from 'models/types';
import useUserOnboardingSliderMutationStore from 'state/ui/userTrainingCards';
import { trpc } from 'utils/trpcClient';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Thread from 'models/Thread';
import Topic from 'models/Topic';
import type { Topic } from 'models/Topic';
import { ApiEndpoints, queryClient } from 'state/api/config';

/**
Expand Down
Loading
Loading