Add registration
This commit is contained in:
1 parent
137e53618b
commit
e5ec0ff1a1
5 files changed
+291
-125
No files matched your search
@@ -3,11 +3,10 @@
|
|||||||
## À faire
|
## À faire
|
||||||
|
|
||||||
- limiter le spam sur `/contact/send`
|
- limiter le spam sur `/contact/send`
|
||||||
- développer l'inscription des utilisateurs et la vérification des adresses électroniques
|
|
||||||
- développer les demandes d'adhésion et leur examen par le Noyau
|
- développer les demandes d'adhésion et leur examen par le Noyau
|
||||||
- développer l'espace personnel des adhérents
|
- développer l'espace personnel des membres
|
||||||
- afficher les recettes et les dépenses sur la page d'accueil
|
- afficher les recettes et les dépenses sur la page d'accueil
|
||||||
- gérer les accès aux services selon la situation des adhérents
|
- gérer les accès aux services selon la situation des membres
|
||||||
|
|
||||||
## Développement
|
## Développement
|
||||||
|
|
||||||
@@ -21,10 +20,18 @@ Créer un fichier `.env` à la racine du projet :
|
|||||||
|
|
||||||
```dotenv
|
```dotenv
|
||||||
SESSION_SECRET=...
|
SESSION_SECRET=...
|
||||||
|
RODAUTH_HMAC_SECRET=...
|
||||||
|
RODAUTH_DOMAIN=netig.net
|
||||||
|
BASE_URL=http://[::1]:9292
|
||||||
SMTP_PASSWORD=...
|
SMTP_PASSWORD=...
|
||||||
```
|
```
|
||||||
|
|
||||||
Générer `SESSION_SECRET` avec `openssl rand -hex 64`.
|
Générer `SESSION_SECRET` et `RODAUTH_HMAC_SECRET` avec :
|
||||||
|
|
||||||
|
```sh
|
||||||
|
openssl rand -hex 64
|
||||||
|
```
|
||||||
|
|
||||||
Ne pas versionner le fichier `.env`.
|
Ne pas versionner le fichier `.env`.
|
||||||
|
|
||||||
Créer ou mettre à jour la base de données :
|
Créer ou mettre à jour la base de données :
|
||||||
@@ -33,32 +40,33 @@ Créer ou mettre à jour la base de données :
|
|||||||
bundle exec ruby bin/migrate
|
bundle exec ruby bin/migrate
|
||||||
```
|
```
|
||||||
|
|
||||||
Créer un ou plusieurs comptes de test :
|
|
||||||
|
|
||||||
```sh
|
|
||||||
bundle exec ruby bin/initialize-account
|
|
||||||
```
|
|
||||||
|
|
||||||
Cette commande crée un compte vérifié et sa fiche de membre.
|
|
||||||
Elle peut être exécutée plusieurs fois. Les comptes créés ne possèdent
|
|
||||||
aucune adhésion ni responsabilité au sein du Noyau.
|
|
||||||
|
|
||||||
Pour tester l'espace du Noyau, désigner un ou plusieurs comptes de test :
|
|
||||||
|
|
||||||
```sh
|
|
||||||
bundle exec ruby bin/initialize-core
|
|
||||||
```
|
|
||||||
|
|
||||||
En développement, un seul membre suffit. Cette commande peut être
|
|
||||||
réexécutée pour ajouter d'autres membres au Noyau.
|
|
||||||
|
|
||||||
Démarrer le serveur de développement :
|
Démarrer le serveur de développement :
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
bundle exec puma
|
bundle exec puma
|
||||||
```
|
```
|
||||||
|
|
||||||
Ou ouvrir un shell interactif :
|
Créer des comptes de test depuis le site :
|
||||||
|
|
||||||
|
http://[::1]:9292/create-account
|
||||||
|
|
||||||
|
Les personnes physiques et les personnes morales peuvent créer
|
||||||
|
un compte. L'adresse électronique doit être vérifiée avant de
|
||||||
|
pouvoir se connecter.
|
||||||
|
|
||||||
|
Pour tester l'espace du Noyau, désigner un ou plusieurs comptes
|
||||||
|
de test depuis le terminal :
|
||||||
|
|
||||||
|
```sh
|
||||||
|
bundle exec ruby bin/initialize-core
|
||||||
|
```
|
||||||
|
|
||||||
|
En développement, un seul membre suffit. Cette commande peut
|
||||||
|
être réexécutée pour ajouter d'autres membres au Noyau.
|
||||||
|
|
||||||
|
La date de l'assemblée est demandée lors de l'exécution.
|
||||||
|
|
||||||
|
Pour ouvrir un shell interactif :
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
bundle exec irb -r dotenv/load -r ./netig.rb
|
bundle exec irb -r dotenv/load -r ./netig.rb
|
||||||
@@ -66,11 +74,24 @@ bundle exec irb -r dotenv/load -r ./netig.rb
|
|||||||
|
|
||||||
## Production
|
## Production
|
||||||
|
|
||||||
Docker Compose fournit les variables d'environnement via `env_file` et définit
|
Docker Compose fournit les variables d'environnement via `env_file`
|
||||||
`RACK_ENV=production`.
|
et définit `RACK_ENV=production`.
|
||||||
|
|
||||||
Exécuter les migrations dans le conteneur applicatif avant de démarrer
|
Le fichier d'environnement doit notamment définir :
|
||||||
la nouvelle version :
|
|
||||||
|
```dotenv
|
||||||
|
SESSION_SECRET=...
|
||||||
|
RODAUTH_HMAC_SECRET=...
|
||||||
|
RODAUTH_DOMAIN=netig.net
|
||||||
|
BASE_URL=https://netig.net
|
||||||
|
SMTP_PASSWORD=...
|
||||||
|
```
|
||||||
|
|
||||||
|
Générer les deux secrets avec `openssl rand -hex 64`.
|
||||||
|
Ne pas versionner le fichier contenant ces variables.
|
||||||
|
|
||||||
|
Créer ou mettre à jour la base de données dans le conteneur
|
||||||
|
applicatif avant de démarrer la nouvelle version :
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
bundle exec ruby bin/migrate
|
bundle exec ruby bin/migrate
|
||||||
@@ -78,19 +99,22 @@ bundle exec ruby bin/migrate
|
|||||||
|
|
||||||
### Initialisation du premier Noyau
|
### Initialisation du premier Noyau
|
||||||
|
|
||||||
Une fois l'inscription publique disponible, les membres fondateurs créent
|
Une fois l'inscription publique disponible, les membres fondateurs
|
||||||
leurs comptes depuis le site et vérifient leurs adresses électroniques.
|
créent leurs comptes depuis le site et vérifient leurs adresses
|
||||||
|
électroniques.
|
||||||
|
|
||||||
Après leur désignation par l'assemblée constitutive, initialiser le Noyau
|
Après leur désignation par l'assemblée constitutive, initialiser
|
||||||
depuis le conteneur applicatif :
|
le Noyau depuis le conteneur applicatif :
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
bundle exec ruby bin/initialize-core
|
bundle exec ruby bin/initialize-core
|
||||||
```
|
```
|
||||||
|
|
||||||
Cette commande doit être exécutée une seule fois en production.
|
Cette commande doit être exécutée une seule fois en production.
|
||||||
Elle exige au moins trois personnes physiques disposant d'un compte vérifié.
|
Elle exige au moins trois personnes physiques disposant d'un
|
||||||
Elle enregistre leurs adhésions comme acceptées et leur attribue la qualité
|
compte vérifié.
|
||||||
de membre du Noyau.
|
|
||||||
|
Elle enregistre leurs adhésions comme acceptées et leur attribue
|
||||||
|
la qualité de membre du Noyau.
|
||||||
|
|
||||||
La date de l'assemblée constitutive est demandée lors de l'exécution.
|
La date de l'assemblée constitutive est demandée lors de l'exécution.
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
#!/usr/bin/env ruby
|
|
||||||
|
|
||||||
environment = ENV.fetch("RACK_ENV", "development")
|
|
||||||
require "dotenv/load" if environment == "development"
|
|
||||||
|
|
||||||
abort "Ce script est réservé au développement." unless
|
|
||||||
ENV.fetch("RACK_ENV", "development") == "development"
|
|
||||||
|
|
||||||
require "io/console"
|
|
||||||
require "rodauth"
|
|
||||||
|
|
||||||
require_relative "../lib/database"
|
|
||||||
|
|
||||||
console = IO.console or abort "Terminal interactif requis."
|
|
||||||
|
|
||||||
console.print "Adresse électronique : "
|
|
||||||
email = console.gets&.strip&.downcase
|
|
||||||
|
|
||||||
abort "Adresse électronique obligatoire." if email.to_s.empty?
|
|
||||||
|
|
||||||
existing_account = DB[:accounts]
|
|
||||||
.where(Sequel.function(:lower, :email) => email)
|
|
||||||
.count
|
|
||||||
.positive?
|
|
||||||
|
|
||||||
abort "Ce compte existe déjà." if existing_account
|
|
||||||
|
|
||||||
console.print "Prénom : "
|
|
||||||
first_name = console.gets&.strip
|
|
||||||
|
|
||||||
console.print "Nom : "
|
|
||||||
last_name = console.gets&.strip
|
|
||||||
|
|
||||||
abort "Prénom et nom obligatoires." if
|
|
||||||
first_name.to_s.empty? || last_name.to_s.empty?
|
|
||||||
|
|
||||||
password = console.getpass("Mot de passe : ")
|
|
||||||
confirmation = console.getpass("Confirmer le mot de passe : ")
|
|
||||||
|
|
||||||
abort "Mot de passe obligatoire." if password.to_s.empty?
|
|
||||||
abort "Les mots de passe ne correspondent pas." unless
|
|
||||||
password == confirmation
|
|
||||||
|
|
||||||
verified_status_id = DB[:account_statuses]
|
|
||||||
.where(name: "Verified")
|
|
||||||
.get(:id)
|
|
||||||
|
|
||||||
abort "Statut Verified introuvable." unless verified_status_id
|
|
||||||
|
|
||||||
console.puts
|
|
||||||
console.puts "Compte : #{first_name} #{last_name} (#{email})"
|
|
||||||
console.puts
|
|
||||||
console.print "Confirmer la création ? [o/N] "
|
|
||||||
|
|
||||||
abort "Opération annulée." unless %w[o oui].include?(
|
|
||||||
console.gets&.strip&.downcase
|
|
||||||
)
|
|
||||||
|
|
||||||
auth = Rodauth.lib do
|
|
||||||
db DB
|
|
||||||
enable :create_account
|
|
||||||
|
|
||||||
already_logged_in { super() }
|
|
||||||
end
|
|
||||||
|
|
||||||
DB.transaction do
|
|
||||||
auth.create_account(
|
|
||||||
login: email,
|
|
||||||
password: password
|
|
||||||
)
|
|
||||||
|
|
||||||
account_id = auth.account_id_for_login(login: email)
|
|
||||||
|
|
||||||
DB[:accounts]
|
|
||||||
.where(id: account_id)
|
|
||||||
.update(status_id: verified_status_id)
|
|
||||||
|
|
||||||
DB[:members].insert(
|
|
||||||
account_id: account_id,
|
|
||||||
kind: "individual",
|
|
||||||
first_name: first_name,
|
|
||||||
last_name: last_name,
|
|
||||||
organization_name: nil,
|
|
||||||
core_member: false
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
puts "Compte de développement créé."
|
|
||||||
|
|
||||||
@@ -19,7 +19,17 @@ class Netig < Roda
|
|||||||
plugin :rodauth do
|
plugin :rodauth do
|
||||||
db DB
|
db DB
|
||||||
|
|
||||||
enable :login, :logout
|
enable :login, :logout, :create_account, :verify_account
|
||||||
|
|
||||||
|
domain ENV.fetch("RODAUTH_DOMAIN")
|
||||||
|
|
||||||
|
account_unverified_status_value 1
|
||||||
|
account_open_status_value 2
|
||||||
|
|
||||||
|
base_url ENV.fetch("BASE_URL")
|
||||||
|
hmac_secret ENV.fetch("RODAUTH_HMAC_SECRET")
|
||||||
|
|
||||||
|
email_from "NETig <noreply@netig.net>"
|
||||||
|
|
||||||
login_label "Adresse électronique"
|
login_label "Adresse électronique"
|
||||||
password_label "Mot de passe"
|
password_label "Mot de passe"
|
||||||
@@ -28,6 +38,87 @@ class Netig < Roda
|
|||||||
login_redirect "/temporary_page"
|
login_redirect "/temporary_page"
|
||||||
login_return_to_requested_location? true
|
login_return_to_requested_location? true
|
||||||
|
|
||||||
|
create_account_page_title "Créer un compte — NETig"
|
||||||
|
create_account_button "Créer mon compte"
|
||||||
|
create_account_link_text "Créer un compte"
|
||||||
|
|
||||||
|
verify_account_page_title "Vérifier votre adresse électronique — NETig"
|
||||||
|
verify_account_button "Confirmer mon adresse électronique"
|
||||||
|
verify_account_set_password? true
|
||||||
|
|
||||||
|
verify_account_email_subject "Confirmez votre adresse électronique — NETig"
|
||||||
|
|
||||||
|
verify_account_email_body do
|
||||||
|
<<~EMAIL
|
||||||
|
Bonjour,
|
||||||
|
|
||||||
|
Pour vérifier votre adresse électronique et activer votre compte
|
||||||
|
NETig, ouvrez le lien suivant :
|
||||||
|
|
||||||
|
#{verify_account_email_link}
|
||||||
|
|
||||||
|
Si vous n'êtes pas à l'origine de cette demande, ignorez ce message.
|
||||||
|
|
||||||
|
L'équipe NETig
|
||||||
|
EMAIL
|
||||||
|
end
|
||||||
|
|
||||||
|
verify_account_email_sent_notice_flash(
|
||||||
|
"Un courriel de vérification vient de vous être envoyé."
|
||||||
|
)
|
||||||
|
|
||||||
|
verify_account_notice_flash(
|
||||||
|
"Votre adresse électronique est maintenant vérifiée."
|
||||||
|
)
|
||||||
|
|
||||||
|
before_create_account do
|
||||||
|
case param("kind")
|
||||||
|
when "individual"
|
||||||
|
throw_error_status(
|
||||||
|
422, "first_name", "doit être renseigné"
|
||||||
|
) if param("first_name").to_s.strip.empty?
|
||||||
|
|
||||||
|
throw_error_status(
|
||||||
|
422, "last_name", "doit être renseigné"
|
||||||
|
) if param("last_name").to_s.strip.empty?
|
||||||
|
|
||||||
|
when "organization"
|
||||||
|
throw_error_status(
|
||||||
|
422, "organization_name", "doit être renseignée"
|
||||||
|
) if param("organization_name").to_s.strip.empty?
|
||||||
|
|
||||||
|
else
|
||||||
|
throw_error_status(
|
||||||
|
422, "kind", "choisissez un type de compte"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
after_create_account do
|
||||||
|
member = if param("kind") == "individual"
|
||||||
|
{
|
||||||
|
kind: "individual",
|
||||||
|
first_name: param("first_name").to_s.strip,
|
||||||
|
last_name: param("last_name").to_s.strip,
|
||||||
|
organization_name: nil
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
kind: "organization",
|
||||||
|
first_name: nil,
|
||||||
|
last_name: nil,
|
||||||
|
organization_name: param("organization_name").to_s.strip
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
db[:members].insert(
|
||||||
|
member.merge(
|
||||||
|
account_id: account[:id],
|
||||||
|
core_member: false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
already_logged_in do
|
already_logged_in do
|
||||||
request.redirect("/")
|
request.redirect("/")
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -0,0 +1,140 @@
|
|||||||
|
<% kind = request.params["kind"] %>
|
||||||
|
<% valid_kind = %w[individual organization].include?(kind) %>
|
||||||
|
|
||||||
|
<section class="page-section">
|
||||||
|
<div class="content page-panel">
|
||||||
|
<h1>Créer un compte</h1>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Créez un compte pour accéder à votre espace personnel
|
||||||
|
et, si vous le souhaitez, demander à rejoindre NETig.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<% if error = flash["error"] %>
|
||||||
|
<p class="flash flash--error" role="alert"><%= error %></p>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% unless valid_kind %>
|
||||||
|
<p>Quel type de compte souhaitez-vous créer ?</p>
|
||||||
|
|
||||||
|
<div class="hero__actions">
|
||||||
|
<a
|
||||||
|
class="button button--secondary"
|
||||||
|
href="<%= rodauth.create_account_path %>?kind=individual"
|
||||||
|
>
|
||||||
|
Personne physique
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a
|
||||||
|
class="button button--secondary"
|
||||||
|
href="<%= rodauth.create_account_path %>?kind=organization"
|
||||||
|
>
|
||||||
|
Personne morale
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<% else %>
|
||||||
|
<form
|
||||||
|
action="<%= rodauth.create_account_path %>"
|
||||||
|
method="post"
|
||||||
|
class="contact-form"
|
||||||
|
accept-charset="UTF-8"
|
||||||
|
>
|
||||||
|
<%== rodauth.csrf_tag %>
|
||||||
|
|
||||||
|
<input type="hidden" name="kind" value="<%= kind %>">
|
||||||
|
|
||||||
|
<% if kind == "individual" %>
|
||||||
|
<h2>Personne physique</h2>
|
||||||
|
|
||||||
|
<label for="first_name">Prénom</label>
|
||||||
|
<input
|
||||||
|
id="first_name"
|
||||||
|
name="first_name"
|
||||||
|
type="text"
|
||||||
|
maxlength="128"
|
||||||
|
autocomplete="given-name"
|
||||||
|
value="<%= request.params["first_name"] %>"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
|
||||||
|
<% if error = rodauth.field_error("first_name") %>
|
||||||
|
<p class="flash flash--error"><%= error %></p>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<label for="last_name">Nom</label>
|
||||||
|
<input
|
||||||
|
id="last_name"
|
||||||
|
name="last_name"
|
||||||
|
type="text"
|
||||||
|
maxlength="128"
|
||||||
|
autocomplete="family-name"
|
||||||
|
value="<%= request.params["last_name"] %>"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
|
||||||
|
<% if error = rodauth.field_error("last_name") %>
|
||||||
|
<p class="flash flash--error"><%= error %></p>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% else %>
|
||||||
|
<h2>Personne morale</h2>
|
||||||
|
|
||||||
|
<label for="organization_name">Dénomination</label>
|
||||||
|
<input
|
||||||
|
id="organization_name"
|
||||||
|
name="organization_name"
|
||||||
|
type="text"
|
||||||
|
maxlength="255"
|
||||||
|
autocomplete="organization"
|
||||||
|
value="<%= request.params["organization_name"] %>"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
|
||||||
|
<% if error = rodauth.field_error("organization_name") %>
|
||||||
|
<p class="flash flash--error"><%= error %></p>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<label for="<%= rodauth.login_param %>">
|
||||||
|
Adresse électronique
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="<%= rodauth.login_param %>"
|
||||||
|
name="<%= rodauth.login_param %>"
|
||||||
|
type="<%= rodauth.login_input_type %>"
|
||||||
|
maxlength="254"
|
||||||
|
autocomplete="email"
|
||||||
|
value="<%= request.params[rodauth.login_param] %>"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
|
||||||
|
<% if error = rodauth.field_error(rodauth.login_param) %>
|
||||||
|
<p class="flash flash--error"><%= error %></p>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Nous vous enverrons un courriel pour vérifier votre adresse
|
||||||
|
électronique. Vous choisirez votre mot de passe à cette étape.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="submit"
|
||||||
|
value="<%= rodauth.create_account_button %>"
|
||||||
|
class="submit"
|
||||||
|
>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<a href="<%= rodauth.create_account_path %>">
|
||||||
|
Changer de type de compte
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Vous avez déjà un compte ?
|
||||||
|
<a href="<%= rodauth.login_path %>">Se connecter</a>.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
Reference in new issue
Block a user