caterium-app/tests/recovery/employee-session.mjs
pavlov346346-source 1e644e6dfb
Fix employee sync and expose mobile profile/logout (#37)
Keep notification-read state personal to user/company, preserve server read-only sections during staff synchronization, and respect separate order-create/edit/delete rights. Add visible mobile header session actions and a sticky logout that survives profile RPC failure; scope asynchronous profile/branding to user and workspace. Targeted browser suites and isolated SQL recovery tests passed in run 35506145405, iPhone screenshots reviewed. Full main QA remains required before production promotion. Workspace branding RPC migration is included but has NOT been applied to production Supabase; older servers retain safe owner-only fallback. No live membership/business-data repair is claimed without identifying the reported employee.
2026-09-20 13:55:56 +03:00

21 lines
2.5 KiB
JavaScript

import assert from 'node:assert/strict';
export async function run(db,{owner,employee,workspace,foreign}){
const q=(sql,args=[])=>db.query(sql,args),one=async(sql,args)=>(await q(sql,args)).rows[0];
const actor=async id=>{await db.exec('reset role');await q("select set_config('request.jwt.claim.sub',$1,false),set_config('request.jwt.claims',$2,false)",[id,JSON.stringify({sub:id,aal:'aal1',role:'authenticated'})]);await db.exec('set role authenticated')};
const brand=async (id=workspace)=>(await one('select public.caterium_workspace_sidebar_brand($1) as b',[id])).b;
await db.exec('reset role');const before=await one('select payload,revision from public.sun_app_state where workspace_id=$1',[workspace]);
await actor(owner);assert.equal((await brand()).variant,'solnce');
await actor(employee);assert.equal((await brand()).variant,'solnce','active company employee inherits sidebar identity');
await assert.rejects(brand(foreign),/Нет доступа/);
await assert.rejects(q('update public.caterium_sidebar_brand_assignment set workspace_id=$1',[foreign]),/permission denied/);
await db.exec('reset role');await q('update public.sun_workspace_members set is_active=false where user_id=$1 and workspace_id=$2',[employee,workspace]);
await actor(employee);await assert.rejects(brand(),/Нет доступа/);
await db.exec('reset role');await q('update public.sun_workspace_members set is_active=true where user_id=$1 and workspace_id=$2',[employee,workspace]);await q('update auth.users set email_confirmed_at=null where id=$1',[employee]);
await actor(employee);await assert.rejects(brand(),/Нет доступа/);
await db.exec('reset role');await q('update auth.users set email_confirmed_at=now() where id=$1',[employee]);await q("insert into public.sun_workspace_members(workspace_id,user_id,role,is_active,permissions) values($1,$2,'viewer',true,public.sun_role_default_permissions('viewer'))",[foreign,employee]);
await actor(employee);assert.equal((await brand(foreign)).variant,'caterium','same employee in another workspace does not carry branding');
await db.exec('reset role');const after=await one('select payload,revision from public.sun_app_state where workspace_id=$1',[workspace]);assert.deepEqual(after,before,'branding never writes business state');
await db.exec('set role anon');await assert.rejects(brand(),/permission denied/);await db.exec('reset role');
console.log('PASS employee sidebar: active membership, selected workspace, confirmation, no branding spoof, no business-data changes');
}