From de9b26df2d6849e18ffd8adbf8341a71ebf123bd Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Tue, 15 Oct 2019 18:13:05 +0200 Subject: [PATCH] Translate them and handle difference between user not found and user not confirmed Closes #212 Signed-off-by: Thomas Citharel --- js/package.json | 1 + js/src/i18n/en_US.json | 5 +++ js/src/i18n/fr_FR.json | 5 +++ js/src/i18n/oc.json | 2 +- js/src/types/login-error-code.model.ts | 6 ++++ js/src/utils/errors.ts | 10 +++--- js/src/views/User/Login.vue | 21 +++++++++--- js/tests/e2e/specs/login.js | 4 +-- lib/mobilizon_web/resolvers/person.ex | 2 +- lib/mobilizon_web/resolvers/user.ex | 7 ++-- .../resolvers/user_resolver_test.exs | 32 +++++++++++++++++-- 11 files changed, 78 insertions(+), 17 deletions(-) diff --git a/js/package.json b/js/package.json index 7cb86ae3a..ebfc18572 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,7 @@ { "name": "mobilizon", "version": "1.0.0-beta.1", + "license": "AGPL-3.0", "private": true, "scripts": { "build": "vue-cli-service build", diff --git a/js/src/i18n/en_US.json b/js/src/i18n/en_US.json index 7f6846f41..a1a90980d 100644 --- a/js/src/i18n/en_US.json +++ b/js/src/i18n/en_US.json @@ -125,6 +125,7 @@ "Identity {displayName} updated": "Identity {displayName} updated", "If an account with this email exists, we just sent another confirmation email to {email}": "If an account with this email exists, we just sent another confirmation email to {email}", "If this identity is the only administrator of some groups, you need to delete them before being able to delete this identity.": "If this identity is the only administrator of some groups, you need to delete them before being able to delete this identity.", + "Impossible to login, your email or password seems incorrect.": "Impossible to login, your email or password seems incorrect.", "In the meantime, please consider that the software is not (yet) finished. More information {onBlog}.": "In the meantime, please consider that the software is not (yet) finished. More information {onBlog}.", "Installing Mobilizon will allow communities to free themselves from the services of tech giants by creating their own event platform.": "Installing Mobilizon will allow communities to free themselves from the services of tech giants by creating their own event platform.", "Join {instance}, a Mobilizon instance": "Join {instance}, a Mobilizon instance", @@ -160,6 +161,7 @@ "No group found": "No group found", "No groups found": "No groups found", "No results for \"{queryText}\"": "No results for \"{queryText}\"", + "No user account with this email was found. Maybe you made a typo?": "No user account with this email was found. Maybe you made a typo?", "Number of places": "Number of places", "OK": "OK", "Old password": "Old password", @@ -251,6 +253,7 @@ "The page you're looking for doesn't exist.": "The page you're looking for doesn't exist.", "The password was successfully changed": "The password was successfully changed", "The report will be sent to the moderators of your instance. You can explain why you report this content below.": "The report will be sent to the moderators of your instance. You can explain why you report this content below.", + "The user account you're trying to login as has not been confirmed yet. Check your email inbox and eventually your spam folder.": "The user account you're trying to login as has not been confirmed yet. Check your email inbox and eventually your spam folder.", "There are {participants} participants.": "There are {participants} participants.", "These events may interest you": "These events may interest you", "This installation (called “instance“) can easily {interconnect}, thanks to {protocol}.": "This installation (called “instance“) can easily {interconnect}, thanks to {protocol}.", @@ -297,6 +300,7 @@ "You have one event in {days} days.": "You have no events in {days} days | You have one event in {days} days. | You have {count} events in {days} days", "You have one event today.": "You have no events today | You have one event today. | You have {count} events today", "You have one event tomorrow.": "You have no events tomorrow | You have one event tomorrow. | You have {count} events tomorrow", + "You may also ask to {resend_confirmation_email}.": "You may also ask to {resend_confirmation_email}.", "You need to login.": "You need to login.", "Your account has been validated": "Your account has been validated", "Your account is being validated": "Your account is being validated", @@ -311,6 +315,7 @@ "interconnect with others like it": "interconnect with others like it", "its source code is public": "its source code is public", "on our blog": "on our blog", + "resend confirmation email": "resend confirmation email", "respect of the fundamental freedoms": "respect of the fundamental freedoms", "with another identity…": "with another identity…", "with {identity}": "with {identity}", diff --git a/js/src/i18n/fr_FR.json b/js/src/i18n/fr_FR.json index 7d6c347a3..5b41689d4 100644 --- a/js/src/i18n/fr_FR.json +++ b/js/src/i18n/fr_FR.json @@ -125,6 +125,7 @@ "Identity {displayName} updated": "Identité {displayName} mise à jour", "If an account with this email exists, we just sent another confirmation email to {email}": "Si un compte avec un tel email existe, nous venons juste d'envoyer un nouvel email de confirmation à {email}", "If this identity is the only administrator of some groups, you need to delete them before being able to delete this identity.": "Si cette identité est la seule administratrice de certains groupes, vous devez les supprimer avant de pouvoir supprimer cette identité.", + "Impossible to login, your email or password seems incorrect.": "Impossible de se connecter, votre email ou bien votre mot de passe semble incorrect.", "In the meantime, please consider that the software is not (yet) finished. More information {onBlog}.": "D'ici là, veuillez considérer que le logiciel n'est pas (encore) fini. Plus d'informations {onBlog}.", "Installing Mobilizon will allow communities to free themselves from the services of tech giants by creating their own event platform.": "Installer Mobilizon permettra à des collectifs de s’émanciper des outils des géants du web en créant leur propre plateforme d’événements.", "Join {instance}, a Mobilizon instance": "Rejoignez {instance}, une instance Mobilizon", @@ -160,6 +161,7 @@ "No group found": "Aucun groupe trouvé", "No groups found": "Aucun groupe trouvé", "No results for \"{queryText}\"": "Pas de résultats pour « {queryText} »", + "No user account with this email was found. Maybe you made a typo?": "Aucun compte utilisateur trouvé pour cet email. Peut-être avez-vous fait une faute de frappe ?", "Number of places": "Nombre de places", "OK": "OK", "Old password": "Ancien mot de passe", @@ -251,6 +253,7 @@ "The page you're looking for doesn't exist.": "La page que vous recherchez n'existe pas.", "The password was successfully changed": "Le mot de passe a été changé avec succès", "The report will be sent to the moderators of your instance. You can explain why you report this content below.": "Le signalement sera envoyé aux modérateur⋅ices de votre instance. Vous pouvez expliquer pourquoi vous signalez ce contenu ci-dessous.", + "The user account you're trying to login as has not been confirmed yet. Check your email inbox and eventually your spam folder.": "Le compte utilisateur avec lequel vous essayez de vous connectez n'a pas été confirmé. Vérifiez la boite de réception de votre adresse email et éventuellement le dossier des messages indésirables.", "There are {participants} participants.": "Il n'y a qu'un⋅e participant⋅e. | Il y a {participants} participants.", "These events may interest you": "Ces événements peuvent vous intéresser", "This installation (called “instance“) can easily {interconnect}, thanks to {protocol}.": "Cette installation (appelée “instance“) peut facilement {interconnect}, grâce à {protocol}.", @@ -297,6 +300,7 @@ "You have one event in {days} days.": "Vous n'avez pas d'événements dans {days} jours | Vous avez un événement dans {days} jours. | Vous avez {count} événements dans {days} jours", "You have one event today.": "Vous n'avez pas d'évenement aujourd'hui | Vous avez un événement aujourd'hui. | Vous avez {count} événements aujourd'hui", "You have one event tomorrow.": "Vous n'avez pas d'événement demain | Vous avez un événement demain. | Vous avez {count} événements demain", + "You may also ask to {resend_confirmation_email}.": "Vous pouvez aussi demander à {resend_confirmation_email}.", "You need to login.": "Vous devez vous connecter.", "Your account has been validated": "Votre compte a été validé", "Your account is being validated": "Votre compte est en cours de validation", @@ -311,6 +315,7 @@ "interconnect with others like it": "s’interconnecter simplement avec d’autres", "its source code is public": "son code source est public", "on our blog": "sur notre blog", + "resend confirmation email": "réenvoyer l'email de confirmation", "respect of the fundamental freedoms": "le respect des libertés fondamentales", "with another identity…": "avec une autre identité…", "with {identity}": "avec {identity}", diff --git a/js/src/i18n/oc.json b/js/src/i18n/oc.json index 933065bfd..b3e8773cb 100644 --- a/js/src/i18n/oc.json +++ b/js/src/i18n/oc.json @@ -117,7 +117,7 @@ "About this event": "Tocant aqueste eveniment", "© The Mobilizon Contributors {date} - Made with Elixir, Phoenix, VueJS & with some love and some weeks": "© Loscontribuidors de Mobilizon {date} - Fach amb Elixir, Phoenix, VueJS e d’amor e de setmanas", "{count} requests waiting": "Una demanda en espèra|{count} demandas en espèra", - "{count} participants": "Aucun participant|Un participant|{count} participants", + "{count} participants": "Cap de participacion pel moment|Un participant|{count} participants", "{approved} / {total} seats": "{approved} / {total} plaças", "You need to login.": "Vos cal vos connectar.", "You are an organizer.": "Sètz un organizaire.", diff --git a/js/src/types/login-error-code.model.ts b/js/src/types/login-error-code.model.ts index 781c1e2ec..dae8a2080 100644 --- a/js/src/types/login-error-code.model.ts +++ b/js/src/types/login-error-code.model.ts @@ -1,3 +1,9 @@ export enum LoginErrorCode { NEED_TO_LOGIN = 'rouge', } + +export enum LoginError { + USER_NOT_CONFIRMED = 'User account not confirmed', + USER_DOES_NOT_EXIST = 'No user with this email was found', + USER_EMAIL_PASSWORD_INVALID = 'Impossible to authenticate, either your email or password are invalid.', +} diff --git a/js/src/utils/errors.ts b/js/src/utils/errors.ts index ff3f6652a..1fd723b3b 100644 --- a/js/src/utils/errors.ts +++ b/js/src/utils/errors.ts @@ -49,17 +49,13 @@ export const errors: IError[] = [ suggestRefresh: false, }, { - match: /^User with email not found$/, + match: /^No user with this email was found$/, value: null, }, { match: /^Username is already taken$/, value: null, }, - { - match: /^No user with this email was found$/, - value: null, - }, { match: /^Impossible to authenticate, either your email or password are invalid.$/, value: null, @@ -72,4 +68,8 @@ export const errors: IError[] = [ match: /^This email is already used.$/, value: null, }, + { + match: /^User account not confirmed$/, + value: null, + }, ]; diff --git a/js/src/views/User/Login.vue b/js/src/views/User/Login.vue index c7284928a..6a3dac43d 100644 --- a/js/src/views/User/Login.vue +++ b/js/src/views/User/Login.vue @@ -3,14 +3,27 @@ {{ $t('You need to login.') }} -

{{ $t('Welcome back!') }}

- {{ error }} + + + {{ $t("The user account you're trying to login as has not been confirmed yet. Check your email inbox and eventually your spam folder.") }} + + {{ $t('resend confirmation email') }} + + + + {{ $t('Impossible to login, your email or password seems incorrect.') }} + + + + {{ $t('No user account with this email was found. Maybe you made a typo?') }} + +
@@ -67,7 +80,7 @@ import { ILogin } from '@/types/login.model'; import { CURRENT_USER_CLIENT, UPDATE_CURRENT_USER_CLIENT } from '@/graphql/user'; import { onLogin } from '@/vue-apollo'; import { RouteName } from '@/router'; -import { LoginErrorCode } from '@/types/login-error-code.model'; +import { LoginErrorCode, LoginError } from '@/types/login-error-code.model'; import { ICurrentUser } from '@/types/current-user.model'; import { CONFIG } from '@/graphql/config'; import { IConfig } from '@/types/config.model'; @@ -95,6 +108,7 @@ export default class Login extends Vue { @Prop({ type: String, required: false, default: '' }) password!: string; LoginErrorCode = LoginErrorCode; + LoginError = LoginError; errorCode: LoginErrorCode | null = null; config!: IConfig; @@ -106,7 +120,6 @@ export default class Login extends Vue { email: '', password: '', }; - validationSent = false; errors: string[] = []; rules = { diff --git a/js/tests/e2e/specs/login.js b/js/tests/e2e/specs/login.js index d55b6eb90..3f5fece19 100644 --- a/js/tests/e2e/specs/login.js +++ b/js/tests/e2e/specs/login.js @@ -37,7 +37,7 @@ describe('Login', () => { cy.get('input[type=password]').type('badPassword').should('have.value', 'badPassword'); cy.contains('button.button.is-primary.is-large', 'Login').click(); - cy.contains('.message.is-danger', 'User with email not found'); + cy.contains('.message.is-danger', 'No user account with this email was found. Maybe you made a typo?'); }); it('Tries to login with valid credentials', () => { @@ -56,7 +56,7 @@ describe('Login', () => { cy.get('input[type=email]').type('unconfirmed@email.com'); cy.get('input[type=password]').type('some password'); cy.get('form').submit(); - cy.contains('.message.is-danger', 'User with email not found'); + cy.contains('.message.is-danger', 'The user account you\'re trying to login as has not been confirmed yet. Check your email inbox and eventually your spam folder.You may also ask to resend confirmation email.'); }); it('Tries to login with valid credentials, confirmed account but no profile', () => { diff --git a/lib/mobilizon_web/resolvers/person.ex b/lib/mobilizon_web/resolvers/person.ex index 1dc9ce07c..bf5ae40e2 100644 --- a/lib/mobilizon_web/resolvers/person.ex +++ b/lib/mobilizon_web/resolvers/person.ex @@ -177,7 +177,7 @@ defmodule MobilizonWeb.Resolvers.Person do {:ok, new_person} else {:error, :user_not_found} -> - {:error, "User with email not found"} + {:error, "No user with this email was found"} {:no_actor, _} -> {:error, "You already have a profile for this user"} diff --git a/lib/mobilizon_web/resolvers/user.ex b/lib/mobilizon_web/resolvers/user.ex index 487ab2724..b6f9bec26 100644 --- a/lib/mobilizon_web/resolvers/user.ex +++ b/lib/mobilizon_web/resolvers/user.ex @@ -67,13 +67,16 @@ defmodule MobilizonWeb.Resolvers.User do Login an user. Returns a token and the user """ def login_user(_parent, %{email: email, password: password}, _resolution) do - with {:ok, %User{} = user} <- Users.get_user_by_email(email, true), + with {:ok, %User{confirmed_at: %DateTime{}} = user} <- Users.get_user_by_email(email), {:ok, %{access_token: access_token, refresh_token: refresh_token}} <- Users.authenticate(%{user: user, password: password}) do {:ok, %{access_token: access_token, refresh_token: refresh_token, user: user}} else + {:ok, %User{confirmed_at: nil} = _user} -> + {:error, "User account not confirmed"} + {:error, :user_not_found} -> - {:error, "User with email not found"} + {:error, "No user with this email was found"} {:error, :unauthorized} -> {:error, "Impossible to authenticate, either your email or password are invalid."} diff --git a/test/mobilizon_web/resolvers/user_resolver_test.exs b/test/mobilizon_web/resolvers/user_resolver_test.exs index c8418df0b..b35ec9d97 100644 --- a/test/mobilizon_web/resolvers/user_resolver_test.exs +++ b/test/mobilizon_web/resolvers/user_resolver_test.exs @@ -359,7 +359,8 @@ defmodule MobilizonWeb.Resolvers.UserResolverTest do context.conn |> post("/api", AbsintheHelpers.mutation_skeleton(mutation)) - assert hd(json_response(res, 200)["errors"])["message"] == "User with email not found" + assert hd(json_response(res, 200)["errors"])["message"] == + "No user with this email was found" end test "register_person/3 can't be called with an existing profile", context do @@ -780,7 +781,34 @@ defmodule MobilizonWeb.Resolvers.UserResolverTest do context.conn |> post("/api", AbsintheHelpers.mutation_skeleton(mutation)) - assert hd(json_response(res, 200)["errors"])["message"] == "User with email not found" + assert hd(json_response(res, 200)["errors"])["message"] == + "No user with this email was found" + end + + test "test login_user/3 with unconfirmed user", context do + {:ok, %User{} = user} = Users.register(%{email: "toto@tata.tld", password: "p4ssw0rd"}) + + mutation = """ + mutation { + login( + email: "#{user.email}", + password: "#{user.password}", + ) { + accessToken, + user { + default_actor { + preferred_username, + } + } + } + } + """ + + res = + context.conn + |> post("/api", AbsintheHelpers.mutation_skeleton(mutation)) + + assert hd(json_response(res, 200)["errors"])["message"] == "User account not confirmed" end end