Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel 2020-10-08 15:54:43 +02:00
parent c229c4a806
commit a8d6e28ee9
No known key found for this signature in database
GPG Key ID: A061B9DDE0CA0773
10 changed files with 336 additions and 109 deletions

View File

@ -34,6 +34,10 @@ config :mobilizon, :groups, enabled: true
config :mobilizon, :events, creation: true config :mobilizon, :events, creation: true
config :mobilizon, :demo_mode,
email: "demo@mobilizon.org",
password: "mobilizon"
# Configures the endpoint # Configures the endpoint
config :mobilizon, Mobilizon.Web.Endpoint, config :mobilizon, Mobilizon.Web.Endpoint,
http: [ http: [

View File

@ -2,41 +2,14 @@
<div id="mobilizon"> <div id="mobilizon">
<NavBar /> <NavBar />
<div class="container" v-if="config && config.demoMode"> <div class="container" v-if="config && config.demoMode">
<b-message <b-message type="is-info" :title="$t('Demo mode')" closable aria-close-label="Close">
type="is-danger"
:title="$t('Warning').toLocaleUpperCase()"
closable
aria-close-label="Close"
>
<p <p
v-html=" v-html="
`${$t('This is a demonstration site to test the beta version of Mobilizon.')} ${$t( `${$t('This is a demonstration website to test Mobilizon.')} ${$t(
'<b>Please do not use it in any real way.</b>' '<b>Please do not use it in any real way.</b>'
)}` )} ${$t('Data is deleted every 7 days.')}`
" "
/> />
<p>
<span
v-html="
$t(
'Mobilizon is under development, we will add new features to this site during regular updates, until the release of <b>version 1 of the software in the fall of 2020</b>.'
)
"
/>
<i18n
path="In the meantime, please consider that the software is not (yet) finished. More information {onBlog}."
>
<a
slot="onBlog"
:href="
$i18n.locale === 'fr'
? 'https://framablog.org/?p=18268'
: 'https://framablog.org/?p=18299'
"
>{{ $t("on our blog") }}</a
>
</i18n>
</p>
</b-message> </b-message>
</div> </div>
<main> <main>

View File

@ -169,7 +169,6 @@
"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 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.", "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.",
"If you want, you may send a message to the event organizer here.": "If you want, you may send a message to the event organizer here.", "If you want, you may send a message to the event organizer here.": "If you want, you may send a message to the event organizer here.",
"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 <b>their own event platform</b>.": "Installing Mobilizon will allow communities to free themselves from the services of tech giants by creating <b>their own event platform</b>.", "Installing Mobilizon will allow communities to free themselves from the services of tech giants by creating <b>their own event platform</b>.": "Installing Mobilizon will allow communities to free themselves from the services of tech giants by creating <b>their own event platform</b>.",
"Instance Name": "Instance Name", "Instance Name": "Instance Name",
"Instance Terms Source": "Instance Terms Source", "Instance Terms Source": "Instance Terms Source",
@ -355,7 +354,6 @@
"This Mobilizon instance and this event organizer allows anonymous participations, but requires validation through email confirmation.": "This Mobilizon instance and this event organizer allows anonymous participations, but requires validation through email confirmation.", "This Mobilizon instance and this event organizer allows anonymous participations, but requires validation through email confirmation.": "This Mobilizon instance and this event organizer allows anonymous participations, but requires validation through email confirmation.",
"This information is saved only on your computer. Click for details": "This information is saved only on your computer. Click for details", "This information is saved only on your computer. Click for details": "This information is saved only on your computer. Click for details",
"This instance isn't opened to registrations, but you can register on other instances.": "This instance isn't opened to registrations, but you can register on other instances.", "This instance isn't opened to registrations, but you can register on other instances.": "This instance isn't opened to registrations, but you can register on other instances.",
"This is a demonstration site to test the beta version of Mobilizon.": "This is a demonstration site to test the beta version of Mobilizon.",
"This will delete / anonymize all content (events, comments, messages, participations…) created from this identity.": "This will delete / anonymize all content (events, comments, messages, participations…) created from this identity.", "This will delete / anonymize all content (events, comments, messages, participations…) created from this identity.": "This will delete / anonymize all content (events, comments, messages, participations…) created from this identity.",
"Title": "Title", "Title": "Title",
"To change the world, change the software": "To change the world, change the software", "To change the world, change the software": "To change the world, change the software",
@ -383,7 +381,6 @@
"View page on {hostname} (in a new window)": "View page on {hostname} (in a new window)", "View page on {hostname} (in a new window)": "View page on {hostname} (in a new window)",
"Visible everywhere on the web (public)": "Visible everywhere on the web (public)", "Visible everywhere on the web (public)": "Visible everywhere on the web (public)",
"Waiting for organization team approval.": "Waiting for organization team approval.", "Waiting for organization team approval.": "Waiting for organization team approval.",
"Warning": "Warning",
"We just sent an email to {email}": "We just sent an email to {email}", "We just sent an email to {email}": "We just sent an email to {email}",
"We will redirect you to your instance in order to interact with this event": "We will redirect you to your instance in order to interact with this event", "We will redirect you to your instance in order to interact with this event": "We will redirect you to your instance in order to interact with this event",
"Website / URL": "Website / URL", "Website / URL": "Website / URL",
@ -432,7 +429,6 @@
"iCal Feed": "iCal Feed", "iCal Feed": "iCal Feed",
"interconnect with others like it": "interconnect with others like it", "interconnect with others like it": "interconnect with others like it",
"its source code is public": "its source code is public", "its source code is public": "its source code is public",
"on our blog": "on our blog",
"profile@instance": "profile@instance", "profile@instance": "profile@instance",
"respect of the fundamental freedoms": "respect of the fundamental freedoms", "respect of the fundamental freedoms": "respect of the fundamental freedoms",
"with another identity…": "with another identity…", "with another identity…": "with another identity…",
@ -536,7 +532,6 @@
"Register on this instance": "Register on this instance", "Register on this instance": "Register on this instance",
"Mobilizon is not developed by a secretive start-up, but by a group of friends who strive to {change_world}. So while we do work slower, we remain attentive and in touch with our users.": "Mobilizon is not developed by a secretive start-up, but by a group of friends who strive to {change_world}. So while we do work slower, we remain attentive and in touch with our users.", "Mobilizon is not developed by a secretive start-up, but by a group of friends who strive to {change_world}. So while we do work slower, we remain attentive and in touch with our users.": "Mobilizon is not developed by a secretive start-up, but by a group of friends who strive to {change_world}. So while we do work slower, we remain attentive and in touch with our users.",
"fit the needs and uses of the people": "fit the needs and uses of the people", "fit the needs and uses of the people": "fit the needs and uses of the people",
"Mobilizon is under development, we will add new features to this site during regular updates, until the release of <b>version 1 of the software in the fall of 2020</b>.": "Mobilizon is under development, we will add new features to this site during regular updates, until the release of <b>version 1 of the software in the fall of 2020</b>.",
"To activate more notifications, head over to the notification settings.": "To activate more notifications, head over to the notification settings.", "To activate more notifications, head over to the notification settings.": "To activate more notifications, head over to the notification settings.",
"Manage my notifications": "Manage my notifications", "Manage my notifications": "Manage my notifications",
"We use your timezone to make sure you get notifications for an event at the correct time.": "We use your timezone to make sure you get notifications for an event at the correct time.", "We use your timezone to make sure you get notifications for an event at the correct time.": "We use your timezone to make sure you get notifications for an event at the correct time.",
@ -798,5 +793,8 @@
"Go to the event page": "Go to the event page", "Go to the event page": "Go to the event page",
"Request for participation confirmation sent": "Request for participation confirmation sent", "Request for participation confirmation sent": "Request for participation confirmation sent",
"Check your inbox (and your junk mail folder).": "Check your inbox (and your junk mail folder).", "Check your inbox (and your junk mail folder).": "Check your inbox (and your junk mail folder).",
"You may now close this window.": "You may now close this window." "You may now close this window.": "You may now close this window.",
"Demo mode": "Demo mode",
"This is a demonstration website to test Mobilizon.": "This is a demonstration website to test Mobilizon.",
"Close notification": "Close notification"
} }

View File

@ -841,5 +841,8 @@
"Go to the event page": "Aller à la page de l'événement", "Go to the event page": "Aller à la page de l'événement",
"Request for participation confirmation sent": "Demande de confirmation de participation envoyée", "Request for participation confirmation sent": "Demande de confirmation de participation envoyée",
"Check your inbox (and your junk mail folder).": "Vérifiez votre boîte de réception (et votre dossier des indésirables)", "Check your inbox (and your junk mail folder).": "Vérifiez votre boîte de réception (et votre dossier des indésirables)",
"You may now close this window.": "Vous pouvez maintenant fermer cette fenêtre." "You may now close this window.": "Vous pouvez maintenant fermer cette fenêtre.",
"Demo mode": "Mode de démonstration",
"This is a demonstration website to test Mobilizon.": "Ceci est un site de démonstration pour tester Mobilizon.",
"Close notification": "Fermer la notification"
} }

View File

@ -68,7 +68,7 @@
<b-notification <b-notification
type="is-danger" type="is-danger"
has-icon has-icon
aria-close-label="Close notification" :aria-close-label="$t('Close notification')"
role="alert" role="alert"
:key="error" :key="error"
v-for="error in errors" v-for="error in errors"

View File

@ -1,5 +1,5 @@
<template> <template>
<div v-if="loggedUser"> <div v-if="loggedUser && config">
<nav class="breadcrumb" aria-label="breadcrumbs"> <nav class="breadcrumb" aria-label="breadcrumbs">
<ul> <ul>
<li> <li>
@ -13,6 +13,9 @@
</ul> </ul>
</nav> </nav>
<section> <section>
<b-message v-if="config.demoMode" type="is-info">
{{ $t("You can't change these settings in demo mode.") }}
</b-message>
<div class="setting-title"> <div class="setting-title">
<h2>{{ $t("Email") }}</h2> <h2>{{ $t("Email") }}</h2>
</div> </div>
@ -34,7 +37,7 @@
<b-notification <b-notification
type="is-danger" type="is-danger"
has-icon has-icon
aria-close-label="Close notification" :aria-close-label="$t('Close notification')"
role="alert" role="alert"
:key="error" :key="error"
v-for="error in changeEmailErrors" v-for="error in changeEmailErrors"
@ -42,12 +45,19 @@
> >
<form @submit.prevent="resetEmailAction" ref="emailForm" class="form" v-if="canChangeEmail"> <form @submit.prevent="resetEmailAction" ref="emailForm" class="form" v-if="canChangeEmail">
<b-field :label="$t('New email')"> <b-field :label="$t('New email')">
<b-input aria-required="true" required type="email" v-model="newEmail" /> <b-input
:disabled="config.demoMode"
aria-required="true"
required
type="email"
v-model="newEmail"
/>
</b-field> </b-field>
<p class="help">{{ $t("You'll receive a confirmation email.") }}</p> <p class="help">{{ $t("You'll receive a confirmation email.") }}</p>
<b-field :label="$t('Password')"> <b-field :label="$t('Password')">
<b-input <b-input
aria-required="true" aria-required="true"
:disabled="config.demoMode"
required required
type="password" type="password"
password-reveal password-reveal
@ -75,7 +85,7 @@
<b-notification <b-notification
type="is-danger" type="is-danger"
has-icon has-icon
aria-close-label="Close notification" :aria-close-label="$t('Close notification')"
role="alert" role="alert"
:key="error" :key="error"
v-for="error in changePasswordErrors" v-for="error in changePasswordErrors"
@ -91,6 +101,7 @@
<b-input <b-input
aria-required="true" aria-required="true"
required required
:disabled="config.demoMode"
type="password" type="password"
password-reveal password-reveal
minlength="6" minlength="6"
@ -101,6 +112,7 @@
<b-input <b-input
aria-required="true" aria-required="true"
required required
:disabled="config.demoMode"
type="password" type="password"
password-reveal password-reveal
minlength="6" minlength="6"
@ -118,7 +130,7 @@
<h2>{{ $t("Delete account") }}</h2> <h2>{{ $t("Delete account") }}</h2>
</div> </div>
<p class="content">{{ $t("Deleting my account will delete all of my identities.") }}</p> <p class="content">{{ $t("Deleting my account will delete all of my identities.") }}</p>
<b-button @click="openDeleteAccountModal" type="is-danger"> <b-button :disabled="config.demoMode" @click="openDeleteAccountModal" type="is-danger">
{{ $t("Delete my account") }} {{ $t("Delete my account") }}
</b-button> </b-button>
@ -156,6 +168,15 @@
:placeholder="$t('Password')" :placeholder="$t('Password')"
/> />
</b-field> </b-field>
<b-notification
type="is-danger"
has-icon
:aria-close-label="$t('Close notification')"
role="alert"
:key="error"
v-for="error in deleteAccountErrors"
>{{ error }}</b-notification
>
<b-button native-type="submit" type="is-danger" size="is-large"> <b-button native-type="submit" type="is-danger" size="is-large">
{{ $t("Delete everything") }} {{ $t("Delete everything") }}
</b-button> </b-button>
@ -176,6 +197,8 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { CONFIG } from "@/graphql/config";
import { IConfig } from "@/types/config.model";
import { Component, Vue, Ref } from "vue-property-decorator"; import { Component, Vue, Ref } from "vue-property-decorator";
import { Route } from "vue-router"; import { Route } from "vue-router";
import { CHANGE_EMAIL, CHANGE_PASSWORD, DELETE_ACCOUNT, LOGGED_USER } from "../../graphql/user"; import { CHANGE_EMAIL, CHANGE_PASSWORD, DELETE_ACCOUNT, LOGGED_USER } from "../../graphql/user";
@ -186,6 +209,7 @@ import { logout, SELECTED_PROVIDERS } from "../../utils/auth";
@Component({ @Component({
apollo: { apollo: {
loggedUser: LOGGED_USER, loggedUser: LOGGED_USER,
config: CONFIG,
}, },
}) })
export default class AccountSettings extends Vue { export default class AccountSettings extends Vue {
@ -193,6 +217,8 @@ export default class AccountSettings extends Vue {
loggedUser!: IUser; loggedUser!: IUser;
config!: IConfig;
passwordForEmailChange = ""; passwordForEmailChange = "";
newEmail = ""; newEmail = "";
@ -211,6 +237,8 @@ export default class AccountSettings extends Vue {
RouteName = RouteName; RouteName = RouteName;
deleteAccountErrors: string[] = [];
async resetEmailAction(): Promise<void> { async resetEmailAction(): Promise<void> {
this.changeEmailErrors = []; this.changeEmailErrors = [];
@ -259,6 +287,7 @@ export default class AccountSettings extends Vue {
} }
async deleteAccount(): Promise<Route | void> { async deleteAccount(): Promise<Route | void> {
this.deleteAccountErrors = [];
try { try {
await this.$apollo.mutate({ await this.$apollo.mutate({
mutation: DELETE_ACCOUNT, mutation: DELETE_ACCOUNT,
@ -308,6 +337,9 @@ export default class AccountSettings extends Vue {
if (err.graphQLErrors !== undefined) { if (err.graphQLErrors !== undefined) {
err.graphQLErrors.forEach(({ message }: { message: string }) => { err.graphQLErrors.forEach(({ message }: { message: string }) => {
switch (type) { switch (type) {
case "delete":
this.deleteAccountErrors.push(message);
break;
case "password": case "password":
this.changePasswordErrors.push(message); this.changePasswordErrors.push(message);
break; break;

View File

@ -203,7 +203,8 @@ defmodule Mobilizon.GraphQL.Resolvers.User do
Send an email to reset the password from an user Send an email to reset the password from an user
""" """
def send_reset_password(_parent, args, _resolution) do def send_reset_password(_parent, args, _resolution) do
with email <- Map.get(args, :email), with {:demo, false} <- {:demo, Config.instance_demo_mode?()},
email <- Map.get(args, :email),
{:ok, %User{locale: locale} = user} <- Users.get_user_by_email(email, true), {:ok, %User{locale: locale} = user} <- Users.get_user_by_email(email, true),
{:can_reset_password, true} <- {:can_reset_password, true} <-
{:can_reset_password, Authenticator.can_reset_password?(user)}, {:can_reset_password, Authenticator.can_reset_password?(user)},
@ -211,6 +212,9 @@ defmodule Mobilizon.GraphQL.Resolvers.User do
Email.User.send_password_reset_email(user, Map.get(args, :locale, locale)) do Email.User.send_password_reset_email(user, Map.get(args, :locale, locale)) do
{:ok, email} {:ok, email}
else else
{:demo, true} ->
{:error, dgettext("errors", "You can't reset your password in demo mode")}
{:can_reset_password, false} -> {:can_reset_password, false} ->
{:error, dgettext("errors", "This user can't reset their password")} {:error, dgettext("errors", "This user can't reset their password")}
@ -315,7 +319,8 @@ defmodule Mobilizon.GraphQL.Resolvers.User do
%{old_password: old_password, new_password: new_password}, %{old_password: old_password, new_password: new_password},
%{context: %{current_user: %User{} = user}} %{context: %{current_user: %User{} = user}}
) do ) do
with {:can_change_password, true} <- with {:demo, false} <- {:demo, Config.instance_demo_mode?()},
{:can_change_password, true} <-
{:can_change_password, Authenticator.can_change_password?(user)}, {:can_change_password, Authenticator.can_change_password?(user)},
{:current_password, {:ok, %User{}}} <- {:current_password, {:ok, %User{}}} <-
{:current_password, Authenticator.login(user.email, old_password)}, {:current_password, Authenticator.login(user.email, old_password)},
@ -326,6 +331,9 @@ defmodule Mobilizon.GraphQL.Resolvers.User do
|> Repo.update() do |> Repo.update() do
{:ok, user} {:ok, user}
else else
{:demo, true} ->
{:error, dgettext("errors", "You can't change your password in demo mode")}
{:current_password, _} -> {:current_password, _} ->
{:error, dgettext("errors", "The current password is invalid")} {:error, dgettext("errors", "The current password is invalid")}
@ -348,7 +356,8 @@ defmodule Mobilizon.GraphQL.Resolvers.User do
def change_email(_parent, %{email: new_email, password: password}, %{ def change_email(_parent, %{email: new_email, password: password}, %{
context: %{current_user: %User{email: old_email} = user} context: %{current_user: %User{email: old_email} = user}
}) do }) do
with {:can_change_password, true} <- with {:demo, false} <- {:demo, Config.instance_demo_mode?()},
{:can_change_password, true} <-
{:can_change_password, Authenticator.can_change_email?(user)}, {:can_change_password, Authenticator.can_change_email?(user)},
{:current_password, {:ok, %User{}}} <- {:current_password, {:ok, %User{}}} <-
{:current_password, Authenticator.login(user.email, password)}, {:current_password, Authenticator.login(user.email, password)},
@ -372,6 +381,9 @@ defmodule Mobilizon.GraphQL.Resolvers.User do
{:ok, user} {:ok, user}
else else
{:demo, true} ->
{:error, dgettext("errors", "You can't change your email in demo mode")}
{:current_password, _} -> {:current_password, _} ->
{:error, dgettext("errors", "The password provided is invalid")} {:error, dgettext("errors", "The password provided is invalid")}
@ -424,13 +436,17 @@ defmodule Mobilizon.GraphQL.Resolvers.User do
def delete_account(_parent, args, %{ def delete_account(_parent, args, %{
context: %{current_user: %User{email: email} = user} context: %{current_user: %User{email: email} = user}
}) do }) do
with {:user_has_password, true} <- {:user_has_password, Authenticator.has_password?(user)}, with {:demo, false} <- {:demo, Config.instance_demo_mode?()},
{:user_has_password, true} <- {:user_has_password, Authenticator.has_password?(user)},
{:confirmation_password, password} when not is_nil(password) <- {:confirmation_password, password} when not is_nil(password) <-
{:confirmation_password, Map.get(args, :password)}, {:confirmation_password, Map.get(args, :password)},
{:current_password, {:ok, _}} <- {:current_password, {:ok, _}} <-
{:current_password, Authenticator.authenticate(email, password)} do {:current_password, Authenticator.authenticate(email, password)} do
do_delete_account(user) do_delete_account(user)
else else
{:demo, true} ->
{:error, dgettext("errors", "You can't delete the demo account")}
# If the user hasn't got any password (3rd-party auth) # If the user hasn't got any password (3rd-party auth)
{:user_has_password, false} -> {:user_has_password, false} ->
do_delete_account(user) do_delete_account(user)

View File

@ -0,0 +1,90 @@
defmodule Mix.Tasks.Mobilizon.Demo do
@moduledoc """
Generates a new demo user, using the credentials
## Usage
``mix mobilizon.demo new``
"""
use Mix.Task
alias Mobilizon.{Actors, Users}
alias Mobilizon.Actors.Actor
alias Mobilizon.Users.User
@preferred_cli_env "prod"
@shortdoc "Creates a demo user"
def run(["new" | options]) do
{options, [], []} =
OptionParser.parse(
options,
strict: [
force: :boolean
],
aliases: [
f: :force
]
)
Mix.Task.run("app.start")
with {:demo_mode_enabled, true} <-
{:demo_mode_enabled, Application.get_env(:mobilizon, :instance)[:demo]},
:ok <- maybe_delete_current_demo_account(options),
[email: email, password: password] <- Application.get_env(:mobilizon, :demo_mode),
{:ok, %User{} = user} <-
Users.register(%{
email: email,
password: password,
role: :user,
confirmed_at: DateTime.utc_now(),
confirmation_sent_at: nil,
confirmation_token: nil
}),
{:ok, %Actor{preferred_username: preferred_username} = _new_person} <-
Actors.new_person(%{
user_id: user.id,
preferred_username: "demo",
name: "Demo",
summary: "I am a simple demo profile"
}) do
Mix.shell().info("""
An user has been created with the following information:
- email: #{user.email}
- password: #{password}
- username: #{preferred_username}
The user will be prompted to create a new profile after login for the first time.
""")
else
{:error, %Ecto.Changeset{errors: [email: _err]}} ->
Mix.raise(
"An user already exists with the following email address. Add -f if you want to recreate it."
)
{:error, %Ecto.Changeset{errors: errors}} ->
Mix.shell().error(inspect(errors))
Mix.raise("User has not been created because of the above reason.")
err ->
Mix.shell().error(inspect(err))
Mix.raise("User has not been created because of an unknown reason.")
end
end
defp maybe_delete_current_demo_account(options) do
with true <- Keyword.get(options, :force, false),
[email: email, password: _password] <- Application.get_env(:mobilizon, :demo_mode),
{:ok, %User{} = user} <- Users.get_user_by_email(email),
actors <- Users.get_actors_for_user(user),
:ok <- Enum.each(actors, &delete_profile/1) do
Users.delete_user(user, reserve_email: false)
end
:ok
end
defp delete_profile(actor) do
Actors.perform(:delete_actor, actor, reserve_username: false)
end
end

View File

@ -114,7 +114,7 @@ msgid "Current profile is not an administrator of the selected group"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/graphql/resolvers/user.ex:514 #: lib/graphql/resolvers/user.ex:530
msgid "Error while saving user settings" msgid "Error while saving user settings"
msgstr "" msgstr ""
@ -146,7 +146,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/graphql/resolvers/actor.ex:58 lib/graphql/resolvers/actor.ex:88 #: lib/graphql/resolvers/actor.ex:58 lib/graphql/resolvers/actor.ex:88
#: lib/graphql/resolvers/user.ex:417 #: lib/graphql/resolvers/user.ex:429
msgid "No profile found for the moderator user" msgid "No profile found for the moderator user"
msgstr "" msgstr ""
@ -157,7 +157,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/graphql/resolvers/person.ex:232 lib/graphql/resolvers/user.ex:76 #: lib/graphql/resolvers/person.ex:232 lib/graphql/resolvers/user.ex:76
#: lib/graphql/resolvers/user.ex:219 #: lib/graphql/resolvers/user.ex:223
msgid "No user with this email was found" msgid "No user with this email was found"
msgstr "" msgstr ""
@ -178,38 +178,38 @@ msgid "Registrations are not open"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/graphql/resolvers/user.ex:330 #: lib/graphql/resolvers/user.ex:338
msgid "The current password is invalid" msgid "The current password is invalid"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/graphql/resolvers/user.ex:382 #: lib/graphql/resolvers/user.ex:394
msgid "The new email doesn't seem to be valid" msgid "The new email doesn't seem to be valid"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/graphql/resolvers/user.ex:379 #: lib/graphql/resolvers/user.ex:391
msgid "The new email must be different" msgid "The new email must be different"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/graphql/resolvers/user.ex:333 #: lib/graphql/resolvers/user.ex:341
msgid "The new password must be different" msgid "The new password must be different"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/graphql/resolvers/user.ex:376 lib/graphql/resolvers/user.ex:439 #: lib/graphql/resolvers/user.ex:388 lib/graphql/resolvers/user.ex:455
#: lib/graphql/resolvers/user.ex:442 #: lib/graphql/resolvers/user.ex:458
msgid "The password provided is invalid" msgid "The password provided is invalid"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/graphql/resolvers/user.ex:337 #: lib/graphql/resolvers/user.ex:345
msgid "The password you have chosen is too short. Please make sure your password contains at least 6 characters." msgid "The password you have chosen is too short. Please make sure your password contains at least 6 characters."
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/graphql/resolvers/user.ex:215 #: lib/graphql/resolvers/user.ex:219
msgid "This user can't reset their password" msgid "This user can't reset their password"
msgstr "" msgstr ""
@ -224,12 +224,12 @@ msgid "Unable to validate user"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/graphql/resolvers/user.ex:420 #: lib/graphql/resolvers/user.ex:432
msgid "User already disabled" msgid "User already disabled"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/graphql/resolvers/user.ex:489 #: lib/graphql/resolvers/user.ex:505
msgid "User requested is not logged-in" msgid "User requested is not logged-in"
msgstr "" msgstr ""
@ -254,12 +254,12 @@ msgid "You may not list groups unless moderator."
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/graphql/resolvers/user.ex:387 #: lib/graphql/resolvers/user.ex:399
msgid "You need to be logged-in to change your email" msgid "You need to be logged-in to change your email"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/graphql/resolvers/user.ex:345 #: lib/graphql/resolvers/user.ex:353
msgid "You need to be logged-in to change your password" msgid "You need to be logged-in to change your password"
msgstr "" msgstr ""
@ -269,7 +269,7 @@ msgid "You need to be logged-in to delete a group"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/graphql/resolvers/user.ex:447 #: lib/graphql/resolvers/user.ex:463
msgid "You need to be logged-in to delete your account" msgid "You need to be logged-in to delete your account"
msgstr "" msgstr ""
@ -299,7 +299,7 @@ msgid "You need to have an existing token to get a refresh token"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/graphql/resolvers/user.ex:198 lib/graphql/resolvers/user.ex:222 #: lib/graphql/resolvers/user.ex:198 lib/graphql/resolvers/user.ex:226
msgid "You requested again a confirmation email too soon" msgid "You requested again a confirmation email too soon"
msgstr "" msgstr ""
@ -837,3 +837,23 @@ msgstr ""
#: lib/graphql/resolvers/member.ex:129 #: lib/graphql/resolvers/member.ex:129
msgid "You can't reject this invitation with this profile." msgid "You can't reject this invitation with this profile."
msgstr "" msgstr ""
#, elixir-format
#: lib/graphql/resolvers/user.ex:385
msgid "You can't change your email in demo mode"
msgstr ""
#, elixir-format
#: lib/graphql/resolvers/user.ex:335
msgid "You can't change your password in demo mode"
msgstr ""
#, elixir-format
#: lib/graphql/resolvers/user.ex:448
msgid "You can't delete the demo account"
msgstr ""
#, elixir-format
#: lib/graphql/resolvers/user.ex:216
msgid "You can't reset your password in demo mode"
msgstr ""

View File

@ -757,6 +757,26 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
assert hd(res["errors"])["message"] == assert hd(res["errors"])["message"] ==
"This user can't reset their password" "This user can't reset their password"
end end
test "test send_reset_password/3 when demo mode is enabled", %{conn: conn} do
Config.put([:instance, :demo], true)
Mobilizon.Config.clear_config_cache()
%User{email: email} = insert(:user)
res =
conn
|> AbsintheHelpers.graphql_query(
query: @send_reset_password_mutation,
variables: %{email: email}
)
assert hd(res["errors"])["message"] ==
"You can't reset your password in demo mode"
Config.put([:instance, :demo], false)
Mobilizon.Config.clear_config_cache()
end
end end
describe "Resolver: Reset user's password" do describe "Resolver: Reset user's password" do
@ -1010,6 +1030,14 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
@old_password "p4ssw0rd" @old_password "p4ssw0rd"
@new_password "upd4t3d" @new_password "upd4t3d"
@change_password_mutation """
mutation ChangePassword($oldPassword: String!, $newPassword: String!) {
changePassword(oldPassword: $oldPassword, newPassword: $newPassword) {
id
}
}
"""
test "change_password/3 with valid password", %{conn: conn} do test "change_password/3 with valid password", %{conn: conn} do
{:ok, %User{} = user} = Users.register(%{email: @email, password: @old_password}) {:ok, %User{} = user} = Users.register(%{email: @email, password: @old_password})
@ -1043,21 +1071,16 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
assert login = json_response(res, 200)["data"]["login"] assert login = json_response(res, 200)["data"]["login"]
assert Map.has_key?(login, "accessToken") && not is_nil(login["accessToken"]) assert Map.has_key?(login, "accessToken") && not is_nil(login["accessToken"])
mutation = """
mutation {
changePassword(old_password: "#{@old_password}", new_password: "#{@new_password}") {
id
}
}
"""
res = res =
conn conn
|> auth_conn(user) |> auth_conn(user)
|> post("/api", AbsintheHelpers.mutation_skeleton(mutation)) |> AbsintheHelpers.graphql_query(
query: @change_password_mutation,
variables: %{oldPassword: @old_password, newPassword: @new_password}
)
assert json_response(res, 200)["errors"] == nil assert is_nil(res["errors"])
assert json_response(res, 200)["data"]["changePassword"]["id"] == to_string(user.id) assert res["data"]["changePassword"]["id"] == to_string(user.id)
mutation = """ mutation = """
mutation { mutation {
@ -1094,20 +1117,15 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
"confirmation_token" => nil "confirmation_token" => nil
}) })
mutation = """
mutation {
changePassword(old_password: "invalid password", new_password: "#{@new_password}") {
id
}
}
"""
res = res =
conn conn
|> auth_conn(user) |> auth_conn(user)
|> post("/api", AbsintheHelpers.mutation_skeleton(mutation)) |> AbsintheHelpers.graphql_query(
query: @change_password_mutation,
variables: %{oldPassword: "invalid password", newPassword: @new_password}
)
assert hd(json_response(res, 200)["errors"])["message"] == "The current password is invalid" assert hd(res["errors"])["message"] == "The current password is invalid"
end end
test "change_password/3 with same password", %{conn: conn} do test "change_password/3 with same password", %{conn: conn} do
@ -1121,20 +1139,15 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
"confirmation_token" => nil "confirmation_token" => nil
}) })
mutation = """
mutation {
changePassword(old_password: "#{@old_password}", new_password: "#{@old_password}") {
id
}
}
"""
res = res =
conn conn
|> auth_conn(user) |> auth_conn(user)
|> post("/api", AbsintheHelpers.mutation_skeleton(mutation)) |> AbsintheHelpers.graphql_query(
query: @change_password_mutation,
variables: %{oldPassword: @old_password, newPassword: @old_password}
)
assert hd(json_response(res, 200)["errors"])["message"] == assert hd(res["errors"])["message"] ==
"The new password must be different" "The new password must be different"
end end
@ -1149,26 +1162,46 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
"confirmation_token" => nil "confirmation_token" => nil
}) })
mutation = """
mutation {
changePassword(old_password: "#{@old_password}", new_password: "new") {
id
}
}
"""
res = res =
conn conn
|> auth_conn(user) |> auth_conn(user)
|> post("/api", AbsintheHelpers.mutation_skeleton(mutation)) |> AbsintheHelpers.graphql_query(
query: @change_password_mutation,
variables: %{oldPassword: @old_password, newPassword: "new"}
)
assert hd(json_response(res, 200)["errors"])["message"] == assert hd(res["errors"])["message"] ==
"The password you have chosen is too short. Please make sure your password contains at least 6 characters." "The password you have chosen is too short. Please make sure your password contains at least 6 characters."
end end
test "change_password/3 without being authenticated", %{conn: conn} do test "change_password/3 without being authenticated", %{conn: conn} do
{:ok, %User{} = user} = Users.register(%{email: @email, password: @old_password}) {:ok, %User{} = user} = Users.register(%{email: @email, password: @old_password})
# Hammer time !
{:ok, %User{} = _user} =
Users.update_user(user, %{
"confirmed_at" => Timex.shift(user.confirmation_sent_at, hours: -3),
"confirmation_sent_at" => nil,
"confirmation_token" => nil
})
res =
conn
|> AbsintheHelpers.graphql_query(
query: @change_password_mutation,
variables: %{oldPassword: @old_password, newPassword: @new_password}
)
assert hd(res["errors"])["message"] ==
"You need to be logged-in to change your password"
end
test "change_password/3 with demo mode enabled", %{conn: conn} do
Mobilizon.Config.clear_config_cache()
Config.put([:instance, :demo], true)
{:ok, %User{} = user} = Users.register(%{email: @email, password: @old_password})
# Hammer time ! # Hammer time !
{:ok, %User{} = _user} = {:ok, %User{} = _user} =
Users.update_user(user, %{ Users.update_user(user, %{
@ -1179,8 +1212,15 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
mutation = """ mutation = """
mutation { mutation {
changePassword(old_password: "#{@old_password}", new_password: "#{@new_password}") { login(
id email: "#{@email}",
password: "#{@old_password}",
) {
accessToken,
refreshToken,
user {
id
}
} }
} }
""" """
@ -1189,8 +1229,21 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
conn conn
|> post("/api", AbsintheHelpers.mutation_skeleton(mutation)) |> post("/api", AbsintheHelpers.mutation_skeleton(mutation))
assert hd(json_response(res, 200)["errors"])["message"] == assert login = json_response(res, 200)["data"]["login"]
"You need to be logged-in to change your password" assert Map.has_key?(login, "accessToken") && not is_nil(login["accessToken"])
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @change_password_mutation,
variables: %{oldPassword: @old_password, newPassword: @new_password}
)
assert hd(res["errors"])["message"] == "You can't change your password in demo mode"
Config.put([:instance, :demo], false)
Mobilizon.Config.clear_config_cache()
end end
end end
@ -1315,6 +1368,44 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
assert hd(res["errors"])["message"] == "The new email doesn't seem to be valid" assert hd(res["errors"])["message"] == "The new email doesn't seem to be valid"
end end
test "change_email/3 with demo mode enabled", %{conn: conn} do
Mobilizon.Config.clear_config_cache()
Config.put([:instance, :demo], true)
{:ok, %User{} = user} = Users.register(%{email: @old_email, password: @password})
# Hammer time !
{:ok, %User{} = _user} =
Users.update_user(user, %{
confirmed_at: Timex.shift(user.confirmation_sent_at, hours: -3),
confirmation_sent_at: nil,
confirmation_token: nil
})
res =
conn
|> AbsintheHelpers.graphql_query(
query: @login_mutation,
variables: %{email: @old_email, password: @password}
)
login = res["data"]["login"]
assert Map.has_key?(login, "accessToken") && not is_nil(login["accessToken"])
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @change_email_mutation,
variables: %{email: @new_email, password: @password}
)
assert hd(res["errors"])["message"] == "You can't change your email in demo mode"
Config.put([:instance, :demo], false)
Mobilizon.Config.clear_config_cache()
end
test "change_password/3 without being authenticated", %{conn: conn} do test "change_password/3 without being authenticated", %{conn: conn} do
{:ok, %User{} = user} = Users.register(%{email: @old_email, password: @password}) {:ok, %User{} = user} = Users.register(%{email: @old_email, password: @password})