-
Notifications
You must be signed in to change notification settings - Fork 731
Expand file tree
/
Copy pathcreateMemberIdentity.ts
More file actions
103 lines (87 loc) · 2.87 KB
/
createMemberIdentity.ts
File metadata and controls
103 lines (87 loc) · 2.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import type { Request, Response } from 'express'
import { z } from 'zod'
import { captureApiChange, memberEditIdentitiesAction } from '@crowd/audit-logs'
import { ConflictError, NotFoundError } from '@crowd/common'
import {
MemberField,
findMemberById,
createMemberIdentity as insertMemberIdentity,
optionsQx,
touchMemberUpdatedAt,
} from '@crowd/data-access-layer'
import { IMemberIdentity, MemberIdentityType } from '@crowd/types'
import { created } from '@/utils/api'
import { validateOrThrow } from '@/utils/validation'
const paramsSchema = z.object({
memberId: z.uuid(),
})
const bodySchema = z
.object({
value: z.string().min(1),
platform: z.string().min(1),
type: z.enum(MemberIdentityType),
source: z.string().min(1),
verified: z.boolean(),
verifiedBy: z.string().optional(),
})
.refine((data) => !data.verified || data.verifiedBy, {
message: 'verifiedBy is required when verified is true',
path: ['verifiedBy'],
})
export async function createMemberIdentity(req: Request, res: Response): Promise<void> {
const { memberId } = validateOrThrow(paramsSchema, req.params)
const data = validateOrThrow(bodySchema, req.body)
const qx = optionsQx(req)
const member = await findMemberById(qx, memberId, [MemberField.ID])
if (!member) {
throw new NotFoundError('Member not found')
}
let result!: IMemberIdentity
await captureApiChange(
req,
memberEditIdentitiesAction(memberId, async (captureOldState, captureNewState) => {
captureOldState({})
await qx.tx(async (tx) => {
try {
result = await insertMemberIdentity(
tx,
{
memberId,
platform: data.platform,
value: data.value,
type: data.type,
source: data.source,
verified: data.verified,
verifiedBy: data.verifiedBy,
},
true,
true,
)
} catch (error) {
const constraint =
error.constraint ?? error.original?.constraint ?? error.parent?.constraint
if (constraint === 'uix_memberIdentities_memberId_platform_value_type') {
throw new ConflictError('Identity already exists on this member')
}
if (constraint === 'uix_memberIdentities_platform_value_type_verified') {
throw new ConflictError('Identity already verified on another member')
}
throw error
}
// touch member updated at to trigger merge suggestion
await touchMemberUpdatedAt(tx, memberId)
})
captureNewState(result)
}),
)
created(res, {
id: result.id,
value: result.value,
platform: result.platform,
verified: result.verified,
verifiedBy: result.verifiedBy ?? null,
source: result.source ?? null,
createdAt: result.createdAt,
updatedAt: result.updatedAt,
})
}