1
0
mirror of https://github.com/pocket-id/pocket-id.git synced 2026-02-12 10:18:31 +00:00

feat: add ability to upload a profile picture (#244)

This commit is contained in:
Elias Schneider
2025-02-19 14:28:45 +01:00
committed by GitHub
parent dca9e7a11a
commit 652ee6ad5d
38 changed files with 500 additions and 73 deletions

View File

@@ -33,41 +33,37 @@
</script>
<section>
<div class="flex min-h-[calc(100vh-64px)] w-full flex-col justify-between bg-muted/40">
<div class="bg-muted/40 flex min-h-[calc(100vh-64px)] w-full flex-col justify-between">
<main
class="mx-auto flex w-full max-w-[1640px] flex-col gap-x-4 gap-y-10 p-4 md:p-10 lg:flex-row"
>
<div>
<div class="min-w-[200px] xl:min-w-[250px]">
<div class="mx-auto grid w-full gap-2">
<h1 class="mb-5 text-3xl font-semibold">Settings</h1>
</div>
<div
class="mx-auto grid items-start gap-6 md:grid-cols-[180px_1fr] lg:grid-cols-[250px_1fr]"
>
<nav class="grid gap-4 text-sm text-muted-foreground">
{#each links as { href, label }}
<a {href} class={$page.url.pathname.startsWith(href) ? 'font-bold text-primary' : ''}>
{label}
</a>
{/each}
{#if $userStore?.isAdmin && versionInformation.isUpToDate === false}
<a
href="https://github.com/pocket-id/pocket-id/releases/latest"
target="_blank"
class="flex items-center gap-2"
>
Update Pocket ID <LucideExternalLink class="my-auto inline-block h-3 w-3" />
</a>
{/if}
</nav>
</div>
<nav class="text-muted-foreground grid gap-4 text-sm">
{#each links as { href, label }}
<a {href} class={$page.url.pathname.startsWith(href) ? 'text-primary font-bold' : ''}>
{label}
</a>
{/each}
{#if $userStore?.isAdmin && versionInformation.isUpToDate === false}
<a
href="https://github.com/pocket-id/pocket-id/releases/latest"
target="_blank"
class="flex items-center gap-2"
>
Update Pocket ID <LucideExternalLink class="my-auto inline-block h-3 w-3" />
</a>
{/if}
</nav>
</div>
<div class="flex w-full flex-col gap-5 overflow-x-hidden">
{@render children()}
</div>
</main>
<div class="flex flex-col items-center">
<p class="py-3 text-xs text-muted-foreground">
<p class="text-muted-foreground py-3 text-xs">
Powered by <a
class="text-foreground"
href="https://github.com/pocket-id/pocket-id"

View File

@@ -13,6 +13,7 @@
import { toast } from 'svelte-sonner';
import AccountForm from './account-form.svelte';
import PasskeyList from './passkey-list.svelte';
import ProfilePictureSettings from '../../../lib/components/form/profile-picture-settings.svelte';
import RenamePasskeyModal from './rename-passkey-modal.svelte';
let { data } = $props();
@@ -36,6 +37,13 @@
return success;
}
async function updateProfilePicture(image: File) {
await userService
.updateCurrentUsersProfilePicture(image)
.then(() => toast.success('Profile picture updated successfully'))
.catch(axiosErrorToast);
}
async function createPasskey() {
try {
const opts = await webauthnService.getRegistrationOptions();
@@ -86,6 +94,12 @@
</Card.Root>
</fieldset>
<Card.Root>
<Card.Content class="pt-6">
<ProfilePictureSettings userId="me" isLdapUser={!!account.ldapId} callback={updateProfilePicture} />
</Card.Content>
</Card.Root>
<Card.Root>
<Card.Header>
<div class="flex items-center justify-between">

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import FormInput from '$lib/components/form-input.svelte';
import FormInput from '$lib/components/form/form-input.svelte';
import { Button } from '$lib/components/ui/button';
import type { UserCreate } from '$lib/types/user.type';
import { createForm } from '$lib/utils/form-util';

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import FileInput from '$lib/components/file-input.svelte';
import FileInput from '$lib/components/form/file-input.svelte';
import { Label } from '$lib/components/ui/label';
import { cn } from '$lib/utils/style';
import type { HTMLAttributes } from 'svelte/elements';

View File

@@ -1,8 +1,8 @@
<script lang="ts">
import { env } from '$env/dynamic/public';
import CheckboxWithLabel from '$lib/components/checkbox-with-label.svelte';
import CheckboxWithLabel from '$lib/components/form/checkbox-with-label.svelte';
import { openConfirmDialog } from '$lib/components/confirm-dialog';
import FormInput from '$lib/components/form-input.svelte';
import FormInput from '$lib/components/form/form-input.svelte';
import { Button } from '$lib/components/ui/button';
import AppConfigService from '$lib/services/app-config-service';
import type { AllAppConfig } from '$lib/types/application-configuration';

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import { env } from '$env/dynamic/public';
import CheckboxWithLabel from '$lib/components/checkbox-with-label.svelte';
import FormInput from '$lib/components/form-input.svelte';
import CheckboxWithLabel from '$lib/components/form/checkbox-with-label.svelte';
import FormInput from '$lib/components/form/form-input.svelte';
import { Button } from '$lib/components/ui/button';
import type { AllAppConfig } from '$lib/types/application-configuration';
import { createForm } from '$lib/utils/form-util';

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import { env } from '$env/dynamic/public';
import CheckboxWithLabel from '$lib/components/checkbox-with-label.svelte';
import FormInput from '$lib/components/form-input.svelte';
import CheckboxWithLabel from '$lib/components/form/checkbox-with-label.svelte';
import FormInput from '$lib/components/form/form-input.svelte';
import { Button } from '$lib/components/ui/button';
import AppConfigService from '$lib/services/app-config-service';
import type { AllAppConfig } from '$lib/types/application-configuration';
@@ -38,6 +38,7 @@
ldapAttributeUserEmail: appConfig.ldapAttributeUserEmail,
ldapAttributeUserFirstName: appConfig.ldapAttributeUserFirstName,
ldapAttributeUserLastName: appConfig.ldapAttributeUserLastName,
ldapAttributeUserProfilePicture: appConfig.ldapAttributeUserProfilePicture,
ldapAttributeGroupMember: appConfig.ldapAttributeGroupMember,
ldapAttributeGroupUniqueIdentifier: appConfig.ldapAttributeGroupUniqueIdentifier,
ldapAttributeGroupName: appConfig.ldapAttributeGroupName,
@@ -57,6 +58,7 @@
ldapAttributeUserEmail: z.string().min(1),
ldapAttributeUserFirstName: z.string().min(1),
ldapAttributeUserLastName: z.string().min(1),
ldapAttributeUserProfilePicture: z.string(),
ldapAttributeGroupMember: z.string(),
ldapAttributeGroupUniqueIdentifier: z.string().min(1),
ldapAttributeGroupName: z.string().min(1),
@@ -166,6 +168,12 @@
placeholder="sn"
bind:input={$inputs.ldapAttributeUserLastName}
/>
<FormInput
label="User Profile Picture Attribute"
description="The value of this attribute can either be a URL, a binary or a base64 encoded image."
placeholder="jpegPhoto"
bind:input={$inputs.ldapAttributeUserProfilePicture}
/>
<FormInput
label="Group Members Attribute"
description="The attribute to use for querying members of a group."

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import FormInput from '$lib/components/form-input.svelte';
import FormInput from '$lib/components/form/form-input.svelte';
import { Button } from '$lib/components/ui/button';
import { Input } from '$lib/components/ui/input';
import { LucideMinus, LucidePlus } from 'lucide-svelte';

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import CheckboxWithLabel from '$lib/components/checkbox-with-label.svelte';
import FileInput from '$lib/components/file-input.svelte';
import FormInput from '$lib/components/form-input.svelte';
import CheckboxWithLabel from '$lib/components/form/checkbox-with-label.svelte';
import FileInput from '$lib/components/form/file-input.svelte';
import FormInput from '$lib/components/form/form-input.svelte';
import { Button } from '$lib/components/ui/button';
import Label from '$lib/components/ui/label/label.svelte';
import type {

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import CollapsibleCard from '$lib/components/collapsible-card.svelte';
import CustomClaimsInput from '$lib/components/custom-claims-input.svelte';
import CustomClaimsInput from '$lib/components/form/custom-claims-input.svelte';
import { Badge } from '$lib/components/ui/badge';
import { Button } from '$lib/components/ui/button';
import * as Card from '$lib/components/ui/card';

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import FormInput from '$lib/components/form-input.svelte';
import FormInput from '$lib/components/form/form-input.svelte';
import { Button } from '$lib/components/ui/button';
import appConfigStore from '$lib/stores/application-configuration-store';
import type { UserGroupCreate } from '$lib/types/user-group.type';

View File

@@ -1,5 +1,7 @@
<script lang="ts">
import CollapsibleCard from '$lib/components/collapsible-card.svelte';
import CustomClaimsInput from '$lib/components/form/custom-claims-input.svelte';
import ProfilePictureSettings from '$lib/components/form/profile-picture-settings.svelte';
import Badge from '$lib/components/ui/badge/badge.svelte';
import { Button } from '$lib/components/ui/button';
import * as Card from '$lib/components/ui/card';
@@ -9,7 +11,6 @@
import { axiosErrorToast } from '$lib/utils/error-util';
import { LucideChevronLeft } from 'lucide-svelte';
import { toast } from 'svelte-sonner';
import CustomClaimsInput from '../../../../../lib/components/custom-claims-input.svelte';
import UserForm from '../user-form.svelte';
let { data } = $props();
@@ -39,6 +40,13 @@
axiosErrorToast(e);
});
}
async function updateProfilePicture(image: File) {
await userService
.updateProfilePicture(user.id, image)
.then(() => toast.success('Profile picture updated successfully'))
.catch(axiosErrorToast);
}
</script>
<svelte:head>
@@ -62,6 +70,16 @@
</Card.Content>
</Card.Root>
<Card.Root>
<Card.Content class="pt-6">
<ProfilePictureSettings
userId={user.id}
isLdapUser={!!user.ldapId}
callback={updateProfilePicture}
/>
</Card.Content>
</Card.Root>
<CollapsibleCard
id="user-custom-claims"
title="Custom Claims"

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import CheckboxWithLabel from '$lib/components/checkbox-with-label.svelte';
import FormInput from '$lib/components/form-input.svelte';
import CheckboxWithLabel from '$lib/components/form/checkbox-with-label.svelte';
import FormInput from '$lib/components/form/form-input.svelte';
import { Button } from '$lib/components/ui/button';
import appConfigStore from '$lib/stores/application-configuration-store';
import type { User, UserCreate } from '$lib/types/user.type';