Now with the ability to look up user email and send user auth key.

This commit is contained in:
Scott Idem
2025-04-08 15:51:05 -04:00
parent 73eee7b8ff
commit 0d8b47af10
5 changed files with 283 additions and 13 deletions

View File

@@ -21,6 +21,8 @@ import {
import {
auth_ae_obj__username_password,
auth_ae_obj__user_id_user_auth_key,
send_email_auth_ae_obj__user_id,
qry_ae_obj_li__user_email,
// handle_load_ae_obj_id__user,
// handle_load_ae_obj_li__user,
// handle_create_ae_obj__user,
@@ -442,6 +444,8 @@ let export_obj = {
handle_update_ae_obj__person: handle_update_ae_obj__person,
auth_ae_obj__username_password: auth_ae_obj__username_password,
auth_ae_obj__user_id_user_auth_key: auth_ae_obj__user_id_user_auth_key,
send_email_auth_ae_obj__user_id: send_email_auth_ae_obj__user_id,
qry_ae_obj_li__user_email: qry_ae_obj_li__user_email,
handle_update_ae_obj_id_crud: handle_update_ae_obj_id_crud,
handle_download_export__obj_type: handle_download_export__obj_type,
generate_qr_code: generate_qr_code

View File

@@ -133,4 +133,149 @@ export async function auth_ae_obj__user_id_user_auth_key(
console.log('ae_promises.auth__user_id_user_key:', ae_promises.auth__user_id_user_key);
}
return ae_promises.auth__user_id_user_key;
}
}
// Send an email to the user with a new one time use authentication key. The new key must be generated and returned first.
// Updated 2025-04-08
export async function send_email_auth_ae_obj__user_id(
{
api_cfg,
account_id,
user_id,
base_url,
key_param_name = 'user_key', // API defaults to 'auth_key'
params = {},
// try_cache = true,
log_lvl = 1
}: {
api_cfg: any,
account_id: string,
user_id: string,
base_url?: string,
key_param_name?: string,
params?: key_val,
// try_cache?: boolean,
log_lvl?: number
}
) {
if (log_lvl) {
console.log(`*** send_email_auth_ae_obj__user_id() *** account_id=${account_id} user_id=${user_id}`);
}
if (log_lvl > 1) {
console.log(api_cfg);
}
let email_auth_key_endpoint = `user/${user_id}/email_auth_key_url`;
params = {
'root_url': base_url,
'key_param_name': key_param_name
}
ae_promises.auth_key__send_email = await api.get_object({
api_cfg: api_cfg,
endpoint: email_auth_key_endpoint,
params: params,
log_lvl: log_lvl
});
return ae_promises.auth_key__send_email;
// let endpoint = `/user/${user_id}/new_auth_key`;
// // params['user_id'] = user_id; // Required
// if (log_lvl > 1) {
// console.log(`send_email_auth_ae_obj__user_id() - params:`, params);
// }
// ae_promises.auth_key__gen_auth_key = await api.get_object({
// api_cfg: api_cfg,
// endpoint: endpoint,
// params: params,
// log_lvl: log_lvl
// })
// .then(async function (email_send_result) {
// if (email_send_result) {
// let email_auth_key_endpoint = `user/${user_id}/email_auth_key_url`;
// params = {
// 'root_url': 'https://test.oneskyit.com'
// }
// ae_promises.auth_key__send_email = await api.get_object({
// api_cfg: api_cfg,
// endpoint: email_auth_key_endpoint,
// params: params,
// log_lvl: log_lvl
// })
// return email_send_result;
// } else {
// console.log('No results returned.');
// return null;
// }
// })
// .catch(function (error) {
// console.log('No results returned or failed.', error);
// });
// if (log_lvl) {
// console.log('ae_promises.send_email_auth__user_id:', ae_promises.send_email_auth__user_id);
// }
// return ae_promises.send_email_auth__user_id;
}
// Look up user based on email address provided
// Updated 2025-04-08
export async function qry_ae_obj_li__user_email(
{
api_cfg,
account_id,
null_account_id = false,
email,
params = {},
try_cache = true,
log_lvl = 1
}: {
api_cfg: any,
account_id: string,
null_account_id?: boolean,
email: string,
params?: key_val,
try_cache?: boolean,
log_lvl?: number
}
) {
if (log_lvl) {
console.log(`*** qry_ae_obj_li__user_email() *** account_id=${account_id} email=${email}`);
}
// /user/lookup_email
let endpoint = '/user/lookup_email';
params['email'] = email; // Required
params['null_account_id'] = null_account_id || false;
if (log_lvl > 1) {
console.log(`qry_ae_obj_li__user_email() - params:`, params);
}
ae_promises.qry__user_email = await api.get_object({
api_cfg: api_cfg,
endpoint: endpoint,
params: params,
log_lvl: log_lvl
})
.then(async function (user_obj_get_result) {
if (user_obj_get_result) {
return user_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
if (log_lvl) {
console.log('ae_promises.qry__user_email:', ae_promises.qry__user_email);
}
return ae_promises.qry__user_email;
}

View File

@@ -1,11 +1,15 @@
<script lang="ts">
// let log_lvl: number = 1;
// *** Import Svelte specific
import { onDestroy, onMount, tick } from 'svelte';
// *** Import other supporting libraries
// import { liveQuery } from "dexie";
// *** Import Aether specific variables and functions
import { ae_util } from '$lib/ae_utils/ae_utils';
import { ae_loc, ae_sess, ae_api, slct, slct_trigger } from '$lib/ae_stores';
// import { core_func } from '$lib/ae_core/ae_core_functions';
// Ideally the Event related stores should not be imported here?
import { events_loc } from '$lib/ae_events_stores';
// import { db_events } from "$lib/db_events";
@@ -206,6 +210,7 @@ function handle_clear_access() {
return true;
}
</script>

View File

@@ -5,8 +5,10 @@ import { browser } from '$app/environment';
// *** Import other supporting libraries
import {
CircleX,
LogIn, LogOut, LockKeyhole,
User
Mail, MailCheck,
User, UserCheck
} from '@lucide/svelte';
// *** Import Aether specific variables and functions
@@ -31,6 +33,8 @@ let {
let url_user_id = data.url.searchParams.get('user_id');
let url_user_key = data.url.searchParams.get('user_key'); // Reminder that "key" is the site's auth key.
let url_user_username = data.url.searchParams.get('username');
let url_user_email = data.url.searchParams.get('user_email');
let ae_promises: key_val = {};
@@ -118,6 +122,62 @@ if (browser) {
// Pre-fill the auth__entered_key if passed in via the URL.
$ae_sess.auth__entered_user_key = url_user_key;
}
if (url_user_username) {
// Pre-fill the auth__entered_username if passed in via the URL.
$ae_sess.auth__entered_username = url_user_username;
}
if (url_user_email) {
// Pre-fill the auth__entered_email if passed in via the URL.
$ae_sess.auth__entered_email = url_user_email;
}
}
// Use core_func.send_email_auth_ae_obj__user_id
function handle_send_auth_email({user_id}: {user_id: string}) {
console.log('handle_send_auth_email()');
console.log($ae_loc.base_url); // URL origin
console.log($ae_loc.hostname); // URL hostname
// This function creates a new auth_key and then sends an email to the user with the new auth key.
ae_promises.send_email_auth_ae_obj__user_id = core_func.send_email_auth_ae_obj__user_id({
api_cfg: $ae_api,
account_id: $slct.account_id,
user_id: user_id,
base_url: $ae_loc.base_url,
log_lvl: 2
});
}
// Use core_func.qry_ae_obj_li__user_email
function handle_lookup_user_email({email}: {email: string}) {
console.log('handle_lookup_user_email()');
// If a user is returned then send the new auth key email
ae_promises.load__user_obj_li = core_func.qry_ae_obj_li__user_email({
api_cfg: $ae_api,
account_id: $slct.account_id,
null_account_id: false,
email: email,
log_lvl: 1
}).then((user_response) => {
if (user_response?.user_id_random) {
console.log(`User found for email:`, user_response);
handle_send_auth_email({
user_id: user_response.user_id_random
});
} else if (user_response.length > 0) {
console.log(`Multiple users found for email:`, user_response);
handle_send_auth_email({
user_id: user_response[0].user_id_random
});
} else {
alert('No user found with that email address.');
}
});
}
</script>
@@ -138,7 +198,7 @@ if (browser) {
>
<button
type="button"
class="btn btn-sm variant-outline-surface hover:variant-filled-surface"
class="btn btn-sm variant-outline-surface hover:variant-filled-surface *:hover:inline"
title="Sign In"
onclick={() => {
$ae_sess.show__sign_in_out__fields = !$ae_sess.show__sign_in_out__fields; // Toggle the visibility of the sign-in form
@@ -147,6 +207,7 @@ if (browser) {
{#if $ae_loc?.person_id && $ae_loc?.user_id}
{#if $ae_sess.show__sign_in_out__fields}
<CircleX class="mx-1" />
Hide Sign-In Options
{:else}
<User class="mx-1 inline-block text-gray-500" />
@@ -155,11 +216,14 @@ if (browser) {
{:else}
{#if $ae_sess.show__sign_in_out__fields}
<CircleX class="mx-1" />
Hide Sign-In Options
{:else}
<LockKeyhole size="1.25em" class="mx-1 inline-block text-gray-500" />
<!-- <User class="mx-1 inline-block text-gray-500" /> -->
<span class="hidden">
Sign-In?
</span>
{/if}
{/if}
@@ -197,13 +261,58 @@ if (browser) {
<span
class:hidden={!$ae_sess.show__sign_in_out__fields}
class="transition-all"
class="flex flex-col gap-1 transition-all"
>
{#if !$ae_loc?.person_id && !$ae_loc?.user_id}
<!-- We need to get the person's linked User ID and auth_key or User username and password to sign in. -->
<!-- Form for user look up based on email address -->
<form
class="ae_sign_in_form flex flex-col items-start gap-1"
class="
ae_sign_in_form
flex flex-col items-start gap-1
p-1
p-1 my-1
border-2 border-gray-200
"
onsubmit={async (e) => {
e.preventDefault();
if ($ae_sess.auth__entered_email) {
alert('Attempting to look up user by email address.');
handle_lookup_user_email({
email: $ae_sess.auth__entered_email
});
} else {
alert('Please enter an email address to look up.');
}
}}
>
<input
type="text"
class="input max-w-48"
placeholder="Email Address"
value={$ae_sess.auth__entered_email ?? ''}
oninput={(e) => $ae_sess.auth__entered_email = e.target.value}
>
<button
type="submit"
class="btn btn-sm variant-filled-secondary"
title="Look up user by email and send sign in email"
>
<!-- <User class="mx-1" /> -->
<!-- <Mail class="mx-1" /> -->
<MailCheck class="mx-1" />
Email Sign In
</button>
</form>
<!-- We need to get the person's linked User ID and auth_key or User username and password to sign in. -->
<form
class="
ae_sign_in_form
flex flex-col items-start gap-1
p-1 my-1
border-2 border-gray-200
"
onsubmit={async (e) => {
e.preventDefault();
@@ -418,11 +527,12 @@ if (browser) {
<button
type="submit"
class="btn btn-sm variant-filled-success"
title="Sign In"
class="btn btn-sm variant-filled-secondary"
title="Sign in with username and password"
>
<LogIn class="mx-1" />
Sign In
<!-- <LogIn class="mx-1" /> -->
<UserCheck class="mx-1" />
Username Sign In
</button>
</form>

View File

@@ -125,11 +125,14 @@ export async function load({ fetch, params, parent, route, url }) { // params, r
submenu: {},
};
// let parent_data = await parent();
// console.log(`root +layout.ts parent_data:`, parent_data);
// First do a site_domain look up to check if it is valid and get the account_id.
// ae_loc.url_host = data.url.host; // Use this to look up? sub.example.com:123
// ae_loc.fqdn = url.host; // Use this to look up? sub.example.com:123
// ae_loc.url_hostname = data.url.hostname; // sub.example.com
// ae_loc.url_origin = data.url.origin; // Use this to look up? https://sub.example.com:123
// ae_loc.url_hostname = parent_data.url.hostname; // sub.example.com
// ae_loc.url_origin = parent_data.url.origin; // Use this to look up? https://sub.example.com:123
// ae_loc.site_domain = data.url.origin;
// console.log(`ae_loc = `, ae_loc);
@@ -200,6 +203,9 @@ export async function load({ fetch, params, parent, route, url }) { // params, r
ae_loc_init['site_access_key'] = json_data.access_key; // This is the general site access key
ae_loc_init['site_domain_access_key'] = json_data.site_domain_access_key; // This is specific to a (sub)domain.
ae_loc_init['base_url'] = url.origin;
ae_loc_init['hostname'] = url.hostname
if (!ae_loc_init['site_access_key'] && !ae_loc_init['site_domain_access_key']) {
ae_loc_init['key_checked'] = true; // Se to true to allow access without a key.
ae_loc_init['allow_access'] = true; // No access key is required here.