Skip to content

Commit b11748e

Browse files
authored
feat: add actor interface (#4255)
Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>
1 parent 43395bb commit b11748e

12 files changed

Lines changed: 344 additions & 123 deletions

File tree

backend/src/api/public/v1/ossprey/activityFeed.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ export async function activityFeedHandler(req: Request, res: Response): Promise<
2525
packagePurl: r.packagePurl,
2626
packageName: r.packageName,
2727
packageEcosystem: r.packageEcosystem,
28-
actorUserId: r.actorUserId,
29-
actorName: r.actorUserId, // TODO: resolve display name from crowd.dev users/members table by actorUserId
28+
actor: r.actor,
3029
actorType: r.actorType,
3130
activityType: r.activityType,
3231
content: r.content,
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { z } from 'zod'
2+
3+
export const actorInputSchema = z.object({
4+
username: z.string().trim().min(1).optional().nullable(),
5+
displayName: z.string().trim().min(1).optional().nullable(),
6+
avatarUrl: z.string().url().optional().nullable(),
7+
})

backend/src/api/public/v1/stewardships/assignSteward.ts

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,39 +8,44 @@ import { getPackagesQx } from '@/db/packagesDb'
88
import { ok } from '@/utils/api'
99
import { validateOrThrow } from '@/utils/validation'
1010

11+
import { actorInputSchema } from './actorSchema'
12+
1113
const paramsSchema = z.object({
1214
id: z.coerce.number().int().positive(),
1315
})
1416

15-
const bodySchema = z
16-
.object({
17-
userId: z.string().trim().min(1),
18-
username: z.string().trim().min(1).optional().nullable(),
19-
displayName: z.string().trim().min(1).optional().nullable(),
20-
role: z.enum(['lead', 'co_steward']),
21-
note: z.string().trim().min(1).optional(),
22-
moveToAssessing: z.boolean().optional().default(false),
23-
})
24-
.refine((d) => (d.username == null) === (d.displayName == null), {
25-
message: 'username and displayName must both be provided or both be absent',
26-
path: ['displayName'],
27-
})
17+
const bodySchema = z.object({
18+
steward: z
19+
.object({
20+
userId: z.string().trim().min(1),
21+
username: z.string().trim().min(1).optional().nullable(),
22+
displayName: z.string().trim().min(1).optional().nullable(),
23+
role: z.enum(['lead', 'co_steward']),
24+
})
25+
.refine((d) => (d.username == null) === (d.displayName == null), {
26+
message: 'username and displayName must both be provided or both be absent',
27+
path: ['displayName'],
28+
}),
29+
note: z.string().trim().min(1).optional(),
30+
moveToAssessing: z.boolean().optional().default(false),
31+
actor: actorInputSchema,
32+
})
2833

2934
export async function assignStewardHandler(req: Request, res: Response): Promise<void> {
3035
const { id } = validateOrThrow(paramsSchema, req.params)
31-
const { userId, username, displayName, role, note, moveToAssessing } = validateOrThrow(
32-
bodySchema,
33-
req.body,
34-
)
36+
const { steward, note, moveToAssessing, actor } = validateOrThrow(bodySchema, req.body)
3537

3638
const qx = await getPackagesQx()
3739
const result = await assignSteward(qx, id, {
38-
userId,
39-
username,
40-
displayName,
41-
role,
40+
userId: steward.userId,
41+
username: steward.username,
42+
displayName: steward.displayName,
43+
role: steward.role,
4244
note,
4345
assignedBy: req.actor.id,
46+
actorUsername: actor.username ?? null,
47+
actorDisplayName: actor.displayName ?? null,
48+
actorAvatarUrl: actor.avatarUrl ?? null,
4449
moveToAssessing,
4550
})
4651

backend/src/api/public/v1/stewardships/escalate.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,30 @@ import { getPackagesQx } from '@/db/packagesDb'
88
import { ok } from '@/utils/api'
99
import { validateOrThrow } from '@/utils/validation'
1010

11+
import { actorInputSchema } from './actorSchema'
12+
1113
const paramsSchema = z.object({
1214
id: z.coerce.number().int().positive(),
1315
})
1416

1517
const bodySchema = z.object({
1618
resolutionPath: z.enum(ESCALATION_RESOLUTION_PATHS),
1719
notes: z.string().trim().min(1).optional(),
20+
actor: actorInputSchema,
1821
})
1922

2023
export async function escalateHandler(req: Request, res: Response): Promise<void> {
2124
const { id } = validateOrThrow(paramsSchema, req.params)
22-
const { resolutionPath, notes } = validateOrThrow(bodySchema, req.body)
25+
const { resolutionPath, notes, actor } = validateOrThrow(bodySchema, req.body)
2326

2427
const qx = await getPackagesQx()
2528
const stewardship = await escalateStewardship(qx, id, {
2629
resolutionPath,
2730
notes,
2831
actorUserId: req.actor.id,
32+
actorUsername: actor.username ?? null,
33+
actorDisplayName: actor.displayName ?? null,
34+
actorAvatarUrl: actor.avatarUrl ?? null,
2935
})
3036

3137
if (!stewardship) {

backend/src/api/public/v1/stewardships/getMyActivity.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ export async function getMyActivityHandler(req: Request, res: Response): Promise
6363
stewardshipStatus: r.stewardshipStatus,
6464
activityType: r.activityType,
6565
description: r.content,
66+
actor: r.actor,
6667
createdAt: r.createdAt,
6768
suggestedAction: SUGGESTED_ACTIONS[r.stewardshipStatus] ?? null,
6869
})),

backend/src/api/public/v1/stewardships/getMyPackages.ts

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
import type { Request, Response } from 'express'
22
import { z } from 'zod'
33

4-
import {
5-
computeHealthBand,
6-
listMyPackages,
7-
translateActivityContent,
8-
} from '@crowd/data-access-layer'
4+
import { computeHealthBand, listMyPackages } from '@crowd/data-access-layer'
95

106
import { getPackagesQx } from '@/db/packagesDb'
117
import { ok } from '@/utils/api'
@@ -42,11 +38,7 @@ export async function getMyPackagesHandler(req: Request, res: Response): Promise
4238
healthBand: computeHealthBand(r.scorecardScore),
4339
openVulns: r.openVulns,
4440
vulnSeverity: r.maxVulnSeverity,
45-
lastActivityDescription: translateActivityContent(
46-
r.lastActivityContent,
47-
r.lastActivityType,
48-
r.lastActivityMetadata,
49-
),
41+
lastActivityDescription: r.lastActivityDescription,
5042
lastActivityAt: r.lastActivityAt ? r.lastActivityAt.toISOString() : null,
5143
stewardshipId: r.stewardshipId,
5244
stewardshipStatus: r.stewardshipStatus,

backend/src/api/public/v1/stewardships/openStewardship.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,25 @@ import { validateOrThrow } from '@/utils/validation'
1010

1111
import { purlFieldSchema } from '../packages/purl'
1212

13+
import { actorInputSchema } from './actorSchema'
14+
1315
const bodySchema = z.object({
1416
purl: purlFieldSchema,
17+
actor: actorInputSchema,
1518
})
1619

1720
export async function openStewardship(req: Request, res: Response): Promise<void> {
18-
const { purl } = validateOrThrow(bodySchema, req.body)
21+
const { purl, actor } = validateOrThrow(bodySchema, req.body)
1922

2023
const qx = await getPackagesQx()
21-
const stewardship = await openStewardshipByPurl(qx, purl, req.actor.id)
24+
const stewardship = await openStewardshipByPurl(
25+
qx,
26+
purl,
27+
req.actor.id,
28+
actor.username ?? null,
29+
actor.displayName ?? null,
30+
actor.avatarUrl ?? null,
31+
)
2232

2333
if (!stewardship) {
2434
throw new NotFoundError(`Package not found: ${purl}`)

0 commit comments

Comments
 (0)