50 lines
1.7 KiB
TypeScript
50 lines
1.7 KiB
TypeScript
|
|
import { NextResponse } from 'next/server';
|
||
|
|
import { and, eq, or, sql } from 'drizzle-orm';
|
||
|
|
|
||
|
|
import { withAuth, withPermission } from '@/lib/api/helpers';
|
||
|
|
import { db } from '@/lib/db';
|
||
|
|
import { roles, user, userPortRoles } from '@/lib/db/schema/users';
|
||
|
|
import { errorResponse } from '@/lib/errors';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Returns the set of users in the current port who can be assigned a
|
||
|
|
* residential interest. A user qualifies when ANY of their port-role
|
||
|
|
* grants either:
|
||
|
|
* - role.permissions.residential_interests.view = true, OR
|
||
|
|
* - role.permissions.residential_clients.view = true, OR
|
||
|
|
* - the per-user `residentialAccess` toggle is set on this port
|
||
|
|
*
|
||
|
|
* Used by the residential-interest detail page's "Assigned to" picker.
|
||
|
|
* Returns minimal `{ id, name, email }` rows so the dropdown stays
|
||
|
|
* fast and the JSON payload doesn't leak more than the picker needs.
|
||
|
|
*/
|
||
|
|
export const GET = withAuth(
|
||
|
|
withPermission('residential_interests', 'view', async (_req, ctx) => {
|
||
|
|
try {
|
||
|
|
const rows = await db
|
||
|
|
.selectDistinct({
|
||
|
|
id: user.id,
|
||
|
|
name: user.name,
|
||
|
|
email: user.email,
|
||
|
|
})
|
||
|
|
.from(userPortRoles)
|
||
|
|
.innerJoin(roles, eq(roles.id, userPortRoles.roleId))
|
||
|
|
.innerJoin(user, eq(user.id, userPortRoles.userId))
|
||
|
|
.where(
|
||
|
|
and(
|
||
|
|
eq(userPortRoles.portId, ctx.portId),
|
||
|
|
or(
|
||
|
|
eq(userPortRoles.residentialAccess, true),
|
||
|
|
sql`${roles.permissions}->'residential_interests'->>'view' = 'true'`,
|
||
|
|
sql`${roles.permissions}->'residential_clients'->>'view' = 'true'`,
|
||
|
|
)!,
|
||
|
|
),
|
||
|
|
)
|
||
|
|
.orderBy(user.name);
|
||
|
|
return NextResponse.json({ data: rows });
|
||
|
|
} catch (error) {
|
||
|
|
return errorResponse(error);
|
||
|
|
}
|
||
|
|
}),
|
||
|
|
);
|