• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hicommonwealth / commonwealth / 15559623773

10 Jun 2025 12:34PM UTC coverage: 40.748% (-0.08%) from 40.827%
15559623773

push

github

web-flow
Merge pull request #12366 from hicommonwealth/rotorsoft/12364-topic-gate-getthreadsbyids

Adds new query for single ids and protect private topics

1771 of 4719 branches covered (37.53%)

Branch coverage included in aggregate %.

0 of 18 new or added lines in 4 files covered. (0.0%)

2 existing lines in 2 files now uncovered.

3206 of 7495 relevant lines covered (42.78%)

37.45 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/libs/model/src/aggregates/thread/GetThreadById.query.ts
1
import { Query } from '@hicommonwealth/core';
2
import * as schemas from '@hicommonwealth/schemas';
3
import { QueryTypes } from 'sequelize';
4
import { z } from 'zod';
5
import { models, sequelize } from '../../database';
6
import { authOptionalForThread, UnauthorizedView } from '../../middleware';
7
import { filterGates, joinGates, withGates } from '../../utils/gating';
8

9
export function GetThreadById(): Query<typeof schemas.GetThreadById> {
NEW
10
  return {
×
11
    ...schemas.GetThreadById,
12
    auth: [authOptionalForThread],
13
    secure: true,
14
    body: async ({ actor, payload, context }) => {
NEW
15
      const { thread_id } = payload;
×
NEW
16
      const address_id = context?.address?.id;
×
17

18
      // find open gates in thread's community
NEW
19
      const [open_thread] = await sequelize.query<{
×
20
        id: number;
21
      }>(
22
        `
23
        ${withGates(address_id)}
24
        SELECT T.id
25
        FROM
26
          "Threads" T
27
          ${joinGates(address_id)}
28
        WHERE
29
          T.id = :thread_id
30
          ${filterGates(address_id)}
31
        `,
32
        {
33
          type: QueryTypes.SELECT,
34
          replacements: {
35
            address_id,
36
            community_id: context?.community_id,
37
            thread_id,
38
          },
39
        },
40
      );
NEW
41
      if (!open_thread) throw new UnauthorizedView(actor);
×
42

43
      // TODO: refactor using plain sql and add gating filters
NEW
44
      const thread = await models.Thread.findOne({
×
45
        where: { id: thread_id },
46
        include: [
47
          {
48
            model: models.Address,
49
            as: 'Address',
50
            include: [
51
              {
52
                model: models.User,
53
                as: 'User',
54
                required: true,
55
                attributes: ['id', 'profile', 'tier'],
56
              },
57
            ],
58
          },
59
          {
60
            model: models.Address,
61
            as: 'collaborators',
62
            include: [
63
              {
64
                model: models.User,
65
                as: 'User',
66
                required: true,
67
                attributes: ['id', 'profile', 'tier'],
68
              },
69
            ],
70
          },
71
          {
72
            model: models.Topic,
73
            as: 'topic',
74
            required: true,
75
          },
76
          {
77
            model: models.Reaction,
78
            as: 'reactions',
79
            include: [
80
              {
81
                model: models.Address,
82
                as: 'Address',
83
                required: true,
84
                include: [
85
                  {
86
                    model: models.User,
87
                    as: 'User',
88
                    required: true,
89
                    attributes: ['id', 'profile', 'tier'],
90
                  },
91
                ],
92
              },
93
            ],
94
          },
95
          {
96
            model: models.ContestAction,
97
            where: { action: 'upvoted' },
98
            required: false,
99
            attributes: ['content_id', 'thread_id'],
100
            include: [
101
              {
102
                model: models.Contest,
103
                on: {
104
                  contest_id: sequelize.where(
105
                    sequelize.col('"ContestActions".contest_id'),
106
                    '=',
107
                    sequelize.col('"ContestActions->Contest".contest_id'),
108
                  ),
109
                  contest_address: sequelize.where(
110
                    sequelize.col('"ContestActions".contest_address'),
111
                    '=',
112
                    sequelize.col('"ContestActions->Contest".contest_address'),
113
                  ),
114
                },
115
                attributes: [
116
                  'contest_id',
117
                  'contest_address',
118
                  'score',
119
                  'start_time',
120
                  'end_time',
121
                ],
122
                include: [
123
                  {
124
                    model: models.ContestManager,
125
                    attributes: ['name', 'cancelled', 'interval'],
126
                  },
127
                ],
128
              },
129
            ],
130
          },
131
          { model: models.ThreadVersionHistory },
132
        ],
133
      });
134

NEW
135
      return thread!.toJSON() as z.infer<typeof schemas.ThreadView>;
×
136
    },
137
  };
138
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc