Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add backend connection to user login #115

Merged
merged 31 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
07678d7
add de localization for login, put data into component
MaHaWo Oct 15, 2024
cf3b2f3
Merge branch 'add-forgot-password-component' into add-backend-connect…
MaHaWo Oct 15, 2024
6681845
use localization, remove some mock functions for backend
MaHaWo Oct 15, 2024
98a5a65
add button styling
MaHaWo Oct 15, 2024
9e2a73c
add new verify logic skeleton
MaHaWo Oct 15, 2024
1a59ef1
Merge branch 'main' into add-backend-connection-to-user-login
MaHaWo Oct 15, 2024
24c17a2
work on using backend in user registration
MaHaWo Oct 15, 2024
5d92407
work on submission of data in userregistration
MaHaWo Oct 15, 2024
60deb5b
add user registration verify and success page
MaHaWo Oct 15, 2024
93d2b7e
remove commented out code
MaHaWo Oct 15, 2024
2b2a4ca
update openapi.json & openapi-ts client, run pnpm format
github-actions[bot] Oct 15, 2024
3f99112
Merge branch 'main' into add-backend-connection-to-user-login
MaHaWo Oct 16, 2024
32f3aec
add role, e-mail to login
MaHaWo Oct 16, 2024
2fc5758
add store for current user
MaHaWo Oct 16, 2024
4c0e3a2
work on making login persistent
MaHaWo Oct 16, 2024
e914f4c
add localizations
MaHaWo Oct 16, 2024
f221554
update openapi.json & openapi-ts client, run pnpm format
github-actions[bot] Oct 16, 2024
122d477
change around debug output
MaHaWo Oct 16, 2024
38c296c
update openapi.json & openapi-ts client, run pnpm format
github-actions[bot] Oct 16, 2024
d13f4b4
add verified warning page
MaHaWo Oct 16, 2024
8c4624f
Merge branch 'add-backend-connection-to-user-login' of github.com:ssc…
MaHaWo Oct 16, 2024
ebc9bb0
update openapi.json & openapi-ts client, run pnpm format
github-actions[bot] Oct 16, 2024
4fce6e6
add data deletion
MaHaWo Oct 16, 2024
e1241e6
Merge branch 'add-backend-connection-to-user-login' of github.com:ssc…
MaHaWo Oct 16, 2024
9d3e45f
some corrections
MaHaWo Oct 16, 2024
46b1fa0
update openapi.json & openapi-ts client, run pnpm format
github-actions[bot] Oct 16, 2024
8676995
add database writing to on_after_register
MaHaWo Oct 16, 2024
f149b6f
fix error in database rewriting
MaHaWo Oct 17, 2024
4e43ab7
better comment
MaHaWo Oct 17, 2024
ac61c69
update comments
MaHaWo Oct 17, 2024
39cc4b2
use async_session_maker and session.get to set user as verified
lkeegan Oct 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 30 additions & 22 deletions frontend/src/lib/components/UserLandingPage.svelte
Original file line number Diff line number Diff line change
@@ -1,45 +1,53 @@
<script lang="ts">
import { activeTabChildren, activeTabPersonal, componentTable } from '$lib/stores/componentStore';
import { currentUser } from '$lib/stores/userStore';
import { TabItem, Tabs } from 'flowbite-svelte';
import { GridPlusSolid, ProfileCardSolid } from 'flowbite-svelte-icons';
import { get } from 'svelte/store';
import UserVerify from './UserVerify.svelte';

import { activeTabChildren, activeTabPersonal, componentTable } from '$lib/stores/componentStore';
import { onDestroy } from 'svelte';

export let userData: any[];
const isVerifed = get(currentUser)?.is_verified;
let currentPersonal = 'userDataInput';
let currentChildren = 'childrenGallery';
export let userData: any[];

const unsubscribePersonal = activeTabPersonal.subscribe((value) => {
console.log('personal tab: ', value);
currentPersonal = value;
});

const unsubscribeChildren = activeTabChildren.subscribe((value) => {
console.log('children tab: ', value);
currentChildren = value;
});

onDestroy(() => {
unsubscribeChildren();
unsubscribePersonal();
});
console.log('user: ', get(currentUser));
console.log(' verified: ', isVerifed);
</script>

<div class="m-2 p-2">
<Tabs tabStyle="pill">
<TabItem open={true}>
<div slot="title" class="flex items-center gap-2 text-lg">
<ProfileCardSolid size="lg" />
Persönliche Daten
</div>
<svelte:component this={componentTable[currentPersonal]} data={userData} />
</TabItem>
<TabItem>
<div slot="title" class="flex items-center gap-2 text-lg">
<GridPlusSolid size="lg" />
Kinder
</div>
<svelte:component this={componentTable[currentChildren]} />
</TabItem>
</Tabs>
</div>
{#if isVerifed === true}
<div class="m-2 p-2">
<Tabs tabStyle="pill">
<TabItem open={true}>
<div slot="title" class="flex items-center gap-2 text-lg">
<ProfileCardSolid size="lg" />
Persönliche Daten
</div>
<svelte:component this={componentTable[currentPersonal]} data={userData} />
</TabItem>
<TabItem>
<div slot="title" class="flex items-center gap-2 text-lg">
<GridPlusSolid size="lg" />
Kinder
</div>
<svelte:component this={componentTable[currentChildren]} />
</TabItem>
</Tabs>
</div>
{:else}
<UserVerify />
{/if}
225 changes: 107 additions & 118 deletions frontend/src/lib/components/UserLogin.svelte
Original file line number Diff line number Diff line change
@@ -1,102 +1,101 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { base } from '$app/paths';

import UserLoginUtil from '$lib/components//UserLoginUtil.svelte';
import AlertMessage from '$lib/components/AlertMessage.svelte';
import DataInput from '$lib/components/DataInput/DataInput.svelte';
import NavigationButtons from '$lib/components/Navigation/NavigationButtons.svelte';

import { hash, users, type UserData } from '$lib/stores/userStore';
import { Card, Heading } from 'flowbite-svelte';
import { onDestroy, onMount } from 'svelte';
import { goto } from '$app/navigation';
import { authCookieLogin, usersCurrentUser } from '$lib/client/services.gen';
import { type AuthCookieLoginData, type UserRead } from '$lib/client/types.gen';
import { currentUser } from '$lib/stores/userStore';
import { preventDefault } from '$lib/util';
import { Button, Card, Heading, Input } from 'flowbite-svelte';
import { _ } from 'svelte-i18n';

async function refresh(): Promise<string> {
const returned = await usersCurrentUser();
if (returned.error) {
console.log('Error getting current user: ', returned.error.detail);
currentUser.set(null as unknown as UserRead);
return returned.error.detail;
} else {
console.log('Successfully retrieved active user');
// TODO: remove this in the final version, this sets verified to true
// to emulate a successful user registration
returned.data.is_verified = true;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it makes more sense to make the backend set is_verified=true on signup for now until #109 is implemented

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok... did that now in on_after_register in the users.py file. find entry in database corresponding to the passed user object, set the verified flag -> write back to database.

currentUser.set(returned.data as UserRead);
return 'success';
}
}

// functionality
async function submitData(): Promise<void> {
const loginData: AuthCookieLoginData = {
body: {
username: formData[0].value,
password: formData[1].value
}
};

/**
* This currently immitates the behavior of a login system by fetching data from
* the userstore that has been precreated. What fetchWithCredentials does currently will later go into the backend
*/
async function validateCredentials() {
// README: this should not be set here but in the child component. However, indication of something missing should
// not happen immediatelly in the first round of entry, so this code here defers it until the first hit of the login button.

const user = await users.fetchWithCredentials(
data[0].value,
await hash(data[1].value),
data[2].value
);
const authReturn = await authCookieLogin(loginData);

console.log(user);
// forget user data again to not have a plain text password lying around in memory somewhere
MaHaWo marked this conversation as resolved.
Show resolved Hide resolved
// any longer than needed
formData.forEach((element) => {
element.value = '';
});

if (user) {
userID = user.id;
if (authReturn.error) {
showAlert = true;
} else {
const status: string = await refresh();

if (remember) {
localStorage.setItem('currentUser', JSON.stringify(userID));
if (status !== 'success') {
console.log('error during retrieving active users: ', status);
showAlert = true;
alertMessage = $_('login.unauthorized') + ': ' + status;
} else {
localStorage.removeItem('currentUser');
console.log('login and user retrieval successful');
goto('/userLand/userLandingpage');
}

await users.setLoggedIn(userID);

await users.save();

goto(`${base}/userLand/userLandingpage/`);
} else {
showAlert = true;
data = data.map((element) => {
element.value = null;
return element;
});
}
}

// data and variables
export let data: any[];

const buttons = [
// form data and variables
let formData = [
{
component: Input,
value: '',
props: {
label: $_('login.usernameLabel'),
type: 'email',
placeholder: $_('login.usernameLabel'),
required: true,
id: 'username'
}
},
{
label: 'Login',
href: null,
onclick: validateCredentials
component: Input,
value: '',
props: {
label: $_('login.passwordLabel'),
type: 'password',
placeholder: $_('login.passwordLabel'),
required: true,
id: 'password'
}
}
];

let alertMessage = 'Eingaben sind falsch';
let userID: string;
let remember: boolean = false;
let showAlert: boolean = false;
const heading = 'Einloggen';

// check if credentials are stored
onMount(async () => {
// make dummyUser if not already there
users.load();

// check if credentials are saved
const savedUID = JSON.parse(localStorage.getItem('currentUser'));

if (savedUID) {
userID = savedUID;

const user: UserData = (await users.fetch(userID)) as UserData;

data[0].value = user.name;
data[1].value = user.password;
data[2].value = user.role;
remember = true;
}
});

onDestroy(async () => {
await users.save();
});
let alertMessage: string = $_('login.badCredentials');
</script>

{#if showAlert}
<AlertMessage
title={'Fehler'}
title={$_('login.alertMessageTitle')}
message={alertMessage}
lastpage={`${base}/userLand/userLogin`}
onclick={() => {
Expand All @@ -105,53 +104,43 @@
/>
{/if}

{#if users.get()['loggedIn'] && users.get()['loggedIn'] !== null}
<AlertMessage
title={'Fehler'}
message={`Sie sind bereits angemeldet. Melden sie sich zuerst ab um den Account zu wechseln.`}
lastpage={`${base}`}
onclick={() => {
showAlert = false;
}}
/>
{:else}
<div class="container m-1 mx-auto w-full max-w-xl">
<Card class="container m-1 mx-auto mb-6 w-full max-w-xl pb-6">
{#if heading}
<Heading
tag="h3"
class="m-1 mb-3 p-1 text-center font-bold tracking-tight text-gray-700 dark:text-gray-400"
>{heading}</Heading
>
{/if}

<form class="m-1 m-3 mx-auto w-full flex-col space-y-6">
{#each data as element}
<DataInput
component={element.component}
label={element.props.label}
bind:value={element.value}
properties={element.props}
eventHandlers={{
'on:change': element.onchange,
'on:blur': element.onblur,
'on:click': element.onclick
}}
/>
{/each}
</form>
<div class="container m-2 mx-auto w-full max-w-xl">
<Card class="container m-2 mx-auto mb-6 w-full max-w-xl pb-6">
<Heading
tag="h3"
class="m-2 mb-3 p-2 text-center font-bold tracking-tight text-gray-700 dark:text-gray-400"
>{$_('login.heading')}</Heading
>

<UserLoginUtil cls="p-6 mb-3" bind:checked={remember} />
<form onsubmit={preventDefault(submitData)} class="m-2 mx-auto w-full flex-col space-y-6">
{#each formData as element}
<DataInput
component={element.component}
label={element.props.label}
bind:value={element.value}
properties={element.props}
eventHandlers={{
'on:change': element.onchange,
'on:blur': element.onblur,
'on:click': element.onclick
}}
/>
{/each}

<NavigationButtons {buttons} />
</Card>
<UserLoginUtil cls="p-6 mb-3" bind:checked={remember} />

<span class="container mx-auto w-full text-gray-700 dark:text-gray-400">Not registered?</span>
<a
href={`${base}/userLand/userRegistration`}
class="text-primary-700 hover:underline dark:text-primary-500"
>
Create account
</a>
</div>
{/if}
<Button
class="dark:bg-primay-700 w-full bg-primary-700 text-center text-sm text-white hover:bg-primary-800 hover:text-white dark:hover:bg-primary-800"
type="submit">{$_('login.submitButtonLabel')}</Button
>
</form>
</Card>

<span class="container mx-auto w-full text-gray-700 dark:text-gray-400">Not registered?</span>
<a
href={`${base}/userLand/userRegistration`}
class="text-primary-700 hover:underline dark:text-primary-500"
>
Create account
</a>
</div>
Loading