ФУНКЦИИ - МЕЖПРОЕКТНАЯ КОММУНИКАЦИЯ: синхронизация профиля из Tasker
This commit is contained in:
parent
06a6160a46
commit
95225280e7
|
|
@ -535,6 +535,44 @@ app.post("/api/internal/tasker/invite-requests/cancel", asyncRoute(async (req, r
|
|||
res.json({ ok: true, taskerInviteRequest: result.taskerInviteRequest });
|
||||
}));
|
||||
|
||||
app.post("/api/internal/tasker/profile-sync", asyncRoute(async (req, res) => {
|
||||
if (!isInternalRequestAuthorized(req)) {
|
||||
res.status(config.internalAccessToken ? 401 : 503).json({
|
||||
ok: false,
|
||||
error: config.internalAccessToken ? "internal_access_unauthorized" : "internal_access_not_configured",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const snapshot = controlPlaneStore.getSnapshot({ name: "NODE.DC tasker profile sync" });
|
||||
const user = findInternalAccessUser(snapshot.data, req.body);
|
||||
|
||||
if (!user) {
|
||||
res.status(404).json({ ok: false, error: "user_not_found" });
|
||||
return;
|
||||
}
|
||||
|
||||
const patch = sanitizeTaskerProfilePatch(req.body);
|
||||
|
||||
if (Object.keys(patch).length === 0) {
|
||||
res.json({ ok: true, user, data: snapshot.data, skipped: true });
|
||||
return;
|
||||
}
|
||||
|
||||
const actor = {
|
||||
sub: "tasker-profile-sync",
|
||||
name: req.body?.source === "tasker" ? "Operational Core" : "NODE.DC profile sync",
|
||||
email: typeof req.body?.email === "string" ? req.body.email : user.email,
|
||||
source: "tasker",
|
||||
};
|
||||
const result = await controlPlaneStore.updateUserProfile(user.id, patch, actor);
|
||||
const syncResult = await syncUsersToAuthentik(result.data, [user.id], actor);
|
||||
const updatedUser = syncResult.data.users.find((candidate) => candidate.id === user.id) ?? result.user;
|
||||
|
||||
publishControlPlaneEvent("tasker.profile.updated", [user.id]);
|
||||
res.json({ ok: true, user: updatedUser, data: syncResult.data });
|
||||
}));
|
||||
|
||||
app.patch("/api/profile", requireSession, asyncRoute(async (req, res) => {
|
||||
const { actor } = getLauncherProfileContext(req.nodedcSession);
|
||||
const result = await controlPlaneStore.updateUserProfile(actor.id, sanitizeSelfProfilePatch(req.body), req.nodedcSession.user);
|
||||
|
|
@ -1735,6 +1773,37 @@ function sanitizeSelfProfilePatch(payload) {
|
|||
};
|
||||
}
|
||||
|
||||
function sanitizeTaskerProfilePatch(payload) {
|
||||
const patch = {};
|
||||
const name = firstNonEmptyString(payload?.displayName, payload?.display_name, payload?.name);
|
||||
const hasAvatar =
|
||||
Object.hasOwn(payload ?? {}, "avatarUrl") ||
|
||||
Object.hasOwn(payload ?? {}, "avatar_url") ||
|
||||
Object.hasOwn(payload ?? {}, "avatar");
|
||||
|
||||
if (name) {
|
||||
patch.name = name;
|
||||
}
|
||||
|
||||
if (hasAvatar) {
|
||||
patch.avatarUrl = nullableProfileUrl(payload?.avatarUrl ?? payload?.avatar_url ?? payload?.avatar);
|
||||
}
|
||||
|
||||
return patch;
|
||||
}
|
||||
|
||||
function firstNonEmptyString(...values) {
|
||||
for (const value of values) {
|
||||
if (typeof value === "string" && value.trim()) return value.trim();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function nullableProfileUrl(value) {
|
||||
return typeof value === "string" && value.trim() ? value.trim() : null;
|
||||
}
|
||||
|
||||
function toProvisioningResponse(provisionedUser) {
|
||||
return {
|
||||
authentikUserId: provisionedUser.authentikUserId,
|
||||
|
|
|
|||
Loading…
Reference in New Issue