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_modal = $state(false);
|
||||||
let show_help = $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) {
|
async function on_toggle(field: string, new_val: boolean) {
|
||||||
await api.update_ae_obj({
|
await api.update_ae_obj({
|
||||||
api_cfg: $ae_api,
|
api_cfg: $ae_api,
|
||||||
@@ -100,10 +111,7 @@ async function on_delete(method: 'delete' | 'disable') {
|
|||||||
{#if $lq__event_presenter_obj?.agree}
|
{#if $lq__event_presenter_obj?.agree}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
disabled={!$ae_loc.trusted_access &&
|
disabled={!presenter_agree_enabled}
|
||||||
!events_auth_loc.current.auth__kv.presenter[
|
|
||||||
$lq__event_presenter_obj?.event_presenter_id
|
|
||||||
]}
|
|
||||||
onclick={() => {
|
onclick={() => {
|
||||||
$events_slct.event_presentation_id =
|
$events_slct.event_presentation_id =
|
||||||
$lq__event_presenter_obj?.event_presentation_id_random;
|
$lq__event_presenter_obj?.event_presentation_id_random;
|
||||||
@@ -120,10 +128,7 @@ async function on_delete(method: 'delete' | 'disable') {
|
|||||||
{:else}
|
{:else}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
disabled={!$ae_loc.trusted_access &&
|
disabled={!presenter_agree_enabled}
|
||||||
!events_auth_loc.current.auth__kv.presenter[
|
|
||||||
$lq__event_presenter_obj?.event_presenter_id
|
|
||||||
]}
|
|
||||||
onclick={() => {
|
onclick={() => {
|
||||||
$events_slct.event_presentation_id =
|
$events_slct.event_presentation_id =
|
||||||
$lq__event_presenter_obj?.event_presentation_id_random;
|
$lq__event_presenter_obj?.event_presentation_id_random;
|
||||||
|
|||||||
@@ -33,7 +33,8 @@ import {
|
|||||||
events_trig_kv
|
events_trig_kv
|
||||||
} from '$lib/stores/ae_events_stores';
|
} from '$lib/stores/ae_events_stores';
|
||||||
import { events_auth_loc } from '$lib/stores/ae_events_stores__auth.svelte';
|
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';
|
import { LogIn, X } from '@lucide/svelte';
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
console.log('Browser environment detected.');
|
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.
|
// 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
|
// WHY: a single sign-in link only grants auth for one presenter_id/session_id. This
|
||||||
// sign-in link only grants auth for that specific presenter_id/session_id. This scan
|
// queries both Dexie (fast, warm cache) AND the API (reliable, cold cache) in parallel,
|
||||||
// pre-populates auth__kv for all their other roles so they don't have to click each link.
|
// merges the results, and pre-populates auth__kv for all roles in one shot.
|
||||||
// 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.
|
|
||||||
async function expand_auth_for_person(person_id: string, event_id: string) {
|
async function expand_auth_for_person(person_id: string, event_id: string) {
|
||||||
try {
|
try {
|
||||||
const [presenter_li, session_li] = await Promise.all([
|
const [dexie_presenters, dexie_sessions, api_presenters, api_sessions] = await Promise.all([
|
||||||
db_events.presenter
|
db_events.presenter
|
||||||
.where('person_id').equals(person_id)
|
.where('person_id').equals(person_id)
|
||||||
.filter(p => p.event_id === event_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
|
db_events.session
|
||||||
.where('poc_person_id').equals(person_id)
|
.where('poc_person_id').equals(person_id)
|
||||||
.filter(s => s.event_id === event_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) {
|
// Merge Dexie + API results, deduplicated by ID using plain objects (not Map)
|
||||||
events_auth_loc.current.auth__kv.presenter[p.event_presenter_id] = true;
|
const api_presenter_li: Presenter[] = Array.isArray(api_presenters) ? (api_presenters as Presenter[]) : [];
|
||||||
events_auth_loc.current.auth__kv.presentation[p.event_presentation_id] = true;
|
const api_session_li: Session[] = Array.isArray(api_sessions) ? (api_sessions as Session[]) : [];
|
||||||
// 'read' matches what presenter_sign_in sets — truthy, but signals read-only session access
|
const presenter_kv: Record<string, Presenter> = {};
|
||||||
events_auth_loc.current.auth__kv.session[p.event_session_id] = 'read';
|
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) {
|
const session_kv: Record<string, Session> = {};
|
||||||
if (s.event_session_id) {
|
for (const s of [...dexie_sessions, ...api_session_li]) {
|
||||||
events_auth_loc.current.auth__kv.session[s.event_session_id] = true;
|
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) {
|
} 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