feat: auto-expand presenter auth to all roles at sign-in
When a presenter or session POC signs in via their access link, expand_auth_for_person now queries both Dexie (warm cache) and the API in parallel so that cold-cache sessions are covered. All presenter records and POC sessions for the same person_id in the event are granted auth in one shot — a multi-session presenter no longer needs to click every individual link. Agreed button now also unlocks via person_id match (not only auth__kv.presenter[id]), covering the case where a presenter signed in via a different session's link and wasn't individually in auth__kv for this record yet. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,17 @@ import AE_Record_Controls from '$lib/ae_elements/AE_Record_Controls.svelte';
|
||||
let show_modal = $state(false);
|
||||
let show_help = $state(false);
|
||||
|
||||
// WHY: auth__kv.presenter[id] is only set when a sign-in link is clicked for that
|
||||
// specific presenter record. A person presenting in multiple sessions would need to
|
||||
// click every link. The person_id match covers them across all their presenter records
|
||||
// once they've signed in via any one link.
|
||||
let presenter_agree_enabled = $derived(
|
||||
$ae_loc.trusted_access ||
|
||||
!!events_auth_loc.current.auth__kv.presenter[$lq__event_presenter_obj?.event_presenter_id ?? ''] ||
|
||||
(!!events_auth_loc.current.auth__person.id &&
|
||||
events_auth_loc.current.auth__person.id === $lq__event_presenter_obj?.person_id)
|
||||
);
|
||||
|
||||
async function on_toggle(field: string, new_val: boolean) {
|
||||
await api.update_ae_obj({
|
||||
api_cfg: $ae_api,
|
||||
@@ -100,10 +111,7 @@ async function on_delete(method: 'delete' | 'disable') {
|
||||
{#if $lq__event_presenter_obj?.agree}
|
||||
<button
|
||||
type="button"
|
||||
disabled={!$ae_loc.trusted_access &&
|
||||
!events_auth_loc.current.auth__kv.presenter[
|
||||
$lq__event_presenter_obj?.event_presenter_id
|
||||
]}
|
||||
disabled={!presenter_agree_enabled}
|
||||
onclick={() => {
|
||||
$events_slct.event_presentation_id =
|
||||
$lq__event_presenter_obj?.event_presentation_id_random;
|
||||
@@ -120,10 +128,7 @@ async function on_delete(method: 'delete' | 'disable') {
|
||||
{:else}
|
||||
<button
|
||||
type="button"
|
||||
disabled={!$ae_loc.trusted_access &&
|
||||
!events_auth_loc.current.auth__kv.presenter[
|
||||
$lq__event_presenter_obj?.event_presenter_id
|
||||
]}
|
||||
disabled={!presenter_agree_enabled}
|
||||
onclick={() => {
|
||||
$events_slct.event_presentation_id =
|
||||
$lq__event_presenter_obj?.event_presentation_id_random;
|
||||
|
||||
@@ -33,7 +33,8 @@ import {
|
||||
events_trig_kv
|
||||
} from '$lib/stores/ae_events_stores';
|
||||
import { events_auth_loc } from '$lib/stores/ae_events_stores__auth.svelte';
|
||||
import { db_events } from '$lib/ae_events/db_events';
|
||||
import { db_events, type Presenter, type Session } from '$lib/ae_events/db_events';
|
||||
import { api } from '$lib/api/api';
|
||||
import { LogIn, X } from '@lucide/svelte';
|
||||
onMount(() => {
|
||||
console.log('Browser environment detected.');
|
||||
@@ -102,14 +103,12 @@ onMount(() => {
|
||||
});
|
||||
|
||||
// Grants auth for every presenter record and POC session this person holds in the event.
|
||||
// WHY: presenters and POCs can appear in multiple sessions/presentations. Clicking a single
|
||||
// sign-in link only grants auth for that specific presenter_id/session_id. This scan
|
||||
// pre-populates auth__kv for all their other roles so they don't have to click each link.
|
||||
// Runs against Dexie cache — benign no-op if cache is cold; person_id matching in auth
|
||||
// checks provides fallback coverage for navigation until cache warms.
|
||||
// WHY: a single sign-in link only grants auth for one presenter_id/session_id. This
|
||||
// queries both Dexie (fast, warm cache) AND the API (reliable, cold cache) in parallel,
|
||||
// merges the results, and pre-populates auth__kv for all roles in one shot.
|
||||
async function expand_auth_for_person(person_id: string, event_id: string) {
|
||||
try {
|
||||
const [presenter_li, session_li] = await Promise.all([
|
||||
const [dexie_presenters, dexie_sessions, api_presenters, api_sessions] = await Promise.all([
|
||||
db_events.presenter
|
||||
.where('person_id').equals(person_id)
|
||||
.filter(p => p.event_id === event_id)
|
||||
@@ -117,24 +116,52 @@ async function expand_auth_for_person(person_id: string, event_id: string) {
|
||||
db_events.session
|
||||
.where('poc_person_id').equals(person_id)
|
||||
.filter(s => s.event_id === event_id)
|
||||
.toArray()
|
||||
.toArray(),
|
||||
api.search_ae_obj({
|
||||
api_cfg: $ae_api,
|
||||
obj_type: 'event_presenter',
|
||||
search_query: { and: [
|
||||
{ field: 'event_id', op: 'eq', value: event_id },
|
||||
{ field: 'person_id', op: 'eq', value: person_id }
|
||||
]},
|
||||
limit: 200
|
||||
}).catch(() => null),
|
||||
api.search_ae_obj({
|
||||
api_cfg: $ae_api,
|
||||
obj_type: 'event_session',
|
||||
search_query: { and: [
|
||||
{ field: 'event_id', op: 'eq', value: event_id },
|
||||
{ field: 'poc_person_id', op: 'eq', value: person_id }
|
||||
]},
|
||||
limit: 200
|
||||
}).catch(() => null)
|
||||
]);
|
||||
for (const p of presenter_li) {
|
||||
if (p.event_presenter_id) {
|
||||
events_auth_loc.current.auth__kv.presenter[p.event_presenter_id] = true;
|
||||
events_auth_loc.current.auth__kv.presentation[p.event_presentation_id] = true;
|
||||
// 'read' matches what presenter_sign_in sets — truthy, but signals read-only session access
|
||||
events_auth_loc.current.auth__kv.session[p.event_session_id] = 'read';
|
||||
}
|
||||
|
||||
// Merge Dexie + API results, deduplicated by ID using plain objects (not Map)
|
||||
const api_presenter_li: Presenter[] = Array.isArray(api_presenters) ? (api_presenters as Presenter[]) : [];
|
||||
const api_session_li: Session[] = Array.isArray(api_sessions) ? (api_sessions as Session[]) : [];
|
||||
const presenter_kv: Record<string, Presenter> = {};
|
||||
for (const p of [...dexie_presenters, ...api_presenter_li]) {
|
||||
if (p.event_presenter_id) presenter_kv[p.event_presenter_id] = p;
|
||||
}
|
||||
for (const s of session_li) {
|
||||
if (s.event_session_id) {
|
||||
events_auth_loc.current.auth__kv.session[s.event_session_id] = true;
|
||||
}
|
||||
const session_kv: Record<string, Session> = {};
|
||||
for (const s of [...dexie_sessions, ...api_session_li]) {
|
||||
if (s.event_session_id) session_kv[s.event_session_id] = s;
|
||||
}
|
||||
console.log(`expand_auth_for_person: ${presenter_li.length} presenter(s), ${session_li.length} POC session(s) auto-granted`);
|
||||
|
||||
for (const p of Object.values(presenter_kv)) {
|
||||
events_auth_loc.current.auth__kv.presenter[p.event_presenter_id] = true;
|
||||
if (p.event_presentation_id) events_auth_loc.current.auth__kv.presentation[p.event_presentation_id] = true;
|
||||
// 'read' matches presenter_sign_in — truthy, signals read-only session access for presenters
|
||||
if (p.event_session_id) events_auth_loc.current.auth__kv.session[p.event_session_id] = 'read';
|
||||
}
|
||||
for (const s of Object.values(session_kv)) {
|
||||
events_auth_loc.current.auth__kv.session[s.event_session_id] = true;
|
||||
}
|
||||
|
||||
console.log(`expand_auth_for_person: ${Object.keys(presenter_kv).length} presenter(s), ${Object.keys(session_kv).length} POC session(s) auto-granted`);
|
||||
} catch (e) {
|
||||
console.warn('expand_auth_for_person: Dexie lookup failed', e);
|
||||
console.warn('expand_auth_for_person: lookup failed', e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user