@@ -475,6 +475,163 @@ const app = new Elysia({
475475
476476 return redirect ( `${ WEBROOT } /login` , 302 ) ;
477477 } )
478+ . get ( "/account" , async ( { jwt, redirect, cookie : { auth } } ) => {
479+ if ( ! auth ?. value ) {
480+ return redirect ( `${ WEBROOT } /` ) ;
481+ }
482+ const user = await jwt . verify ( auth . value ) ;
483+
484+ if ( ! user ) {
485+ return redirect ( `${ WEBROOT } /` , 302 ) ;
486+ }
487+
488+ const userData = db
489+ . query ( "SELECT * FROM users WHERE id = ?" )
490+ . as ( User )
491+ . get ( user . id ) ;
492+
493+ if ( ! userData ) {
494+ return redirect ( `${ WEBROOT } /` , 302 ) ;
495+ }
496+
497+ return (
498+ < BaseHtml webroot = { WEBROOT } title = "ConvertX | Login" >
499+ < >
500+ < Header
501+ webroot = { WEBROOT }
502+ accountRegistration = { ACCOUNT_REGISTRATION }
503+ allowUnauthenticated = { ALLOW_UNAUTHENTICATED }
504+ hideHistory = { HIDE_HISTORY }
505+ />
506+ < main
507+ class = { `
508+ w-full px-2
509+ sm:px-4
510+ ` }
511+ >
512+ < article class = "article" >
513+ < form method = "post" class = "flex flex-col gap-4" >
514+ < fieldset class = "mb-4 flex flex-col gap-4" >
515+ < label class = "flex flex-col gap-1" >
516+ Email
517+ < input
518+ type = "email"
519+ name = "email"
520+ class = "rounded-sm bg-neutral-800 p-3"
521+ placeholder = "Email"
522+ autocomplete = "email"
523+ value = { userData . email }
524+ required
525+ />
526+ </ label >
527+ < label class = "flex flex-col gap-1" >
528+ Password (leave blank for unchanged)
529+ < input
530+ type = "password"
531+ name = "newPassword"
532+ class = "rounded-sm bg-neutral-800 p-3"
533+ placeholder = "Password"
534+ autocomplete = "new-password"
535+ />
536+ </ label >
537+ < label class = "flex flex-col gap-1" >
538+ Current Password
539+ < input
540+ type = "password"
541+ name = "password"
542+ class = "rounded-sm bg-neutral-800 p-3"
543+ placeholder = "Password"
544+ autocomplete = "current-password"
545+ required
546+ />
547+ </ label >
548+ </ fieldset >
549+ < div role = "group" >
550+ < input
551+ type = "submit"
552+ value = "Update"
553+ class = "btn-primary w-full"
554+ />
555+ </ div >
556+ </ form >
557+ </ article >
558+ </ main >
559+ </ >
560+ </ BaseHtml >
561+ ) ;
562+ } )
563+ . post (
564+ "/account" ,
565+ async function handler ( { body, set, redirect, jwt, cookie : { auth } } ) {
566+ if ( ! auth ?. value ) {
567+ return redirect ( `${ WEBROOT } /login` , 302 ) ;
568+ }
569+
570+ const user = await jwt . verify ( auth . value ) ;
571+ if ( ! user ) {
572+ return redirect ( `${ WEBROOT } /login` , 302 ) ;
573+ }
574+ const existingUser = db
575+ . query ( "SELECT * FROM users WHERE id = ?" )
576+ . as ( User )
577+ . get ( user . id ) ;
578+
579+ if ( ! existingUser ) {
580+ if ( auth ?. value ) {
581+ auth . remove ( ) ;
582+ }
583+ return redirect ( `${ WEBROOT } /login` , 302 ) ;
584+ }
585+
586+ const validPassword = await Bun . password . verify (
587+ body . password ,
588+ existingUser . password ,
589+ ) ;
590+
591+ if ( ! validPassword ) {
592+ set . status = 403 ;
593+ return {
594+ message : "Invalid credentials." ,
595+ } ;
596+ }
597+
598+ const fields = [ ] ;
599+ const values = [ ] ;
600+
601+ if ( body . email ) {
602+ const existingUser = await db
603+ . query ( "SELECT id FROM users WHERE email = ?" )
604+ . as ( User )
605+ . get ( body . email ) ;
606+ if ( existingUser && existingUser . id . toString ( ) !== user . id ) {
607+ set . status = 409 ;
608+ return { message : "Email already in use." } ;
609+ }
610+ fields . push ( "email" ) ;
611+ values . push ( body . email ) ;
612+ }
613+ if ( body . newPassword ) {
614+ fields . push ( "password" ) ;
615+ values . push ( await Bun . password . hash ( body . newPassword ) ) ;
616+ }
617+
618+ if ( fields . length > 0 ) {
619+ db . query (
620+ `UPDATE users SET ${ fields . map ( ( field ) => `${ field } =?` ) . join ( ", " ) } WHERE id=?` ,
621+ ) . run ( ...values , user . id ) ;
622+ }
623+
624+ return redirect ( `${ WEBROOT } /` , 302 ) ;
625+ } ,
626+ {
627+ body : t . Object ( {
628+ email : t . MaybeEmpty ( t . String ( ) ) ,
629+ newPassword : t . MaybeEmpty ( t . String ( ) ) ,
630+ password : t . String ( ) ,
631+ } ) ,
632+ } ,
633+ )
634+
478635 . get ( "/" , async ( { jwt, redirect, cookie : { auth, jobId } } ) => {
479636 if ( ! ALLOW_UNAUTHENTICATED ) {
480637 if ( FIRST_RUN ) {
0 commit comments