Skip to content

Commit

Permalink
Merge pull request #48 from bde-isima/staging
Browse files Browse the repository at this point in the history
October release
  • Loading branch information
citorva authored Nov 11, 2023
2 parents 7cfb66f + 234a622 commit f7ca0ca
Show file tree
Hide file tree
Showing 13 changed files with 259 additions and 58 deletions.
4 changes: 2 additions & 2 deletions .env.template
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Copy the content of this file to a new .env file with proper values

DATABASE_URL=postgresql://postgres:postgres@localhost:5432/postgres
DATABASE_URL=postgresql://postgres:postgres@bde_isima_pg:5432/postgres

NEXT_PUBLIC_FRONTEND_URL=http://localhost:3000
NEXT_PUBLIC_GA_TRACKING_ID=REDACTED
Expand All @@ -17,4 +17,4 @@ SMTP_HOST=smtp.gmail.com
SMTP_PASSWORD=your_password
SMTP_PORT=587

CONTACT_MAIL=contact@example.com
CONTACT_MAIL=contact@example.com
5 changes: 5 additions & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Learn how to add code owners here:
# https://help.github.com/en/articles/about-code-owners


* @bde-isima/bde
12 changes: 11 additions & 1 deletion app/components/auth/LoginForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ export default function LoginForm() {
}
};

let errorMessage = '';

if (router.query.invalid) {
console.log(router.query.invalid);

if (router.query.invalid == '1') errorMessage = 'Jeton invalide';
else if (router.query.invalid == '2') errorMessage = 'Jeton expiré';
else errorMessage = 'Erreur inconnue';
}

return (
<Form submitText="Connexion" schema={LoginInput} initialValues={{ identifier: undefined }} onSubmit={onSubmit}>
<TextField
Expand All @@ -49,7 +59,7 @@ export default function LoginForm() {
color={router.query.invalid && !message ? 'error.main' : 'success.main'}
align="center"
>
<b>{message || (router.query.invalid ? 'Jeton invalide' : '')}</b>
<b>{message || errorMessage}</b>
</Typography>
</Form>
);
Expand Down
4 changes: 3 additions & 1 deletion app/components/dashboard/users/PromotionsForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import { useQuery } from '@blitzjs/rpc';
import getPromotions from 'app/entities/promotions/queries/getPromotions';

export default function PromotionsForm() {
const [{ promotions }] = useQuery(getPromotions, {});
const [{ promotions }] = useQuery(getPromotions, {
orderBy: { year: 'desc' }
});

return (
<Select
Expand Down
11 changes: 11 additions & 0 deletions app/entities/auth/mutations/invalidateToken.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import db from 'db';

import { resolver } from '@blitzjs/rpc';

type ValidateTokenInput = {
token: string;
};

export default resolver.pipe(async ({ token }: ValidateTokenInput) => {
await db.loginRequest.delete({ where: { token: token } });
});
4 changes: 2 additions & 2 deletions app/entities/auth/mutations/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export default resolver.pipe(
const inFifteenMinutes = new Date(new Date().getTime() + 15 * 60 * 1000);

if (process.env.NODE_ENV === 'development') {
console.log(`Lien de connexion: ${process.env.NEXT_PUBLIC_FRONTEND_URL}/verify-login?token=${token}`);
console.log(`Lien de connexion: ${process.env.NEXT_PUBLIC_FRONTEND_URL}/authenticate?token=${token}`);
}

try {
Expand All @@ -36,7 +36,7 @@ export default resolver.pipe(
variables: {
subject,
firstname: user.firstname,
link: `${process.env.NEXT_PUBLIC_FRONTEND_URL}/verify-login?token=${token}`
link: `${process.env.NEXT_PUBLIC_FRONTEND_URL}/authenticate?token=${token}`
}
})
]);
Expand Down
34 changes: 34 additions & 0 deletions app/entities/auth/mutations/validateToken.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Ctx } from 'blitz';
import db from 'db';

import { resolver } from '@blitzjs/rpc';

type ValidateTokenInput = {
token: string;
};

export default resolver.pipe(async ({ token }: ValidateTokenInput, { session }: Ctx) => {
const request = await db.loginRequest.findUnique({
where: { token: token },
include: { user: true }
});

if (!request) return 'UnknownTokenError';

await db.loginRequest.delete({ where: { id: request.id } });

if (new Date() > request.expires) return 'ExpiredTokenError';

await session.$create({
userId: request.user.id,
firstname: request.user.firstname,
lastname: request.user.lastname,
nickname: request.user.nickname,
image: request.user.image,
email: request.user.email,
card: request.user.card,
roles: request.user.roles
});

return 'LoggedIn';
});
23 changes: 23 additions & 0 deletions app/entities/auth/queries/userInfoFromToken.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import db from 'db';

import { resolver } from '@blitzjs/rpc';

type UserInfoFromTokenInput = {
token: string;
};

export default resolver.pipe(async ({ token }: UserInfoFromTokenInput) => {
return await db.loginRequest.findUnique({
where: { token: token },
include: {
user: {
select: {
firstname: true,
lastname: true,
nickname: true,
image: true
}
}
}
});
});
2 changes: 1 addition & 1 deletion app/entities/users/mutations/upsertUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export default resolver.pipe(resolver.authorize(['*']), async ({ where, create,
variables: {
subject,
firstname: newUser.firstname,
link: `${process.env.NEXT_PUBLIC_FRONTEND_URL}/verify-login?token=${token}`
link: `${process.env.NEXT_PUBLIC_FRONTEND_URL}/authenticate?token=${token}`
}
})
]);
Expand Down
137 changes: 137 additions & 0 deletions pages/authenticate.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import { useState } from 'react';

import Button from '@mui/material/Button';
import Card from '@mui/material/Card';
import Typography from '@mui/material/Typography';

import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRightTwoTone';

import Head from 'next/head';
import Image from 'next/image';
import { NextRouter, useRouter } from 'next/router';

import { useMutation, useQuery } from '@blitzjs/rpc';

import invalidateToken from 'app/entities/auth/mutations/invalidateToken';
import validateToken from 'app/entities/auth/mutations/validateToken';
import userInfoFromToken from 'app/entities/auth/queries/userInfoFromToken';

import DefaultUser from 'public/static/images/illustrations/DefaultUser.svg';

function getToken(router: NextRouter) {
try {
const token = router.query.token;

if (token == undefined) return '';

if (typeof token === 'string') return token;

if (token.length > 0) return token[0];
} catch {}

return '';
}

function AuthenticatePage() {
const router = useRouter();
const token = getToken(router);

const [response] = useQuery(userInfoFromToken, {
token: token
});
const [validate] = useMutation(validateToken);
const [invalidate] = useMutation(invalidateToken);

const [loggedIn, setLoggedIn] = useState<boolean>(false);

if (!loggedIn) {
if (response == undefined) {
router.push('/login?invalid=1').finally(() => {});
} else {
const redirectURL = response.callbackUrl;

function onAuth() {
validate({ token: token }).then(
(response) => {
setLoggedIn(true);

let redirectPath = redirectURL;
if (response == 'UnknownTokenError') redirectPath = '/login?invalid=1';
if (response == 'ExpiredTokenError') redirectPath = '/login?invalid=2';

router.push(redirectPath).finally(() => {});
},
() => {
router.push('/login?invalid=0').finally(() => {});
}
);
}

function onCancel() {
invalidate({ token: token }).finally(() => {
router.push('/').finally(() => {});
});
}

const user = response.user;

let shownName = user.nickname == null ? user.firstname : response.user.nickname!;

return (
<>
<Head>
<title>Bienvenue `{shownName}`</title>
</Head>

<div className="flex flex-col items-center p-8">
<Card className="rounded-full z-10 p-0 flex justify-center items-center">
<Image
src={user.image ? user.image : DefaultUser}
width={150}
height={150}
alt={`Photo de ${shownName}`}
quality={100}
/>
</Card>

<Card className="py-6 px-4 rounded-md -mt-16 pt-20 max-w-sm" variant="outlined">
<div className="text-center">
<Typography variant="h4" paragraph>
Bienvenue <b>{shownName}</b>
</Typography>

<Typography className="mb-6" variant="h6">
Bon retour parmi nous&nbsp;!
</Typography>

<Button
variant="contained"
size="large"
aria-label="Continuer vers le hub"
color="primary"
endIcon={<KeyboardArrowRightIcon />}
onClick={onAuth}
>
Continuer vers le hub
</Button>

<Button
variant="text"
size="small"
aria-label="Annuler ma connexion"
color="neutral"
onClick={onCancel}
>
Annuler ma connexion
</Button>
</div>
</Card>
</div>
</>
);
}
}
}

AuthenticatePage.suppressFirstRenderFlicker = true;
export default AuthenticatePage;
7 changes: 5 additions & 2 deletions pages/login.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { BlitzPage } from '@blitzjs/auth';

import LoginFallback from 'app/components/auth/LoginFallback';

function Login() {
const Login: BlitzPage = () => {
return <LoginFallback />;
}
};

Login.suppressFirstRenderFlicker = true;
Login.redirectAuthenticatedTo = '/hub';
export default Login;
49 changes: 0 additions & 49 deletions pages/verify-login.ts

This file was deleted.

25 changes: 25 additions & 0 deletions public/static/images/illustrations/DefaultUser.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit f7ca0ca

Please sign in to comment.