diff --git a/geneit_app/src/App.tsx b/geneit_app/src/App.tsx
index dfff5ac..4f3161f 100644
--- a/geneit_app/src/App.tsx
+++ b/geneit_app/src/App.tsx
@@ -9,6 +9,7 @@ import { useAtom } from "jotai";
import { BaseAuthenticatedPage } from "./widgets/BaseAuthenticatedPage";
import { PasswordForgottenRoute } from "./routes/auth/PasswordForgottenRoute";
import { ResetPasswordRoute } from "./routes/auth/ResetPasswordRoute";
+import { NewAccountRoute } from "./routes/auth/NewAccountRoute";
/**
* Core app
@@ -24,6 +25,7 @@ function App() {
}>
} />
} />
+ } />
}
diff --git a/geneit_app/src/api/AuthApi.ts b/geneit_app/src/api/AuthApi.ts
index 9a62fc0..47838a0 100644
--- a/geneit_app/src/api/AuthApi.ts
+++ b/geneit_app/src/api/AuthApi.ts
@@ -1,6 +1,14 @@
import { atom } from "jotai";
import { APIClient } from "./ApiClient";
+export enum CreateAccountResult {
+ TooManyRequests,
+ BadInputData,
+ MailAlreadyExists,
+ Success,
+ Error,
+}
+
export interface CheckResetTokenResponse {
name: string;
}
@@ -25,6 +33,38 @@ export class AuthApi {
return sessionStorage.getItem(TokenStateKey)!;
}
+ /**
+ * Create a new account
+ */
+ static async CreateAccount(
+ name: string,
+ mail: string
+ ): Promise {
+ const res = await APIClient.exec({
+ uri: "/auth/create_account",
+ method: "POST",
+ allowFail: true,
+ jsonData: {
+ name: name,
+ email: mail,
+ },
+ });
+
+ switch (res.status) {
+ case 429:
+ return CreateAccountResult.TooManyRequests;
+ case 400:
+ return CreateAccountResult.BadInputData;
+ case 409:
+ return CreateAccountResult.MailAlreadyExists;
+ case 200:
+ case 201:
+ return CreateAccountResult.Success;
+ default:
+ return CreateAccountResult.Error;
+ }
+ }
+
/**
* Start OpenID login
*
diff --git a/geneit_app/src/routes/auth/LoginRoute.tsx b/geneit_app/src/routes/auth/LoginRoute.tsx
index 550dd03..d0730d9 100644
--- a/geneit_app/src/routes/auth/LoginRoute.tsx
+++ b/geneit_app/src/routes/auth/LoginRoute.tsx
@@ -100,9 +100,8 @@ export function LoginRoute(): React.ReactElement {
- {" "}
Créer un nouveau compte
diff --git a/geneit_app/src/routes/auth/NewAccountRoute.tsx b/geneit_app/src/routes/auth/NewAccountRoute.tsx
new file mode 100644
index 0000000..5a39176
--- /dev/null
+++ b/geneit_app/src/routes/auth/NewAccountRoute.tsx
@@ -0,0 +1,156 @@
+import {
+ Alert,
+ Box,
+ Button,
+ CircularProgress,
+ TextField,
+ Typography,
+} from "@mui/material";
+import React from "react";
+import { ServerApi } from "../../api/ServerApi";
+import { Link } from "react-router-dom";
+import { AuthSingleMessage } from "../../widgets/AuthSingleMessage";
+import { AuthApi, CreateAccountResult } from "../../api/AuthApi";
+
+export function NewAccountRoute(): React.ReactElement {
+ const [mail, setMail] = React.useState("");
+ const [name, setName] = React.useState("");
+
+ const [showErrors, setShowErrors] = React.useState(false);
+ const [loading, setLoading] = React.useState(false);
+ const [error, setError] = React.useState(null);
+ const [success, setSuccess] = React.useState(false);
+
+ const nameLen = ServerApi.Config.constraints.user_name_len;
+ const mailLen = ServerApi.Config.constraints.mail_len;
+
+ const mailValid = mail.length >= mailLen.min && mail.length <= mailLen.max;
+ const nameValid = name.length >= nameLen.min && name.length <= nameLen.max;
+ const canSubmit = mailValid && nameValid;
+
+ const handleSubmit = async (event: React.FormEvent) => {
+ event.preventDefault();
+ setShowErrors(true);
+ if (!canSubmit) return;
+ setLoading(true);
+ try {
+ const res = await AuthApi.CreateAccount(name, mail);
+ switch (res) {
+ case CreateAccountResult.Success:
+ setSuccess(true);
+ break;
+
+ case CreateAccountResult.TooManyRequests:
+ setError("Trop de tentatives. Veuillez réessayer ultérieurement.");
+ break;
+
+ case CreateAccountResult.MailAlreadyExists:
+ setError(
+ "Cette adresse mail est associée à un compte existant. Veuillez essayer de vous connecter ou de réinitialiser votre mot de passe."
+ );
+ break;
+
+ case CreateAccountResult.BadInputData:
+ setError("Les données saisies sont invalides !");
+ break;
+
+ case CreateAccountResult.Error:
+ setError("Une erreur a survenue lors de la création du compte !");
+ break;
+ }
+ } catch (e) {
+ console.error(e);
+ setError(
+ "Une erreur a survenue lors de la tentative de création de compte !"
+ );
+ }
+
+ setLoading(false);
+ };
+
+ if (loading)
+ return (
+ <>
+
+ >
+ );
+
+ if (success)
+ return (
+
+ );
+
+ return (
+ <>
+ {error && (
+
+ {error}
+
+ )}
+
+
+ Nouveau compte
+
+
+
+ setName(v.target.value)}
+ id="name"
+ label="Nom"
+ autoComplete="name"
+ autoFocus
+ inputProps={{
+ maxLength: nameLen.max,
+ }}
+ helperText={`Saisissez votre nom (entre ${nameLen.min} et ${nameLen.max} caractères)`}
+ />
+ setMail(v.target.value)}
+ label="Adresse mail"
+ autoComplete="email"
+ autoFocus
+ inputProps={{ maxLength: mailLen.max }}
+ helperText={`Saisissez votre adresse mail (entre ${mailLen.min} et ${mailLen.max} caractères)`}
+ />
+
+
+
+
+
+
+ Retour au formulaire de connexion
+
+
+ >
+ );
+}
diff --git a/geneit_backend/src/controllers/auth_controller.rs b/geneit_backend/src/controllers/auth_controller.rs
index 804d436..155a4de 100644
--- a/geneit_backend/src/controllers/auth_controller.rs
+++ b/geneit_backend/src/controllers/auth_controller.rs
@@ -19,7 +19,6 @@ pub async fn create_account(remote_ip: RemoteIP, req: web::Json HttpResult {
if !user.active {
log::error!("Auth failed: account for mail {} is disabled!", user.email);
- return Ok(HttpResponse::ExpectationFailed().json("Ce compte est désactivé !"));
+ return Ok(HttpResponse::ExpectationFailed().json("This account is disabled!"));
}
Ok(HttpResponse::Ok().json(LoginResponse {
@@ -271,16 +272,13 @@ pub async fn finish_openid_login(
if user_info.email_verified != Some(true) {
log::error!("Email is not verified!");
- return Ok(
- HttpResponse::Unauthorized().json("Email non vérifié par le fournisseur d'identité !")
- );
+ return Ok(HttpResponse::Unauthorized().json("Email unverified by IDP!"));
}
let mail = match user_info.email {
Some(m) => m,
None => {
- return Ok(HttpResponse::Unauthorized()
- .json("Email non spécifié par le fournisseur d'identité !"));
+ return Ok(HttpResponse::Unauthorized().json("Email not provided by the IDP!"));
}
};
@@ -290,8 +288,7 @@ pub async fn finish_openid_login(
(Some(name), _, _) => name,
(None, Some(g), Some(f)) => format!("{g} {f}"),
(_, _, _) => {
- return Ok(HttpResponse::Unauthorized()
- .json("Nom non spécifié par le fournisseur d'identité !"));
+ return Ok(HttpResponse::Unauthorized().json("Name unspecified by the IDP!"));
}
};