feat(v3-auth): modernize hosted file access with simplified bypass pattern

- Roll out platform-wide standard for unauthenticated binary access using '?key=[account_id]' query parameter.
- Update API helpers (get, post, patch) to recognize 'key' bypass and strip account context headers accordingly.
- Refactor IDAA Bulletin Board to restore inline image rendering and edit-mode previews.
- Modernize Events Launcher (Layout, Sync, Session View) to use V3 Action URLs with verified auth.
- Update HTML generators in 'ae_utils.ts' to support the new authenticated URL structure.
- Harden 'ae_comp__event_file_obj_tbl' CSV export and clipboard links with V3 standard patterns.
This commit is contained in:
Scott Idem
2026-02-03 18:37:55 -05:00
parent 6634c9aef0
commit 0809ad3eac
21 changed files with 412 additions and 701 deletions

View File

@@ -76,6 +76,7 @@ export const get_object = async function get_object({
const bypass_val = merged_headers['x-no-account-id'] || merged_headers['x_no_account_id'];
const is_valid_bypass = bypass_val === 'bypass' ||
bypass_val === 'Nothing to See Here' ||
params['key'] ||
bypass_val === 'direct-download';
if (is_valid_bypass) {

View File

@@ -59,6 +59,7 @@ export const patch_object = async function patch_object({
const bypass_val = merged_headers['x-no-account-id'] || merged_headers['x_no_account_id'];
const is_valid_bypass = bypass_val === 'bypass' ||
bypass_val === 'Nothing to See Here' ||
params['key'] ||
bypass_val === 'direct-download';
if (is_valid_bypass) {

View File

@@ -79,6 +79,7 @@ export const post_object = async function post_object({
const bypass_val = merged_headers['x-no-account-id'] || merged_headers['x_no_account_id'];
const is_valid_bypass = bypass_val === 'bypass' ||
bypass_val === 'Nothing to See Here' ||
params['key'] ||
bypass_val === 'direct-download';
if (is_valid_bypass) {

View File

@@ -20,6 +20,8 @@
slct_trigger
} from '$lib/stores/ae_stores';
import AE_Comp_Hosted_Files_Download_Button from '$lib/ae_core/ae_comp__hosted_files_download_button.svelte';
// Exports
// export let input_name = 'file_list';
@@ -178,10 +180,7 @@
{#each Object.entries(hosted_file_obj_kv) as [hosted_file_id, hosted_file_obj]}
<div class="border border-gray-300 rounded-lg p-2 m-2">
<!-- {#if $ae_sess.files[hosted_file_id].upload_complete}
<a href="/hosted_file/{hosted_file_id}/download?x_no_account_id_token=direct-download" download={$ae_sess.files[hosted_file_id].new_filename} class="ae_btn btn_lg btn_primary"><span class="fas fa-download"></span> Ready to Download</a>
{/if} -->
<!-- Download Button (Standardized) -->
<div class="flex flex-row flex-wrap gap-1 justify-center items-center w-full">
<!-- Remove from uploaded file kv list -->
<button
@@ -211,52 +210,17 @@
</button>
<!-- Download the file -->
<button
type="button"
disabled={!$ae_loc.trusted_access}
onclick={() => {
ae_promises[hosted_file_id] = api.download_hosted_file({
api_cfg: $ae_api,
hosted_file_id: hosted_file_id,
return_file: true,
filename: hosted_file_obj.filename,
auto_download: true,
log_lvl: 0
});
}}
class:hidden={!$ae_loc.edit_mode}
class="novi_btn btn btn-sm lg:btn-md preset-tonal-primary hover:preset-filled-primary-500 min-w-72 lg:min-w-96"
title={`Download this file:\n${hosted_file_obj.filename}\n[API] SHA256: ${hosted_file_obj?.hash_sha256?.slice(0, 10)}... Hosted ID: ${hosted_file_obj.hosted_file_id_random}`}
>
{#await ae_promises[hosted_file_id]}
<span class="fas fa-spinner fa-spin mx-1"></span>
{#if submit_status == 'clipping'}
<span class="">Clipping</span>
{:else}
<span class="">
Downloading
{#if $ae_sess.api_download_kv[hosted_file_id]}
{$ae_sess.api_download_kv[hosted_file_id].percent_completed}%
{/if}
:
</span>
{/if}
{:then}
<span
class="fas fa-{ae_util.file_extension_icon(
hosted_file_obj?.file_extension
)}"
></span>
{/await}
<span class="grow">
{ae_util.shorten_filename({
filename: hosted_file_obj?.filename,
max_length: 30
})}
</span>
</button>
<div class:hidden={!$ae_loc.edit_mode}>
<AE_Comp_Hosted_Files_Download_Button
hosted_file_id={hosted_file_id}
hosted_file_obj={hosted_file_obj}
color="primary"
variant="tonal"
classes="novi_btn btn-sm lg:btn-md min-w-72 lg:min-w-96 !justify-start"
show_divider={true}
max_filename={30}
/>
</div>
<span
>{ae_util.shorten_filename({
filename: hosted_file_obj?.filename,

View File

@@ -1,6 +1,7 @@
<script lang="ts">
// Imports
// Import components and elements
import AE_Comp_Hosted_Files_Download_Button from '$lib/ae_core/ae_comp__hosted_files_download_button.svelte';
// Import storage, functions, and libraries
import type { key_val } from '$lib/stores/ae_stores';
@@ -47,44 +48,13 @@
<h3 class="h3">{Object.entries($ae_loc.files).length}× files clipped</h3>
<div class="{class_li_default} {class_li} ">
{#each Object.entries(video_clip_file_kv) as [hosted_file_id, hosted_file_obj]}
<button
type="button"
disabled={!$ae_loc.trusted_access}
onclick={() => {
ae_promises[hosted_file_id] = api.download_hosted_file({
api_cfg: $ae_api,
hosted_file_id: hosted_file_id,
return_file: true,
filename: hosted_file_obj.filename,
auto_download: true,
log_lvl: log_lvl
});
}}
class="novi_btn btn btn-sm lg:btn-md preset-tonal-primary hover:preset-filled-primary-500 min-w-72 lg:min-w-96"
title={`Download this file:\n${hosted_file_obj.filename}\n[API] SHA256: ${hosted_file_obj?.hash_sha256?.slice(0, 10)}... Hosted ID: ${hosted_file_obj.hosted_file_id}`}
>
{#await ae_promises[hosted_file_id]}
<span class="fas fa-spinner fa-spin mx-1"></span>
<span class="">
Downloading
{#if $ae_sess.api_download_kv[hosted_file_id]}
{$ae_sess.api_download_kv[hosted_file_id].percent_completed}%
{/if}
:
</span>
{:then}
<span class="fas fa-{ae_util.file_extension_icon(hosted_file_obj?.file_extension)}"
></span>
{/await}
<span class="grow">
{ae_util.shorten_filename({ filename: hosted_file_obj?.filename, max_length: 30 })}
</span>
<span class="shrink">
{ae_util.format_bytes(hosted_file_obj?.size)}
</span>
</button>
<AE_Comp_Hosted_Files_Download_Button
{hosted_file_id}
{hosted_file_obj}
max_filename={30}
classes="btn btn-sm lg:btn-md preset-tonal-primary hover:preset-filled-primary-500 min-w-72 lg:min-w-96"
linked_to_type={link_to_type}
linked_to_id={link_to_id}
/>
{/each}
</div>

View File

@@ -30,6 +30,7 @@
show_divider?: boolean;
show_direct_download?: boolean;
classes?: string;
click?: () => void | Promise<any>;
label?: import('svelte').Snippet;
}
@@ -50,6 +51,7 @@
show_divider = true,
show_direct_download = false,
classes = '',
click,
label
}: Props = $props();
@@ -166,8 +168,50 @@
// Legacy endpoints often expect integer IDs and will return 404 for string IDs.
const file_id = hosted_file_obj.event_file_id || hosted_file_obj.hosted_file_id || hosted_file_id;
const obj_type_path = hosted_file_obj.event_file_id ? 'event_file' : 'hosted_file';
return `${$ae_api.base_url}/v3/action/${obj_type_path}/${file_id}/download?filename=${ae_util.clean_filename(final_filename)}&x_no_account_id_token=direct-download`;
return `${$ae_api.base_url}/v3/action/${obj_type_path}/${file_id}/download?filename=${ae_util.clean_filename(final_filename)}&x_no_account_id_token=${$ae_api.account_id}`;
});
async function handle_click() {
const file_id = hosted_file_obj?.id || hosted_file_obj?.hosted_file_id || hosted_file_id;
download_complete = undefined;
download_status_msg = 'Downloading...';
if (click) {
const result = click();
// If the override returns a promise, track it so the UI shows progress
if (result instanceof Promise) {
ae_promises[file_id] = result;
}
return;
}
ae_promises[file_id] = download_ae_obj_id__hosted_file({
api_cfg: $ae_api,
hosted_file_id: file_id,
return_file: true,
filename: final_filename,
auto_download: auto_download,
log_lvl: log_lvl
})
.then((result) => {
if (result === null) {
console.log('File not found (404)');
download_complete = null;
download_status_msg = 'File not found';
} else if (result === false) {
console.log(
'Possible error with API server (check network and server status)'
);
download_complete = false;
download_status_msg = 'Failed to download';
} else {
// console.log('File found and downloaded');
download_complete = true;
download_status_msg = 'File downloaded';
}
return result;
});
}
</script>
{#snippet content()}
@@ -246,36 +290,7 @@
type="button"
disabled={!$ae_loc.trusted_access}
class={variant_classes}
onclick={() => {
download_complete = undefined;
download_status_msg = 'Downloading...';
ae_promises[file_id] = download_ae_obj_id__hosted_file({
api_cfg: $ae_api,
hosted_file_id: file_id,
return_file: true,
filename: final_filename,
auto_download: auto_download,
log_lvl: log_lvl
})
.then((result) => {
if (result === null) {
console.log('File not found (404)');
download_complete = null;
download_status_msg = 'File not found';
} else if (result === false) {
console.log(
'Possible error with API server (check network and server status)'
);
download_complete = false;
download_status_msg = 'Failed to download';
} else {
// console.log('File found and downloaded');
download_complete = true;
download_status_msg = 'File downloaded';
}
return result;
});
}}
onclick={handle_click}
title={`Download this file:\n${final_filename}\n[API] SHA256: ${hosted_file_obj?.hash_sha256?.slice(0, 10)}...\nHosted ID: ${file_id}\n Linked to: ${linked_to_type} ID: ${linked_to_id}`}
>
{@render content()}

View File

@@ -1,8 +1,7 @@
<script lang="ts">
import { preventDefault } from 'svelte/legacy';
// Imports
// Import components and elements
import * as Lucide from 'lucide-svelte';
import Element_input_files_tbl from '$lib/elements/element_input_files_tbl.svelte';
// Import storage, functions, and libraries
@@ -76,8 +75,9 @@
}
// *** Functions and Logic
async function handle_submit_form_files(event: Event) {
async function handle_submit_form_files(event: SubmitEvent) {
console.log('*** handle_submit_form() ***');
event.preventDefault();
if (!event) {
return;
@@ -94,7 +94,7 @@
let hosted_file_results;
const target = event.target as HTMLFormElement;
const target = event.currentTarget as HTMLFormElement;
const file_input = target ? (target[input_element_id] as HTMLInputElement) : null;
if (
@@ -264,10 +264,10 @@
</script>
<!-- class:hidden={!$ae_loc.trusted_access} -->
<form onsubmit={preventDefault(handle_submit_form_files)} class="{class_li_default} {class_li}">
<form onsubmit={handle_submit_form_files} class="{class_li_default} {class_li}">
{#await ae_promises.upload__hosted_file_obj}
<div class="text-lg flex flex-row gap-1 items-center justify-center">
<span class="fas fa-spinner fa-spin m-1"></span>
<Lucide.Loader2 class="animate-spin m-1" />
<span class="">
Uploading
{#if $ae_sess.api_upload_kv[task_id]}
@@ -283,16 +283,13 @@
class:hidden={$ae_sess.files.disable_submit__hosted_file_obj}
>
{#if label}{@render label()}{:else}
<div>
<span class="fas fa-upload"></span>
<!-- Select files to upload -->
<!-- <span class="fas fa-file-archive"></span> -->
<strong class="bg-blue-300 p-1">Upload files</strong>
<!-- (drag and drop) -->
<div class="flex items-center justify-center gap-2 mb-2">
<Lucide.Upload class="text-primary-500" />
<strong class="preset-tonal-primary px-3 py-1 rounded-full">Select Files</strong>
</div>
<span class="text-sm text-gray-600 dark:text-gray-400 italic">
<strong>Presentation related files only</strong><br />
(PowerPoint, Keynote, PDF, mp4, Word Doc, Excel, txt, etc)
<strong>Supported formats</strong><br />
(PowerPoint, Keynote, PDF, Media, etc)
</span>
{/if}
</label>
@@ -312,8 +309,8 @@
block w-full text-lg
text-gray-900
border border-gray-300 rounded-lg
cursor-pointer b
g-gray-50 dark:text-gray-400 focus:outline-hidden dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400
cursor-pointer
bg-gray-50 dark:text-gray-400 focus:outline-hidden dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400
{input_class_li.join(' ')}
"
class:hidden={$ae_sess.files.disable_submit__hosted_file_obj}
@@ -328,32 +325,28 @@
<button
type="submit"
class="btn btn-lg btn-primary preset-tonal-primary border border-primary-500 hover:preset-tonal-success border border-success-500 w-54"
class="btn btn-lg btn-primary preset-tonal-primary border border-primary-500 hover:preset-tonal-success hover:border-success-500 w-54"
disabled={$ae_sess.files.disable_submit__hosted_file_obj ||
$ae_sess.files.status__file_list != 'ready'}
>
{#await ae_promises.upload__hosted_file_obj}
<span class="fas fa-spinner fa-spin m-1"></span>
<Lucide.Loader2 class="animate-spin m-1" />
<span class="">
Uploading
{#if $ae_sess.api_upload_kv[task_id]}
{$ae_sess.api_upload_kv[task_id].percent_completed}%
{:else}
...
{/if}
</span>
{:then}
<span class="fas fa-upload m-1"></span>
<span class="text-sm"> Upload? </span>
<!-- <span class="fas fa-save m-1"></span> -->
<span class="grow font-bold">
<Lucide.UploadCloud class="m-1" size={20} />
<span class="text-sm"> Upload </span>
<span class="grow font-bold ml-2">
{#if $ae_sess.files.processed_file_list?.length > 0}
{$ae_sess.files.processed_file_list.length == 1
? `${$ae_sess.files.processed_file_list.length} file`
: `${$ae_sess.files.processed_file_list.length} files`}
{$ae_sess.files.processed_file_list.length} { $ae_sess.files.processed_file_list.length === 1 ? 'file' : 'files' }
{:else}
<span class="text-xs"> No files selected </span>
<span class="text-xs"> 0 </span>
{/if}
<!-- Files -->
</span>
{/await}
</button>

View File

@@ -81,6 +81,8 @@ function handle_url_and_message(name: string, value: null | string) {
// console.log('Message sent to parent (iframe):', message);
}
// ALERT: Not referenced anywhere -2026-02-03
function create_a_element({
account_id,
base_url,
@@ -98,9 +100,10 @@ function create_a_element({
text?: string;
class_li?: string;
}) {
return `<a href="${base_url}/hosted_file/${hosted_file_id}/download?x_no_account_id_token=${account_id}&filename=${filename}" class="${class_li}">${text}</a>`;
return `<a href="${base_url}/v3/action/hosted_file/${hosted_file_id}/download?key=${account_id}&filename=${filename}" class="${class_li}">${text}</a>`;
}
// ALERT: Not referenced anywhere -2026-02-03
function create_img_element({
account_id,
base_url,
@@ -122,9 +125,9 @@ function create_img_element({
}) {
let img_html = '';
if (filename) {
img_html = `<img src="${base_url}/hosted_file/${hosted_file_id}/download?x_no_account_id_token=${account_id}&filename=${filename}" class="${class_li}" style="${style}" />`;
img_html = `<img src="${base_url}/v3/action/hosted_file/${hosted_file_id}/download?key=${account_id}&filename=${filename}" class="${class_li}" style="${style}" />`;
} else {
img_html = `<img src="${base_url}/hosted_file/${hosted_file_id}/download?x_no_account_id_token=${account_id}" class="${class_li}" style="${style}" />`;
img_html = `<img src="${base_url}/v3/action/hosted_file/${hosted_file_id}/download?key=${account_id}" class="${class_li}" style="${style}" />`;
}
if (inc_link) {
@@ -141,6 +144,7 @@ function create_img_element({
return img_html;
}
// ALERT: Not referenced anywhere -2026-02-03
function create_video_element({
account_id,
base_url,
@@ -160,9 +164,9 @@ function create_video_element({
}) {
let video_html = '';
if (filename) {
video_html = `<video src="${base_url}/hosted_file/${hosted_file_id}/download?x_no_account_id_token=${account_id}&filename=${filename}" controls class="${class_li}"></video>`;
video_html = `<video src="${base_url}/v3/action/hosted_file/${hosted_file_id}/download?key=${account_id}&filename=${filename}" controls class="${class_li}"></video>`;
} else {
video_html = `<video src="${base_url}/hosted_file/${hosted_file_id}/download?x_no_account_id_token=${account_id}" controls class="${class_li}"></video>`;
video_html = `<video src="${base_url}/v3/action/hosted_file/${hosted_file_id}/download?key=${account_id}" controls class="${class_li}"></video>`;
}
if (inc_link) {

View File

@@ -17,6 +17,7 @@
events_trigger
} from '$lib/stores/ae_events_stores';
import { events_func } from '$lib/ae_events_functions';
import AE_Comp_Hosted_Files_Download_Button from '$lib/ae_core/ae_comp__hosted_files_download_button.svelte';
interface Props {
log_lvl?: number;
@@ -166,174 +167,45 @@
>
<td class="event_file__file align-middle">
{#if $events_sess.pres_mgmt?.show_field_edit__filename != event_file_obj.event_file_id}
<button
type="button"
disabled={!allow_basic &&
!allow_moderator &&
!$ae_loc.trusted_access}
onclick={() => {
// ae_promises[event_file_obj.event_file_id]
ae_promises[event_file_obj.event_file_id] =
api.download_hosted_file({
api_cfg: $ae_api,
hosted_file_id: event_file_obj.hosted_file_id,
return_file: true,
filename: event_file_obj.filename,
auto_download: true,
log_lvl: 0
});
<div class="flex flex-col gap-2">
<AE_Comp_Hosted_Files_Download_Button
hosted_file_id={event_file_obj?.hosted_file_id}
hosted_file_obj={event_file_obj}
show_divider={true}
show_direct_download={ae_tmp.show__direct_download}
max_filename={30}
classes="btn btn-sm lg:btn-md preset-tonal-primary hover:preset-filled-primary-500 min-w-72 lg:min-w-96"
/>
}}
class="btn btn-sm lg:btn-md preset-tonal-primary hover:preset-filled-primary-500 min-w-72 lg:min-w-96"
title={`Download this file:\n${event_file_obj.filename}\n[API] SHA256: ${event_file_obj.hash_sha256.slice(0, 10)}... Hosted ID: ${event_file_obj.hosted_file_id} Event File ID: ${event_file_obj.event_file_id}`}
>
{#await ae_promises[event_file_obj.event_file_id]}
<span class="fas fa-spinner fa-spin mx-1"></span>
<span class="">
Downloading
{#if $ae_sess.api_download_kv[event_file_obj.hosted_file_id]}
{$ae_sess.api_download_kv[
event_file_obj.hosted_file_id
].percent_completed}%
{/if}
:
</span>
{:then}
<!-- <span class="fas fa-download mx-1"></span> -->
<span
class="fas fa-{ae_util.file_extension_icon(
event_file_obj.extension
)}"
></span>
<!-- <span class="text-sm">
Download:
</span> -->
{/await}
<span class="grow">
{ae_util.shorten_filename({
filename: event_file_obj.filename,
max_length: 30
})}
</span>
<span
class="badge preset-tonal-success hover:preset-filled-success-500 text-sm"
class:hidden={!event_file_obj.file_purpose}
>
{event_file_obj.file_purpose}
</span>
</button>
<span
class="px-4 py-2 flex flex-col gap-0.5"
class:hidden={!ae_tmp.show__direct_download}
>
<div class="flex flex-row gap-0.5">
<span class="text-xs text-gray-500 w-32">
Original:
</span>
<a
href="{$ae_api.base_url}/event/file/{event_file_obj?.event_file_id}/download?filename={ae_util.clean_filename(
event_file_obj?.filename
)}&x_no_account_id_token=direct-download"
class="btn btn-sm p-1 preset-tonal-secondary *:hover:inline lg:text-xs underline"
title={`Download this file:\n${ae_util.clean_filename(event_file_obj?.filename)}\n[API] SHA256: ${event_file_obj?.hash_sha256.slice(0, 10)}...\nHosted ID: ${event_file_obj?.hosted_file_id} Event File ID: ${event_file_obj?.event_file_id}`}
{#if ae_tmp.show__direct_download}
<div
class="px-4 py-2 flex flex-col gap-0.5 bg-surface-100/50 rounded-lg border border-surface-500/10"
>
<span class="fas fa-download mx-1"></span>
<span class="hidden"> Download </span>
</a>
<!-- {#if clipboard_success}Copied!{:else}Copy Access Link{/if} -->
<!-- <span class="fas fa-copy mx-1"></span> -->
<!-- <Clipboard
value={encodeURI(`${$ae_api.base_url}/event/file/${event_file_obj?.event_file_id}/download?filename=${ae_util.clean_filename(event_file_obj?.filename)}&x_no_account_id_token=direct-download`)}
bind:success={clipboard_success}
class="w-24"
>
{#if clipboard_success}Copied!{:else}Copy Link{/if}
</Clipboard> -->
<MyClipboard
value={encodeURI(
`${$ae_api.base_url}/event/file/${event_file_obj?.event_file_id}/download?filename=${ae_util.clean_filename(event_file_obj?.filename)}&x_no_account_id_token=direct-download`
)}
btn_text="Copy Link"
btn_title="Copy the direct download link to the clipboard."
btn_class="btn btn-sm preset-tonal-warning hover:preset-filled-warning-500 float-right m-1"
></MyClipboard>
</div>
<div class="flex flex-row gap-0.5">
<span class="text-xs text-gray-500 w-32">
Session Name:
</span>
<a
href="{$ae_api.base_url}/event/file/{event_file_obj?.event_file_id}/download?filename={event_file_obj?.event_session_code}-{ae_util
.clean_filename(
event_file_obj?.event_presentation_name
)
.substring(0, 20)}-{ae_util.clean_filename(
event_file_obj?.event_presenter_full_name
)}.{event_file_obj?.extension}&x_no_account_id_token=direct-download"
class="btn btn-sm p-1 preset-tonal-secondary *:hover:inline lg:text-xs underline"
title={`Download renamed with session name to: ${event_file_obj?.event_session_code}-${ae_util.clean_filename(event_file_obj?.event_session_name).substring(0, 20)}-${ae_util.clean_filename(event_file_obj?.event_presenter_full_name)}.${event_file_obj?.extension}`}
>
<span class="fas fa-download mx-1"></span>
<span class="hidden"> Renamed </span>
</a>
<!-- <Clipboard
value={encodeURI(`${$ae_api.base_url}/event/file/${event_file_obj?.event_file_id}/download?filename=${event_file_obj?.event_session_code}-${ae_util.clean_filename(event_file_obj?.event_session_name).substring(0, 20)}-${ae_util.clean_filename(event_file_obj?.event_presenter_full_name)}.${event_file_obj?.extension}&x_no_account_id_token=direct-download`)}
bind:success={clipboard_success}
class="w-24"
>
{#if clipboard_success}Copied!{:else}Copy Renamed{/if}
</Clipboard> -->
<MyClipboard
value={encodeURI(
`${$ae_api.base_url}/event/file/${event_file_obj?.event_file_id}/download?filename=${event_file_obj?.event_session_code}-${ae_util.clean_filename(event_file_obj?.event_session_name).substring(0, 20)}-${ae_util.clean_filename(event_file_obj?.event_presenter_full_name)}.${event_file_obj?.extension}&x_no_account_id_token=direct-download`
)}
btn_text="Copy Renamed"
btn_title="Copy the renamed download link to the clipboard."
btn_class="btn btn-sm preset-tonal-warning hover:preset-filled-warning-500 float-right m-1"
></MyClipboard>
</div>
<div class="flex flex-row gap-0.5">
<span class="text-xs text-gray-500 w-32">
Presentation Name:
</span>
<a
href="{$ae_api.base_url}/event/file/{event_file_obj?.event_file_id}/download?filename={event_file_obj?.event_session_code}-{ae_util
.clean_filename(
event_file_obj?.event_presentation_name
)
.substring(0, 20)}-{ae_util.clean_filename(
event_file_obj?.event_presenter_full_name
)}.{event_file_obj?.extension}&x_no_account_id_token=direct-download"
class="btn btn-sm p-1 preset-tonal-secondary *:hover:inline lg:text-xs underline"
title={`Download renamed with presentation name to: ${event_file_obj?.event_session_code}-${ae_util.clean_filename(event_file_obj?.event_presentation_name).substring(0, 20)}-${ae_util.clean_filename(event_file_obj?.event_presenter_full_name)}.${event_file_obj?.extension}`}
>
<span class="fas fa-download mx-1"></span>
<span class="hidden"> Renamed </span>
</a>
<!-- {#if clipboard_success}Copied!{:else}Copy Access Link{/if} -->
<!-- <span class="fas fa-copy mx-1"></span> -->
<!-- <Clipboard
value={encodeURI(`${$ae_api.base_url}/event/file/${event_file_obj?.event_file_id}/download?filename=${event_file_obj?.event_session_code}-${ae_util.clean_filename(event_file_obj?.event_presentation_name).substring(0, 20)}-${ae_util.clean_filename(event_file_obj?.event_presenter_full_name)}.${event_file_obj?.extension}&x_no_account_id_token=direct-download`)}
bind:success={clipboard_success}
class="w-24"
>
{#if clipboard_success}Copied!{:else}Copy Renamed{/if}
</Clipboard> -->
<MyClipboard
value={encodeURI(
`${$ae_api.base_url}/event/file/${event_file_obj?.event_file_id}/download?filename=${event_file_obj?.event_session_code}-${ae_util.clean_filename(event_file_obj?.event_presentation_name).substring(0, 20)}-${ae_util.clean_filename(event_file_obj?.event_presenter_full_name)}.${event_file_obj?.extension}&x_no_account_id_token=direct-download`
)}
btn_text="Copy Renamed"
btn_title="Copy the renamed download link to the clipboard."
btn_class="btn btn-sm preset-tonal-warning hover:preset-filled-warning-500 float-right m-1"
></MyClipboard>
</div>
</span>
<div class="flex flex-row items-center gap-2">
<span class="text-[10px] font-bold uppercase opacity-50 w-24">
Access Link:
</span>
<MyClipboard
value={encodeURI(
`${$ae_api.base_url}/v3/action/event_file/${event_file_obj?.event_file_id}/download?filename=${ae_util.clean_filename(event_file_obj?.filename)}&key=${$ae_api.account_id}`
)}
btn_text="Copy Original"
btn_title="Copy the direct download link to the clipboard."
btn_class="btn btn-xs preset-tonal-warning hover:preset-filled-warning-500"
></MyClipboard>
<MyClipboard
value={encodeURI(
`${$ae_api.base_url}/v3/action/event_file/${event_file_obj?.event_file_id}/download?filename=${event_file_obj?.event_session_code}-${ae_util.clean_filename(event_file_obj?.event_session_name).substring(0, 20)}-${ae_util.clean_filename(event_file_obj?.event_presenter_full_name)}.${event_file_obj?.extension}&key=${$ae_api.account_id}`
)}
btn_text="Copy Renamed"
btn_title="Copy the renamed download link to the clipboard."
btn_class="btn btn-xs preset-tonal-warning hover:preset-filled-warning-500"
></MyClipboard>
</div>
</div>
{/if}
</div>
{:else}
<!-- Show change filename input field here -->
<span class="flex flex-col gap-1 text-sm">
@@ -386,7 +258,7 @@
})
.then(function (update_results) {
console.log(
`Update results:`,
`Update results:`,
update_results
);
$events_sess.pres_mgmt.show_field_edit__filename = false;
@@ -440,7 +312,7 @@
class:preset-tonal-warning={$events_sess.pres_mgmt
.show_field_edit__filename ==
event_file_obj.event_file_id}
title={`Rename this file? "${event_file_obj.filename}"`}
title={`Rename this file? "${event_file_obj.filename}"}`}
>
<span class="fas fa-edit mx-1"></span>
{#if $events_sess.pres_mgmt?.show_field_edit__filename == event_file_obj.event_file_id}
@@ -467,7 +339,7 @@
})
.then(function (update_results) {
console.log(
`Update results:`,
`Update results:`,
update_results
);
@@ -491,7 +363,8 @@
title="Hide this file from the presentation launcher"
>
<!-- Users see this as the "Archive" option button -->
<!-- {@html (event_file_obj?.hide ? '<span class="fas fa-archive m-1"></span> Unarchive' : '<span class="fas fa-archive m-1"></span> Archive')} -->
<!-- {@html (event_file_obj?.hide ? '<span class="fas fa-archive m-1"></span> Unarchive' : '<span class="fas fa-archive m-1"></span> Archive')}
-->
{#await ae_promises.update__event_file_obj}
<span class="fas fa-spinner fa-spin mx-1"></span>
@@ -504,10 +377,6 @@
{:else}
<span class="fas fa-eye-slash m-1"></span> Hide
{/if}
<!-- {@html (event_file_obj?.hide ? '<span class="fas fa-eye m-1"></span> Unhide?' : '<span class="fas fa-eye-slash m-1"></span> Hide?')} -->
<!-- <span class="fas fa-save mx-1"></span>
Save {event_file_obj.extension} filename? -->
{/await}
</button>
@@ -592,7 +461,7 @@
})
.then(function (update_results) {
console.log(
`Update results:`,
`Update results:`,
update_results
);
$slct_trigger =
@@ -765,4 +634,4 @@
</section>
<style>
</style>
</style>