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

hicommonwealth / commonwealth / 17274955188

27 Aug 2025 06:09PM UTC coverage: 37.936% (+0.07%) from 37.87%
17274955188

Pull #12899

github

web-flow
Merge d2948b44a into 67b2bc393
Pull Request #12899: Removed Unsed Hook From Token Trading

1938 of 5499 branches covered (35.24%)

Branch coverage included in aggregate %.

3422 of 8630 relevant lines covered (39.65%)

45.05 hits per line

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

71.43
/libs/model/src/aggregates/user/UpdateUser.command.ts
1
import { type Command, InvalidInput, InvalidState } from '@hicommonwealth/core';
2
import * as schemas from '@hicommonwealth/schemas';
3
import { DEFAULT_NAME } from '@hicommonwealth/shared';
4
import { QueryTypes } from 'sequelize';
5
import { models } from '../../database';
6
import { authVerified } from '../../middleware/auth';
7
import { mustExist } from '../../middleware/guards';
8
import { decodeContent, emitEvent, getDelta, updateTags } from '../../utils';
9

10
export function UpdateUser(): Command<typeof schemas.UpdateUser> {
11
  return {
1✔
12
    ...schemas.UpdateUser,
13
    auth: [authVerified()],
14
    body: async ({ actor, payload }) => {
15
      // comparing number to string since command convention requires string id
16
      if (actor.user.id != payload.id)
1!
17
        throw new InvalidInput('Invalid user id');
×
18

19
      const { id, profile, tag_ids } = payload;
1✔
20
      const {
21
        slug,
22
        name,
23
        email,
24
        website,
25
        avatar_url,
26
        socials,
27
        bio: rawBio,
28
        background_image,
29
      } = profile;
1✔
30

31
      const user = (
1✔
32
        await models.User.findOne({
33
          where: { id },
34
          include: {
35
            model: models.ProfileTags,
36
          },
37
        })
38
      )?.toJSON();
39
      mustExist('User', user);
1✔
40

41
      const is_welcome_onboard_flow_complete = !!(
1✔
42
        user.is_welcome_onboard_flow_complete ||
3✔
43
        (name && name !== DEFAULT_NAME)
44
      );
45

46
      const promotional_emails_enabled =
47
        payload.promotional_emails_enabled ??
1✔
48
        user.promotional_emails_enabled ??
49
        false;
50

51
      const notify_user_name_change =
52
        payload.notify_user_name_change ??
1!
53
        user.notify_user_name_change ??
54
        false;
55

56
      const user_delta = getDelta(user, {
1✔
57
        is_welcome_onboard_flow_complete,
58
        promotional_emails_enabled,
59
        notify_user_name_change,
60
        profile: {
61
          email,
62
          slug,
63
          name,
64
          bio: rawBio && decodeContent(rawBio),
1!
65
          website,
66
          avatar_url,
67
          socials,
68
          background_image,
69
        },
70
      });
71

72
      const tags_delta = tag_ids
1!
73
        ? getDelta(
74
            { tag_ids: user.ProfileTags?.map((t) => t.tag_id) },
×
75
            {
76
              tag_ids,
77
            },
78
          )
79
        : {};
80

81
      const update_user = Object.keys(user_delta).length;
1✔
82
      const update_tags = Object.keys(tags_delta).length;
1✔
83

84
      if (update_user || update_tags) {
1!
85
        const updated = await models.sequelize.transaction(
1✔
86
          async (transaction) => {
87
            if (update_tags)
1!
88
              await updateTags(tag_ids!, user.id!, 'user_id', transaction);
×
89

90
            if (update_user) {
1!
91
              // TODO: utility to deep merge deltas
92
              const updates = {
1✔
93
                ...user_delta,
94
                profile: {
95
                  ...user.profile,
96
                  ...user_delta.profile,
97
                  background_image: {
98
                    ...user.profile.background_image,
99
                    ...user_delta.profile?.background_image,
100
                  },
101
                },
102
              };
103
              if (updates.profile.bio === '') {
1!
104
                updates.profile.bio = null;
×
105
              }
106

107
              if (
1!
108
                updates?.profile?.name &&
2✔
109
                updates?.profile?.name !== 'Anonymous'
110
              ) {
111
                const [existingUsername] = await models.sequelize.query<{
1✔
112
                  id: number;
113
                }>(
114
                  `
115
                  SELECT id
116
                  FROM "Users"
117
                  WHERE id != :id
118
                    AND (profile ->> 'name') IS DISTINCT FROM 'Anonymous'
119
                    AND (profile ->> 'name') = :profile_name
120
                  LIMIT 1;
121
                `,
122
                  {
123
                    replacements: {
124
                      id,
125
                      profile_name: updates.profile.name,
126
                    },
127
                    type: QueryTypes.SELECT,
128
                  },
129
                );
130
                if (existingUsername) {
1!
131
                  throw new InvalidState('Username already exists');
×
132
                }
133
              }
134

135
              const [, rows] = await models.User.update(updates, {
1✔
136
                where: { id: user.id },
137
                returning: true,
138
                transaction,
139
              });
140
              const updated_user = rows.at(0);
1✔
141

142
              // emit sign-up flow completed event when:
143
              if (updated_user && user_delta.is_welcome_onboard_flow_complete) {
1!
144
                await emitEvent(
1✔
145
                  models.Outbox,
146
                  [
147
                    {
148
                      event_name: 'SignUpFlowCompleted',
149
                      event_payload: {
150
                        user_id: id,
151
                        address: actor.address!,
152
                        referred_by_address: user.referred_by_address,
153
                        created_at: updated_user.created_at!,
154
                      },
155
                    },
156
                    {
157
                      event_name: 'UserUpdated',
158
                      event_payload: {
159
                        old_user: user,
160
                        new_user: updated_user,
161
                      },
162
                    },
163
                  ],
164
                  transaction,
165
                );
166
              }
167
              return updated_user;
1✔
168
            } else return user;
×
169
          },
170
        );
171

172
        return updated!;
1✔
173
      }
174

175
      // nothing changed
176
      return user;
×
177
    },
178
  };
179
}
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