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 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 7x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 1x | import {type IMeta, handler} from '@feasibleone/blong';
type KnexQb = any;
/**
* Update the currently authenticated user's own profile. The actor id always
* comes from `$meta.auth.actorId` (the token's `sub` claim) — a caller can
* never edit someone else's record.
*
* Supported fields (all optional — only provided ones are changed):
* - `emailAddress` → the `access_user` row
* - `preferredLanguage` → the `core.property` key `preferredLanguage`
* - `firstName` / `middleName` / `lastName` → the linked `party.person` row
* (best-effort: only when the user actually has a `hasProfile` edge and the
* `party_person` table exists — otherwise these are silently ignored, which
* is the documented fallback for suites without the party realm)
*/
export default handler(
({lib: {crockfordDecode}}) =>
async function accessProfileEdit(
params: {
firstName?: string | null;
middleName?: string | null;
lastName?: string | null;
emailAddress?: string | null;
preferredLanguage?: string | null;
},
$meta: IMeta,
): Promise<{success: boolean}> {
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));
if (params.emailAddress !== undefined) {
await qb('access_user')
.where('userId', userIdBuf)
.update({emailAddress: params.emailAddress});
}
if (params.preferredLanguage !== undefined) {
await qb('core_property')
.insert({
resourceId: userIdBuf,
propertyName: 'preferredLanguage',
propertyValue: params.preferredLanguage,
})
.onConflict(['resourceId', 'propertyName'])
.merge({propertyValue: params.preferredLanguage});
}
const namePatch: Record<string, string | null> = {};
if (params.firstName !== undefined) namePatch.firstName = params.firstName;
if (params.middleName !== undefined) namePatch.middleName = params.middleName;
if (params.lastName !== undefined) namePatch.lastName = params.lastName;
if (Object.keys(namePatch).length) {
try {
const person = await qb
.select('t.objectId')
.from('core_triple as t')
.where('t.subjectId', userIdBuf)
.where('t.predicateName', 'hasProfile')
.first();
if (person) {
await qb('party_person')
.where('personId', person.objectId)
.update(namePatch);
}
} catch {
// party_person table is not present — name fields cannot be
// stored; this is the documented no-personal-data fallback.
}
}
return {success: true};
},
);
|