Add registration

This commit is contained in:
julien committed 2026-11-03 12:08:57 +01:00
1 parent 137e53618b
commit e5ec0ff1a1
5 files changed
+291 -125

No files matched your search

View File
Whitespace-only changes.
+59 -35
View File
@@ -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.
-89
View File
@@ -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éé."
+92 -1
View File
@@ -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
+140
View File
@@ -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>