Skip to content

Commit

Permalink
Fixes and improvements to user and signup (#103)
Browse files Browse the repository at this point in the history
* fixes and improvements to user and signup

* add GQLSP introspection
  • Loading branch information
hingobway authored Jul 28, 2024
1 parent e62fcf2 commit 8f3560d
Show file tree
Hide file tree
Showing 9 changed files with 49 additions and 12 deletions.
2 changes: 1 addition & 1 deletion client/graphql-schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export type introspection = {
'ID': unknown;
'Int': unknown;
'Mutation': { kind: 'OBJECT'; name: 'Mutation'; fields: { 'cmsImageConfirm': { name: 'cmsImageConfirm'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'CMSImage'; ofType: null; }; } }; 'cmsImageDelete': { name: 'cmsImageDelete'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'CMSImage'; ofType: null; }; } }; 'cmsImageDeleteMultiple': { name: 'cmsImageDeleteMultiple'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'OBJECT'; name: 'CMSImage'; ofType: null; }; }; } }; 'cmsImageDeleteUnconfirmed': { name: 'cmsImageDeleteUnconfirmed'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'OBJECT'; name: 'CMSImage'; ofType: null; }; }; } }; 'cmsImageUpdate': { name: 'cmsImageUpdate'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'CMSImage'; ofType: null; }; } }; 'cmsImageUpload': { name: 'cmsImageUpload'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'CMSImageUploadOutput'; ofType: null; }; } }; 'cmsPageCreate': { name: 'cmsPageCreate'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'CMSPage'; ofType: null; }; } }; 'cmsPageDelete': { name: 'cmsPageDelete'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'CMSPage'; ofType: null; }; } }; 'cmsPageUpdate': { name: 'cmsPageUpdate'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'CMSPage'; ofType: null; }; } }; 'preUserCreate': { name: 'preUserCreate'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'PreUser'; ofType: null; }; } }; 'preUserDelete': { name: 'preUserDelete'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'PreUser'; ofType: null; }; } }; 'preUserUpdate': { name: 'preUserUpdate'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'PreUser'; ofType: null; }; } }; 'userCreate': { name: 'userCreate'; type: { kind: 'OBJECT'; name: 'User'; ofType: null; } }; 'userCreateCredential': { name: 'userCreateCredential'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'userDelete': { name: 'userDelete'; type: { kind: 'OBJECT'; name: 'User'; ofType: null; } }; 'userDeleteCredential': { name: 'userDeleteCredential'; type: { kind: 'OBJECT'; name: 'UserCredential'; ofType: null; } }; 'userResetSecret': { name: 'userResetSecret'; type: { kind: 'OBJECT'; name: 'User'; ofType: null; } }; 'userUpdate': { name: 'userUpdate'; type: { kind: 'OBJECT'; name: 'User'; ofType: null; } }; }; };
'PreUser': { kind: 'OBJECT'; name: 'PreUser'; fields: { 'email': { name: 'email'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'id': { name: 'id'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'ID'; ofType: null; }; } }; 'name': { name: 'name'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; } }; 'timestamp': { name: 'timestamp'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'TS'; ofType: null; }; } }; }; };
'PreUser': { kind: 'OBJECT'; name: 'PreUser'; fields: { 'email': { name: 'email'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'id': { name: 'id'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'ID'; ofType: null; }; } }; 'name': { name: 'name'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; } }; 'scope': { name: 'scope'; type: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'ENUM'; name: 'UserScopeProp'; ofType: null; }; }; } }; 'timestamp': { name: 'timestamp'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'TS'; ofType: null; }; } }; }; };
'Query': { kind: 'OBJECT'; name: 'Query'; fields: { 'cmsImage': { name: 'cmsImage'; type: { kind: 'OBJECT'; name: 'CMSImage'; ofType: null; } }; 'cmsImages': { name: 'cmsImages'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'OBJECT'; name: 'CMSImage'; ofType: null; }; }; } }; 'cmsImagesFromPageId': { name: 'cmsImagesFromPageId'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'OBJECT'; name: 'CMSImage'; ofType: null; }; }; } }; 'cmsPage': { name: 'cmsPage'; type: { kind: 'OBJECT'; name: 'CMSPage'; ofType: null; } }; 'cmsPageFromSlug': { name: 'cmsPageFromSlug'; type: { kind: 'OBJECT'; name: 'CMSPage'; ofType: null; } }; 'cmsPages': { name: 'cmsPages'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'OBJECT'; name: 'CMSPage'; ofType: null; }; }; } }; 'preUser': { name: 'preUser'; type: { kind: 'OBJECT'; name: 'PreUser'; ofType: null; } }; 'preUserFromEmail': { name: 'preUserFromEmail'; type: { kind: 'OBJECT'; name: 'PreUser'; ofType: null; } }; 'preUsers': { name: 'preUsers'; type: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'PreUser'; ofType: null; }; }; } }; 'user': { name: 'user'; type: { kind: 'OBJECT'; name: 'User'; ofType: null; } }; 'userFromAuth': { name: 'userFromAuth'; type: { kind: 'OBJECT'; name: 'User'; ofType: null; } }; 'userFromEmail': { name: 'userFromEmail'; type: { kind: 'OBJECT'; name: 'User'; ofType: null; } }; 'userSECURE': { name: 'userSECURE'; type: { kind: 'OBJECT'; name: 'UserSECURE'; ofType: null; } }; 'users': { name: 'users'; type: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'User'; ofType: null; }; }; } }; }; };
'String': unknown;
'TS': { kind: 'OBJECT'; name: 'TS'; fields: { 'created': { name: 'created'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'Int'; ofType: null; }; } }; 'updated': { name: 'updated'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'Int'; ofType: null; }; } }; }; };
Expand Down
2 changes: 1 addition & 1 deletion client/src/app/_components/_base/LineLabel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const LineLabel = ({
)}
>
<div className="flex-1 border-t"></div>
<div className="bg-dwhite">or</div>
<div className="bg-dwhite">{children}</div>
<div className="flex-1 border-t"></div>
</div>
</>
Expand Down
26 changes: 25 additions & 1 deletion client/src/app/account/_components/AccountDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ const AccountDetails = () => {
</div>
</div>

<div className=" flex flex-col gap-4 rounded-lg sm:flex-row sm:items-center">
<div className="flex flex-col gap-4 rounded-lg sm:flex-row">
{/* avatar view */}
<div className="relative flex flex-col items-center rounded-xl p-4 sm:max-w-56">
<a
Expand Down Expand Up @@ -198,6 +198,30 @@ const AccountDetails = () => {
}}
{...form.getInputProps('email')}
/>
<details className="rounded-md border border-transparent p-3 text-xs open:border-red-800/50 open:bg-red-400/20">
<summary className="cursor-pointer text-red-800 hover:underline">
Be cautious about changing your email. (click for more)
</summary>
<div className="mt-1 space-y-3 p-2 text-sm text-red-900">
<p>
<b>
If you don’t have access to the email you list here, you
may become unable to login.
</b>{' '}
Double check that it’s correct.
</p>
<p>
Additionally, your passkeys are stored with an email address
which is shown to you upon login. Changing the email listed
here{' '}
<b>
will not update the email address shown on your passkey
</b>
, although the passkeys will still work. All passkey managers
allow you to manually change their stored email address.
</p>
</div>
</details>
</div>
</div>
</div>
Expand Down
4 changes: 2 additions & 2 deletions client/src/app/auth/register/_components/SignupForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import { TRPCClientError } from '@trpc/client';
import { authErrorMap } from '../../_util/authErrors';
import LoadingBlurFrame from '@/app/_components/_base/LoadingBlurFrame';

const SignupForm = () => {
const [email, setEmail] = useState('');
const SignupForm = ({ initialEmail }: { initialEmail?: string }) => {
const [email, setEmail] = useState(initialEmail ?? '');
function handleChange(e: ChangeEvent<HTMLInputElement>) {
setEmail(e.currentTarget.value);
}
Expand Down
10 changes: 7 additions & 3 deletions client/src/app/auth/register/page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { Metadata } from 'next';
import type { Metadata } from 'next';
import type { SearchParams } from '@/util/propTypes';

import SignupForm from './_components/SignupForm';
import A from '@/app/_components/_base/A';

export const metadata: Metadata = { title: 'Sign up' };

export default function RegisterPage() {
export default function RegisterPage({ searchParams }: SearchParams) {
let initialEmail = searchParams.email;
if (typeof initialEmail !== 'string') initialEmail = undefined;

return (
<>
<div className="flex flex-col gap-4">
Expand Down Expand Up @@ -34,7 +38,7 @@ export default function RegisterPage() {

<hr className="border-slate-300" />

<SignupForm />
<SignupForm initialEmail={initialEmail} />

<div className="t">
<A href="login">I already have an account</A>
Expand Down
2 changes: 1 addition & 1 deletion server/graphql-schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export type introspection = {
'ID': unknown;
'Int': unknown;
'Mutation': { kind: 'OBJECT'; name: 'Mutation'; fields: { 'cmsImageConfirm': { name: 'cmsImageConfirm'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'CMSImage'; ofType: null; }; } }; 'cmsImageDelete': { name: 'cmsImageDelete'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'CMSImage'; ofType: null; }; } }; 'cmsImageDeleteMultiple': { name: 'cmsImageDeleteMultiple'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'OBJECT'; name: 'CMSImage'; ofType: null; }; }; } }; 'cmsImageDeleteUnconfirmed': { name: 'cmsImageDeleteUnconfirmed'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'OBJECT'; name: 'CMSImage'; ofType: null; }; }; } }; 'cmsImageUpdate': { name: 'cmsImageUpdate'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'CMSImage'; ofType: null; }; } }; 'cmsImageUpload': { name: 'cmsImageUpload'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'CMSImageUploadOutput'; ofType: null; }; } }; 'cmsPageCreate': { name: 'cmsPageCreate'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'CMSPage'; ofType: null; }; } }; 'cmsPageDelete': { name: 'cmsPageDelete'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'CMSPage'; ofType: null; }; } }; 'cmsPageUpdate': { name: 'cmsPageUpdate'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'CMSPage'; ofType: null; }; } }; 'preUserCreate': { name: 'preUserCreate'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'PreUser'; ofType: null; }; } }; 'preUserDelete': { name: 'preUserDelete'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'PreUser'; ofType: null; }; } }; 'preUserUpdate': { name: 'preUserUpdate'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'PreUser'; ofType: null; }; } }; 'userCreate': { name: 'userCreate'; type: { kind: 'OBJECT'; name: 'User'; ofType: null; } }; 'userCreateCredential': { name: 'userCreateCredential'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'userDelete': { name: 'userDelete'; type: { kind: 'OBJECT'; name: 'User'; ofType: null; } }; 'userDeleteCredential': { name: 'userDeleteCredential'; type: { kind: 'OBJECT'; name: 'UserCredential'; ofType: null; } }; 'userResetSecret': { name: 'userResetSecret'; type: { kind: 'OBJECT'; name: 'User'; ofType: null; } }; 'userUpdate': { name: 'userUpdate'; type: { kind: 'OBJECT'; name: 'User'; ofType: null; } }; }; };
'PreUser': { kind: 'OBJECT'; name: 'PreUser'; fields: { 'email': { name: 'email'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'id': { name: 'id'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'ID'; ofType: null; }; } }; 'name': { name: 'name'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; } }; 'timestamp': { name: 'timestamp'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'TS'; ofType: null; }; } }; }; };
'PreUser': { kind: 'OBJECT'; name: 'PreUser'; fields: { 'email': { name: 'email'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'id': { name: 'id'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'ID'; ofType: null; }; } }; 'name': { name: 'name'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; } }; 'scope': { name: 'scope'; type: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'ENUM'; name: 'UserScopeProp'; ofType: null; }; }; } }; 'timestamp': { name: 'timestamp'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'TS'; ofType: null; }; } }; }; };
'Query': { kind: 'OBJECT'; name: 'Query'; fields: { 'cmsImage': { name: 'cmsImage'; type: { kind: 'OBJECT'; name: 'CMSImage'; ofType: null; } }; 'cmsImages': { name: 'cmsImages'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'OBJECT'; name: 'CMSImage'; ofType: null; }; }; } }; 'cmsImagesFromPageId': { name: 'cmsImagesFromPageId'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'OBJECT'; name: 'CMSImage'; ofType: null; }; }; } }; 'cmsPage': { name: 'cmsPage'; type: { kind: 'OBJECT'; name: 'CMSPage'; ofType: null; } }; 'cmsPageFromSlug': { name: 'cmsPageFromSlug'; type: { kind: 'OBJECT'; name: 'CMSPage'; ofType: null; } }; 'cmsPages': { name: 'cmsPages'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'OBJECT'; name: 'CMSPage'; ofType: null; }; }; } }; 'preUser': { name: 'preUser'; type: { kind: 'OBJECT'; name: 'PreUser'; ofType: null; } }; 'preUserFromEmail': { name: 'preUserFromEmail'; type: { kind: 'OBJECT'; name: 'PreUser'; ofType: null; } }; 'preUsers': { name: 'preUsers'; type: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'PreUser'; ofType: null; }; }; } }; 'user': { name: 'user'; type: { kind: 'OBJECT'; name: 'User'; ofType: null; } }; 'userFromAuth': { name: 'userFromAuth'; type: { kind: 'OBJECT'; name: 'User'; ofType: null; } }; 'userFromEmail': { name: 'userFromEmail'; type: { kind: 'OBJECT'; name: 'User'; ofType: null; } }; 'userSECURE': { name: 'userSECURE'; type: { kind: 'OBJECT'; name: 'UserSECURE'; ofType: null; } }; 'users': { name: 'users'; type: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'User'; ofType: null; }; }; } }; }; };
'String': unknown;
'TS': { kind: 'OBJECT'; name: 'TS'; fields: { 'created': { name: 'created'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'Int'; ofType: null; }; } }; 'updated': { name: 'updated'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'Int'; ofType: null; }; } }; }; };
Expand Down
11 changes: 9 additions & 2 deletions server/src/api/routes/register.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ export const createUser = t.procedure
query GetPreUser($preUserId: ID!) {
preUser(id: $preUserId) {
id
scope
}
}
`),
Expand All @@ -100,13 +101,19 @@ export const createUser = t.procedure
$email: String!
$name: String!
$firstName: String!
$scope: [UserScopeProp!]
) {
userCreate(email: $email, name: $name, firstName: $firstName) {
userCreate(
email: $email
name: $name
firstName: $firstName
scope: $scope
) {
id
}
}
`),
{ ...user }
{ ...user, scope: d0.preUser.scope }
);
if (e1 || !d1?.userCreate)
throw err(
Expand Down
3 changes: 2 additions & 1 deletion server/src/db/schema/PreUser/types.graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export default gql`
id: ID!
email: String!
name: String
scope: [UserScopeProp!]
timestamp: TS!
}
Expand Down Expand Up @@ -48,7 +49,7 @@ export default gql`
update a preuser
"""
preUserUpdate(id: ID!, name: String): PreUser!
preUserUpdate(id: ID!, name: String, scope: [UserScopeProp!]): PreUser!
"""
**SCOPE: admin**
Expand Down
1 change: 1 addition & 0 deletions server/src/db/schema/User/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export const getUserSECURE = h<QueryResolvers['userSECURE']>(
);

export const userCreate = h<MutationResolvers['userCreate']>(
scoped('ADMIN'),
async ({ sources, args: newUser, scope }) => {
const nu = newUser as DBUser;
nu.email = prepEmail(nu.email);
Expand Down

0 comments on commit 8f3560d

Please sign in to comment.