Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 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 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 7x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 6x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 33x 27x 27x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 33x 1x | import {type IMeta, handler} from '@feasibleone/blong';
import * as model from './accessModel.ts';
type KnexQb = any;
/**
* Return the currently authenticated user's own profile: account details
* (username, email, active flag), the persisted preferred language
* (`core.property` key `preferredLanguage`), the granted roles (`hasRole`
* graph edges) and — when available — the linked `party.person` record
* (resolved through the `user --hasProfile--> person` graph edge).
*
* The `party.person` part is best-effort: it is only returned when the
* `party_person` table exists AND the user has a `hasProfile` edge (the
* standalone access suite has no party schema, so callers there simply see
* `person: null` — the profile page then falls back to no personal details).
*/
export default handler(
({lib: {crockfordDecode}}) =>
async function accessProfileGet(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_params: Record<string, never>,
$meta: IMeta,
): Promise<{
userId: string;
userName: string | null;
emailAddress: string | null;
isActive: boolean;
preferredLanguage: string | null;
roles: Array<{roleId: string; roleName: string}>;
person: {
personId: string;
firstName: string;
middleName: string | null;
lastName: string;
birthDate: string | null;
gender: string | null;
nationality: string | null;
occupation: string | null;
} | null;
}> {
const qb: KnexQb = this.config?.context?.queryBuilder;
if (!qb) throw new Error('Database not available');
const actorId = $meta?.auth?.actorId as string | undefined;
if (!actorId) throw new Error('Missing actor identity in request metadata');
const userIdBuf = Buffer.from(crockfordDecode(actorId));
const user = await qb
.select('u.emailAddress', 'u.isActive', 'r.resourceName')
.from('access_user as u')
.join('core_resource as r', 'r.resourceId', 'u.userId')
.where('u.userId', userIdBuf)
.first();
const pref = await qb('core_property')
.select('propertyValue')
.where('resourceId', userIdBuf)
.where('propertyName', 'preferredLanguage')
.first();
const roles = await model.edgeRowsWithNames(
qb,
userIdBuf,
'hasRole',
'access_role',
'roleId',
'roleName',
);
// Best-effort: party.person only exists when the party realm is
// part of the suite. A missing table (or a user without a linked
// person) simply yields `person: null` — no personal details.
let person: Awaited<ReturnType<typeof accessProfileGet>>['person'] = null;
try {
const row = await qb
.select(
'p.personId',
'p.firstName',
'p.middleName',
'p.lastName',
'p.birthDate',
'p.gender',
'p.nationality',
'p.occupation',
)
.from('core_triple as t')
.join('party_person as p', 'p.personId', 't.objectId')
.where('t.subjectId', userIdBuf)
.where('t.predicateName', 'hasProfile')
.first();
if (row) {
person = {
personId: Buffer.from(row.personId).toString('base64'),
firstName: row.firstName,
middleName: row.middleName ?? null,
lastName: row.lastName,
birthDate: row.birthDate ?? null,
gender: row.gender ?? null,
nationality: row.nationality ?? null,
occupation: row.occupation ?? null,
};
}
} catch {
// party_person table is not present — treat as no personal data.
}
return {
userId: actorId,
userName: user?.resourceName ?? null,
emailAddress: user?.emailAddress ?? null,
isActive: user?.isActive ? Boolean(user.isActive) : false,
preferredLanguage:
(pref?.propertyValue as string | undefined | null) ?? null,
roles: (roles ?? []).map(r => ({
roleId: r.roleId as string,
roleName: r.roleName as string,
})),
person,
};
},
);
|