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

hicommonwealth / commonwealth / 17104140308

20 Aug 2025 04:16PM UTC coverage: 37.557% (-0.02%) from 37.576%
17104140308

push

github

web-flow
Merge pull request #12784 from hicommonwealth/ryan/poll-revotes

Implement revotable polls

1868 of 5393 branches covered (34.64%)

Branch coverage included in aggregate %.

0 of 6 new or added lines in 2 files covered. (0.0%)

1 existing line in 1 file now uncovered.

3360 of 8527 relevant lines covered (39.4%)

35.63 hits per line

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

5.56
/libs/model/src/aggregates/poll/createPollVote.command.ts
1
import { Command, InvalidState } from '@hicommonwealth/core';
2
import * as schemas from '@hicommonwealth/schemas';
3
import dayjs from 'dayjs';
4
import utc from 'dayjs/plugin/utc';
5
import { models } from '../../database';
6
import { authPoll } from '../../middleware';
7
import { mustBeAuthorizedPoll } from '../../middleware/guards';
8
import { getVotingWeight } from '../../services/stakeHelper';
9

10
dayjs.extend(utc);
7✔
11

12
export const CreateVotePollErrors = {
7✔
13
  InvalidOption: 'Invalid response option',
14
  PollingClosed: 'Polling already finished',
15
};
16

17
export function CreatePollVote(): Command<typeof schemas.CreatePollVote> {
18
  return {
×
19
    ...schemas.CreatePollVote,
20
    auth: [
21
      authPoll({
22
        action: 'UPDATE_POLL',
23
      }),
24
    ],
25
    body: async ({ actor, payload, context }) => {
26
      const { poll, address, thread } = mustBeAuthorizedPoll(actor, context);
×
27
      if (!poll.ends_at && dayjs(poll.ends_at).utc().isBefore(dayjs().utc())) {
×
28
        throw new InvalidState(CreateVotePollErrors.PollingClosed);
×
29
      }
30

31
      if (thread.archived_at) {
×
32
        throw new InvalidState('Cannot vote on an archived thread');
×
33
      }
34
      if (thread.locked_at) {
×
35
        throw new InvalidState('Cannot vote on a locked thread');
×
36
      }
37

38
      if (!poll.options.includes(payload.option)) {
×
39
        throw new InvalidState(CreateVotePollErrors.InvalidOption);
×
40
      }
41

42
      const calculated_voting_weight = await getVotingWeight(
×
43
        thread.topic_id,
44
        address.address,
45
      );
46

UNCOV
47
      let vote = await models.Vote.findOne({
×
48
        where: {
49
          poll_id: payload.poll_id,
50
          address: address.address,
51
        },
52
      });
53

54
      if (!vote) {
×
55
        vote = await models.Vote.create({
×
56
          poll_id: payload.poll_id,
57
          address: address.address,
58
          user_id: actor.user.id!,
59
          author_community_id: address.community_id,
60
          community_id: poll.community_id,
61
          calculated_voting_weight: calculated_voting_weight?.toString(),
62
          option: payload.option,
63
        });
NEW
64
      } else if (poll.allow_revotes) {
×
NEW
65
        vote.option = payload.option;
×
NEW
66
        vote.calculated_voting_weight = calculated_voting_weight?.toString();
×
NEW
67
        await vote.save();
×
68
      } else {
NEW
69
        throw new InvalidState('User has already voted in this poll');
×
70
      }
71

72
      return vote.toJSON();
×
73
    },
74
  };
75
}
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