Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions backend/src/api/public/v1/ossprey/activityFeed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ export async function activityFeedHandler(req: Request, res: Response): Promise<
packagePurl: r.packagePurl,
packageName: r.packageName,
packageEcosystem: r.packageEcosystem,
actorUserId: r.actorUserId,
actorName: r.actorUserId, // TODO: resolve display name from crowd.dev users/members table by actorUserId
actor: r.actor,
actorType: r.actorType,
activityType: r.activityType,
content: r.content,
Expand Down
7 changes: 7 additions & 0 deletions backend/src/api/public/v1/stewardships/actorSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { z } from 'zod'

export const actorInputSchema = z.object({
username: z.string().trim().min(1).optional().nullable(),
displayName: z.string().trim().min(1).optional().nullable(),
avatarUrl: z.string().url().optional().nullable(),
})
Comment thread
ulemons marked this conversation as resolved.
Comment thread
ulemons marked this conversation as resolved.
47 changes: 26 additions & 21 deletions backend/src/api/public/v1/stewardships/assignSteward.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,39 +8,44 @@ import { getPackagesQx } from '@/db/packagesDb'
import { ok } from '@/utils/api'
import { validateOrThrow } from '@/utils/validation'

import { actorInputSchema } from './actorSchema'

const paramsSchema = z.object({
id: z.coerce.number().int().positive(),
})

const bodySchema = z
.object({
userId: z.string().trim().min(1),
username: z.string().trim().min(1).optional().nullable(),
displayName: z.string().trim().min(1).optional().nullable(),
role: z.enum(['lead', 'co_steward']),
note: z.string().trim().min(1).optional(),
moveToAssessing: z.boolean().optional().default(false),
})
.refine((d) => (d.username == null) === (d.displayName == null), {
message: 'username and displayName must both be provided or both be absent',
path: ['displayName'],
})
const bodySchema = z.object({
steward: z
.object({
userId: z.string().trim().min(1),
username: z.string().trim().min(1).optional().nullable(),
displayName: z.string().trim().min(1).optional().nullable(),
role: z.enum(['lead', 'co_steward']),
})
.refine((d) => (d.username == null) === (d.displayName == null), {
message: 'username and displayName must both be provided or both be absent',
path: ['displayName'],
}),
note: z.string().trim().min(1).optional(),
moveToAssessing: z.boolean().optional().default(false),
actor: actorInputSchema,
})
Comment thread
ulemons marked this conversation as resolved.

export async function assignStewardHandler(req: Request, res: Response): Promise<void> {
const { id } = validateOrThrow(paramsSchema, req.params)
const { userId, username, displayName, role, note, moveToAssessing } = validateOrThrow(
bodySchema,
req.body,
)
const { steward, note, moveToAssessing, actor } = validateOrThrow(bodySchema, req.body)

const qx = await getPackagesQx()
const result = await assignSteward(qx, id, {
userId,
username,
displayName,
role,
userId: steward.userId,
username: steward.username,
displayName: steward.displayName,
role: steward.role,
note,
assignedBy: req.actor.id,
actorUsername: actor.username ?? null,
actorDisplayName: actor.displayName ?? null,
actorAvatarUrl: actor.avatarUrl ?? null,
moveToAssessing,
})

Expand Down
8 changes: 7 additions & 1 deletion backend/src/api/public/v1/stewardships/escalate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,30 @@ import { getPackagesQx } from '@/db/packagesDb'
import { ok } from '@/utils/api'
import { validateOrThrow } from '@/utils/validation'

import { actorInputSchema } from './actorSchema'

const paramsSchema = z.object({
id: z.coerce.number().int().positive(),
})

const bodySchema = z.object({
resolutionPath: z.enum(ESCALATION_RESOLUTION_PATHS),
notes: z.string().trim().min(1).optional(),
actor: actorInputSchema,
})

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

const qx = await getPackagesQx()
const stewardship = await escalateStewardship(qx, id, {
resolutionPath,
notes,
actorUserId: req.actor.id,
actorUsername: actor.username ?? null,
actorDisplayName: actor.displayName ?? null,
actorAvatarUrl: actor.avatarUrl ?? null,
})

if (!stewardship) {
Expand Down
1 change: 1 addition & 0 deletions backend/src/api/public/v1/stewardships/getMyActivity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export async function getMyActivityHandler(req: Request, res: Response): Promise
stewardshipStatus: r.stewardshipStatus,
activityType: r.activityType,
description: r.content,
actor: r.actor,
createdAt: r.createdAt,
suggestedAction: SUGGESTED_ACTIONS[r.stewardshipStatus] ?? null,
})),
Expand Down
12 changes: 2 additions & 10 deletions backend/src/api/public/v1/stewardships/getMyPackages.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import type { Request, Response } from 'express'
import { z } from 'zod'

import {
computeHealthBand,
listMyPackages,
translateActivityContent,
} from '@crowd/data-access-layer'
import { computeHealthBand, listMyPackages } from '@crowd/data-access-layer'

import { getPackagesQx } from '@/db/packagesDb'
import { ok } from '@/utils/api'
Expand Down Expand Up @@ -42,11 +38,7 @@ export async function getMyPackagesHandler(req: Request, res: Response): Promise
healthBand: computeHealthBand(r.scorecardScore),
openVulns: r.openVulns,
vulnSeverity: r.maxVulnSeverity,
lastActivityDescription: translateActivityContent(
r.lastActivityContent,
r.lastActivityType,
r.lastActivityMetadata,
),
lastActivityDescription: r.lastActivityDescription,
lastActivityAt: r.lastActivityAt ? r.lastActivityAt.toISOString() : null,
stewardshipId: r.stewardshipId,
stewardshipStatus: r.stewardshipStatus,
Expand Down
14 changes: 12 additions & 2 deletions backend/src/api/public/v1/stewardships/openStewardship.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,25 @@ import { validateOrThrow } from '@/utils/validation'

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

import { actorInputSchema } from './actorSchema'

const bodySchema = z.object({
purl: purlFieldSchema,
actor: actorInputSchema,
})

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

const qx = await getPackagesQx()
const stewardship = await openStewardshipByPurl(qx, purl, req.actor.id)
const stewardship = await openStewardshipByPurl(
qx,
purl,
req.actor.id,
actor.username ?? null,
actor.displayName ?? null,
actor.avatarUrl ?? null,
)

if (!stewardship) {
throw new NotFoundError(`Package not found: ${purl}`)
Expand Down
Loading
Loading