-
-
Notifications
You must be signed in to change notification settings - Fork 23
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
Feature/change password dashboard #38
base: main
Are you sure you want to change the base?
Changes from all commits
d84a005
e907238
86aaabd
ef16a01
751f2b6
c0ceb11
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,17 +3,30 @@ import { redirect, type Actions } from '@sveltejs/kit'; | |
import type { PageServerLoad } from './$types'; | ||
import prisma from '@db'; | ||
import type { UserSettings } from '$lib/types'; | ||
import { validatePassword } from '$lib/server/validate'; | ||
import { hashPassword } from '$lib/crypto'; | ||
import { env } from '$env/dynamic/private'; | ||
|
||
export const load: PageServerLoad = async ({ cookies }) => { | ||
const userId = await getUserIdFromCookie(cookies); | ||
if (!userId) throw redirect(303, '/login'); | ||
|
||
const user = await prisma.user.findUnique({ | ||
where: { id: userId }, | ||
select: { settings: true }, | ||
select: { | ||
settings: true, | ||
username: true, | ||
name: true, | ||
email: true, | ||
}, | ||
}); | ||
|
||
return { settings: user?.settings as UserSettings }; | ||
return { | ||
settings: user?.settings as UserSettings, | ||
username: user?.username as string, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't think we need to use |
||
name: user?.name as string, | ||
email: user?.email as string, | ||
}; | ||
}; | ||
|
||
export const actions: Actions = { | ||
|
@@ -47,4 +60,61 @@ export const actions: Actions = { | |
}, | ||
}; | ||
}, | ||
changePassword: async ({ cookies, request }) => { | ||
const formData = await request.formData(); | ||
const token = cookies.get('token'); | ||
if (!token) { | ||
return redirect(301, '/login'); | ||
} | ||
const newPassword = formData.get('newPassword'); | ||
const confirmPassword = formData.get('confirmPassword'); | ||
|
||
if (!newPassword || !confirmPassword) { | ||
return { | ||
passwordForm: { | ||
success: false, | ||
error: 'Missing required fields', | ||
}, | ||
}; | ||
} | ||
|
||
if (newPassword !== confirmPassword) { | ||
return { | ||
passwordForm: { | ||
success: false, | ||
error: 'Passwords do not match', | ||
}, | ||
}; | ||
} | ||
|
||
try { | ||
if (newPassword) validatePassword(newPassword); | ||
} catch (err: any) { | ||
return { | ||
passwordForm: { | ||
success: false, | ||
error: err.message, | ||
}, | ||
}; | ||
} | ||
|
||
const userId = await getUserIdFromCookie(cookies); | ||
if (userId && newPassword) { | ||
const hash = await hashPassword(newPassword.toString(), env.SALT); | ||
const user = await prisma.user.update({ | ||
where: { | ||
id: userId, | ||
}, | ||
data: { | ||
password: hash, | ||
}, | ||
}); | ||
} | ||
|
||
return { | ||
passwordForm: { | ||
success: true, | ||
}, | ||
}; | ||
}, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -43,79 +43,141 @@ | |
<h1 class="text-5xl">Settings</h1> | ||
|
||
<div class="px-4"> | ||
<h4 class="text-2xl mt-6 mb-4">Defaults</h4> | ||
<div> | ||
<h4 class="text-2xl mt-6 mb-4">User</h4> | ||
<div class="grid grid-cols-3 px-4 py-1"> | ||
<div> | ||
<div class="text-xl">Name</div> | ||
<div class="opacity-80">{data?.name}</div> | ||
</div> | ||
|
||
<form | ||
method="post" | ||
action="?/defaults" | ||
class="mt-2 flex flex-col gap-4" | ||
use:enhance={() => { | ||
return async ({ result }) => { | ||
if (result.type === 'redirect') await goto(result.location); | ||
else await applyAction(result); | ||
}; | ||
}} | ||
> | ||
<div> | ||
<label for="encrypted" class="py-2">Encrypted</label> | ||
<input | ||
id="encrypted" | ||
class="bg-dark px-2 py-1" | ||
type="checkbox" | ||
name="encrypted" | ||
checked={settings?.defaults?.encrypted} | ||
/> | ||
<div class=""> | ||
<div class="text-xl">Username</div> | ||
<div class="opacity-80">{data?.username}</div> | ||
</div> | ||
<div> | ||
<div class="text-xl">Email</div> | ||
<div class="opacity-80">{data?.email}</div> | ||
</div> | ||
</div> | ||
|
||
<div> | ||
<label for="burn-after-read" class="py-2">Burn after read</label> | ||
<input | ||
id="burn-after-read" | ||
class="bg-dark px-2 py-1" | ||
type="checkbox" | ||
name="burn-after-read" | ||
checked={settings?.defaults?.burnAfterRead} | ||
/> | ||
</div> | ||
<div> | ||
<h4 class="text-2xl mt-6 mb-4">Change Password</h4> | ||
<div class="px-3"> | ||
<form | ||
method="post" | ||
action="?/changePassword" | ||
use:enhance | ||
class="flex flex-col gap-7" | ||
> | ||
<div class="flex flex-col lg:w-[40%] w-[80%] gap-1"> | ||
<label for="newPassword">New Password:</label> | ||
<input | ||
type="newPassword" | ||
name="newPassword" | ||
class="bg-dark py-1 text-center" | ||
/> | ||
</div> | ||
<div class="flex flex-col lg:w-[40%] w-[80%] gap-1"> | ||
<label for="confirmPassword">Confirm Password:</label> | ||
<input | ||
type="confirmPassword" | ||
name="confirmPassword" | ||
class="bg-dark py-1 text-center" | ||
/> | ||
</div> | ||
<div class=""> | ||
<button class="bg-amber-500 text-black text-lg px-4 py-1" | ||
>Save</button | ||
> | ||
{#if form?.passwordForm?.success} | ||
<span class="text-green-500">Saved</span> | ||
{/if} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can use if/else here instead of two different if statements. |
||
{#if form?.passwordForm?.success === false} | ||
<span class="text-red-800" | ||
>{form.passwordForm?.error}</span | ||
> | ||
{/if} | ||
</div> | ||
</form> | ||
</div> | ||
</div> | ||
<div> | ||
<h4 class="text-2xl mt-6 mb-4">Defaults</h4> | ||
|
||
<div> | ||
<span>Expires in:</span> | ||
<div class="grid grid-cols-3 gap-2 justify-center items-center"> | ||
<input | ||
type="number" | ||
class="bg-dark py-1 text-center" | ||
placeholder="DD" | ||
bind:value={expiresAfter.days} | ||
/> | ||
<input | ||
type="number" | ||
class="bg-dark py-1 text-center" | ||
placeholder="HH" | ||
bind:value={expiresAfter.hours} | ||
/> | ||
<form | ||
method="post" | ||
action="?/defaults" | ||
class="mt-2 flex flex-col gap-4 px-3" | ||
use:enhance={() => { | ||
return async ({ result }) => { | ||
if (result.type === 'redirect') await goto(result.location); | ||
else await applyAction(result); | ||
}; | ||
}} | ||
> | ||
<div> | ||
<label for="encrypted" class="py-2">Encrypted</label> | ||
<input | ||
type="number" | ||
class="bg-dark py-1 text-center" | ||
placeholder="MM" | ||
bind:value={expiresAfter.minutes} | ||
id="encrypted" | ||
class="bg-dark px-2 py-1" | ||
type="checkbox" | ||
name="encrypted" | ||
checked={settings?.defaults?.encrypted} | ||
/> | ||
</div> | ||
|
||
<div> | ||
<label for="burn-after-read" class="py-2">Burn after read</label | ||
> | ||
<input | ||
type="hidden" | ||
name="expires-after-seconds" | ||
bind:value={expiresAfterSeconds} | ||
id="burn-after-read" | ||
class="bg-dark px-2 py-1" | ||
type="checkbox" | ||
name="burn-after-read" | ||
checked={settings?.defaults?.burnAfterRead} | ||
/> | ||
</div> | ||
</div> | ||
|
||
<div class="mt-2"> | ||
<button class="bg-amber-500 text-black text-lg px-4 py-1" | ||
>Save</button | ||
> | ||
{#if form?.defaultsForm.success} | ||
<span class="text-green-500">Saved</span> | ||
<!-- {:else if form?.defaultsForm.error} | ||
<div> | ||
<span>Expires in:</span> | ||
<div class="grid grid-cols-3 gap-2 justify-center items-center"> | ||
<input | ||
type="number" | ||
class="bg-dark py-1 text-center" | ||
placeholder="DD" | ||
bind:value={expiresAfter.days} | ||
/> | ||
<input | ||
type="number" | ||
class="bg-dark py-1 text-center" | ||
placeholder="HH" | ||
bind:value={expiresAfter.hours} | ||
/> | ||
<input | ||
type="number" | ||
class="bg-dark py-1 text-center" | ||
placeholder="MM" | ||
bind:value={expiresAfter.minutes} | ||
/> | ||
<input | ||
type="hidden" | ||
name="expires-after-seconds" | ||
bind:value={expiresAfterSeconds} | ||
/> | ||
</div> | ||
</div> | ||
|
||
<div class="mt-2"> | ||
<button class="bg-amber-500 text-black text-lg px-4 py-1" | ||
>Save</button | ||
> | ||
{#if form?.defaultsForm !== undefined && form?.defaultsForm.success} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can be simplied as |
||
<span class="text-green-500">Saved</span> | ||
<!-- {:else if form?.defaultsForm.error} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you remove the commented lines please? |
||
<span class="text-red-500">Error</span> --> | ||
{/if} | ||
</div> | ||
</form> | ||
{/if} | ||
</div> | ||
</form> | ||
</div> | ||
</div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this empty div needed?