Remove admin account
This commit is contained in:
1 parent
4f28a59c7e
commit
db316b2914
13 files changed
+372
-144
No files matched your search
@@ -33,15 +33,24 @@ Créer ou mettre à jour la base de données :
|
||||
bundle exec ruby bin/migrate
|
||||
```
|
||||
|
||||
Lors de la première installation, créer le compte du premier administrateur :
|
||||
Créer un ou plusieurs comptes de test :
|
||||
|
||||
```sh
|
||||
bundle exec ruby bin/initialize-admin
|
||||
bundle exec ruby bin/initialize-account
|
||||
```
|
||||
|
||||
Cette commande est à exécuter une seule fois. Elle crée un compte vérifié et
|
||||
lui attribue les droits techniques d'administration. Elle ne crée pas de
|
||||
demande d'adhésion.
|
||||
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 :
|
||||
|
||||
@@ -60,16 +69,28 @@ bundle exec irb -r dotenv/load -r ./netig.rb
|
||||
Docker Compose fournit les variables d'environnement via `env_file` et définit
|
||||
`RACK_ENV=production`.
|
||||
|
||||
Exécuter les migrations dans le conteneur applicatif avant de démarrer la
|
||||
nouvelle version :
|
||||
Exécuter les migrations dans le conteneur applicatif avant de démarrer
|
||||
la nouvelle version :
|
||||
|
||||
```sh
|
||||
bundle exec ruby bin/migrate
|
||||
```
|
||||
|
||||
Lors de la première installation, créer le premier administrateur depuis le
|
||||
conteneur applicatif :
|
||||
### Initialisation du premier Noyau
|
||||
|
||||
Une fois l'inscription publique disponible, les membres fondateurs 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
|
||||
depuis le conteneur applicatif :
|
||||
|
||||
```sh
|
||||
bundle exec ruby bin/initialize-admin
|
||||
bundle exec ruby bin/initialize-core
|
||||
```
|
||||
|
||||
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 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.
|
||||
@@ -1,6 +1,11 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require "dotenv/load" if ENV.fetch("RACK_ENV", "development") == "development"
|
||||
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"
|
||||
|
||||
@@ -8,16 +13,17 @@ require_relative "../lib/database"
|
||||
|
||||
console = IO.console or abort "Terminal interactif requis."
|
||||
|
||||
abort "Un administrateur existe déjà." if
|
||||
DB[:members].where(admin: true).count.positive?
|
||||
|
||||
console.print "Adresse électronique : "
|
||||
email = console.gets&.strip
|
||||
email = console.gets&.strip&.downcase
|
||||
|
||||
abort "Adresse électronique obligatoire." if email.to_s.empty?
|
||||
|
||||
abort "Ce compte existe déjà." if
|
||||
DB[:accounts].where(email: email).count.positive?
|
||||
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
|
||||
@@ -31,16 +37,9 @@ abort "Prénom et nom obligatoires." if
|
||||
password = console.getpass("Mot de passe : ")
|
||||
confirmation = console.getpass("Confirmer le mot de passe : ")
|
||||
|
||||
abort "Mot de passe obligatoire." if password.empty?
|
||||
abort "Les mots de passe ne correspondent pas." unless password == confirmation
|
||||
|
||||
console.puts
|
||||
console.puts "Administrateur : #{first_name} #{last_name} (#{email})"
|
||||
console.print "Confirmer la création ? [o/N] "
|
||||
|
||||
abort "Opération annulée." unless %w[o oui].include?(
|
||||
console.gets&.strip&.downcase
|
||||
)
|
||||
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")
|
||||
@@ -48,6 +47,15 @@ verified_status_id = DB[:account_statuses]
|
||||
|
||||
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
|
||||
@@ -73,8 +81,9 @@ DB.transaction do
|
||||
first_name: first_name,
|
||||
last_name: last_name,
|
||||
organization_name: nil,
|
||||
admin: true
|
||||
core_member: false
|
||||
)
|
||||
end
|
||||
|
||||
puts "Premier administrateur créé."
|
||||
puts "Compte de développement créé."
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
environment = ENV.fetch("RACK_ENV", "development")
|
||||
require "dotenv/load" if environment == "development"
|
||||
|
||||
abort "Environnement non pris en charge." unless
|
||||
%w[development production].include?(
|
||||
ENV.fetch("RACK_ENV", "development")
|
||||
)
|
||||
|
||||
require "date"
|
||||
require "io/console"
|
||||
|
||||
require_relative "../lib/database"
|
||||
|
||||
console = IO.console or abort "Terminal interactif requis."
|
||||
|
||||
if environment == "production" &&
|
||||
DB[:members].where(core_member: true).count.positive?
|
||||
abort "Un Noyau existe déjà."
|
||||
end
|
||||
|
||||
verified_status_id = DB[:account_statuses]
|
||||
.where(name: "Verified")
|
||||
.get(:id)
|
||||
|
||||
abort "Statut Verified introuvable." unless verified_status_id
|
||||
|
||||
find_member = lambda do |email|
|
||||
account = DB[:accounts]
|
||||
.where(Sequel.function(:lower, :email) => email)
|
||||
.first
|
||||
|
||||
abort "Compte introuvable : #{email}" unless account
|
||||
|
||||
abort "Adresse électronique non vérifiée : #{email}" unless
|
||||
account[:status_id] == verified_status_id
|
||||
|
||||
member = DB[:members]
|
||||
.where(account_id: account[:id])
|
||||
.first
|
||||
|
||||
abort "Fiche membre introuvable : #{email}" unless member
|
||||
|
||||
abort "Une personne physique est requise : #{email}" unless
|
||||
member[:kind] == "individual"
|
||||
|
||||
member
|
||||
end
|
||||
|
||||
console.print "Date de l'assemblée (AAAA-MM-JJ) : "
|
||||
date_input = console.gets&.strip
|
||||
|
||||
unless date_input&.match?(/\A\d{4}-\d{2}-\d{2}\z/)
|
||||
abort "Format attendu : AAAA-MM-JJ."
|
||||
end
|
||||
|
||||
begin
|
||||
assembly_date = Date.iso8601(date_input)
|
||||
rescue Date::Error
|
||||
abort "Date invalide."
|
||||
end
|
||||
|
||||
abort "La date ne peut pas être dans le futur." if
|
||||
assembly_date > Date.today
|
||||
|
||||
assembly_datetime = Time.utc(
|
||||
assembly_date.year,
|
||||
assembly_date.month,
|
||||
assembly_date.day
|
||||
)
|
||||
|
||||
console.puts
|
||||
console.puts "Saisissez les adresses électroniques des membres désignés."
|
||||
console.puts "Une adresse par ligne. Entrée pour terminer."
|
||||
console.puts
|
||||
|
||||
emails = []
|
||||
|
||||
loop do
|
||||
console.print "Adresse électronique : "
|
||||
email = console.gets&.strip&.downcase
|
||||
|
||||
break if email.to_s.empty?
|
||||
|
||||
abort "Adresse déjà saisie : #{email}" if emails.include?(email)
|
||||
|
||||
emails << email
|
||||
end
|
||||
|
||||
minimum_members = environment == "production" ? 3 : 1
|
||||
|
||||
abort "Au moins #{minimum_members} membre(s) sont nécessaires." if
|
||||
emails.length < minimum_members
|
||||
|
||||
members = emails.map do |email|
|
||||
[email, find_member.call(email)]
|
||||
end
|
||||
|
||||
console.puts
|
||||
console.print "Adresse de la personne qui enregistre la décision : "
|
||||
recorded_by_email = console.gets&.strip&.downcase
|
||||
|
||||
abort "Adresse électronique obligatoire." if
|
||||
recorded_by_email.to_s.empty?
|
||||
|
||||
recorded_by = find_member.call(recorded_by_email)
|
||||
|
||||
console.puts
|
||||
console.puts "Environnement : #{environment}"
|
||||
console.puts "Date de l'assemblée : #{assembly_date}"
|
||||
console.puts
|
||||
console.puts "Membres du Noyau :"
|
||||
|
||||
members.each do |email, member|
|
||||
name = "#{member[:first_name]} #{member[:last_name]}"
|
||||
console.puts " #{name} (#{email})"
|
||||
end
|
||||
|
||||
console.puts
|
||||
console.puts "Décision enregistrée par : #{recorded_by_email}"
|
||||
console.puts
|
||||
console.print "Confirmer l'initialisation ? [o/N] "
|
||||
|
||||
abort "Opération annulée." unless %w[o oui].include?(
|
||||
console.gets&.strip&.downcase
|
||||
)
|
||||
|
||||
if environment == "production" &&
|
||||
DB[:members].where(core_member: true).count.positive?
|
||||
abort "Un Noyau existe déjà."
|
||||
end
|
||||
|
||||
DB.transaction do
|
||||
members.each do |_email, member|
|
||||
membership = DB[:memberships]
|
||||
.where(
|
||||
member_id: member[:id],
|
||||
status: %w[pending accepted],
|
||||
ended_at: nil
|
||||
)
|
||||
.first
|
||||
|
||||
if membership && membership[:status] == "pending"
|
||||
DB[:memberships]
|
||||
.where(id: membership[:id])
|
||||
.update(
|
||||
status: "accepted",
|
||||
decided_at: assembly_datetime,
|
||||
recorded_by: recorded_by[:id]
|
||||
)
|
||||
elsif membership.nil?
|
||||
DB[:memberships].insert(
|
||||
member_id: member[:id],
|
||||
status: "accepted",
|
||||
requested_at: assembly_datetime,
|
||||
decided_at: assembly_datetime,
|
||||
recorded_by: recorded_by[:id]
|
||||
)
|
||||
end
|
||||
|
||||
DB[:members]
|
||||
.where(id: member[:id])
|
||||
.update(core_member: true)
|
||||
end
|
||||
end
|
||||
|
||||
puts "Noyau initialisé (#{members.length} membres)."
|
||||
|
||||
@@ -12,7 +12,7 @@ Sequel.migration do
|
||||
String :last_name
|
||||
String :organization_name
|
||||
|
||||
TrueClass :admin, null: false, default: false
|
||||
TrueClass :core_member, null: false, default: false
|
||||
|
||||
index :account_id, unique: true
|
||||
|
||||
@@ -28,6 +28,9 @@ Sequel.migration do
|
||||
"AND last_name IS NULL AND organization_name IS NOT NULL " \
|
||||
"AND trim(organization_name) <> '')"
|
||||
)
|
||||
|
||||
constraint :members_core_member_individual,
|
||||
Sequel.lit("core_member = FALSE OR kind = 'individual'")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
+67
-50
@@ -1,9 +1,9 @@
|
||||
# Informations légales et conditions d’utilisation
|
||||
|
||||
NETig est un projet associatif régi par la loi du 1er juillet 1901.
|
||||
L’association n’a pas encore été déclarée en préfecture et ne dispose donc
|
||||
pas encore de la personnalité morale ni de la capacité juridique attachée
|
||||
à une association déclarée. Cette information sera mise à jour après la
|
||||
L’association n’a pas encore été déclarée en préfecture et ne dispose
|
||||
donc pas encore de la personnalité morale ni de la capacité juridique
|
||||
attachée à une association déclarée. Cette information sera mise à jour après la
|
||||
déclaration et sa publication au Journal officiel des associations et
|
||||
fondations d’entreprises (JOAFE).
|
||||
|
||||
@@ -30,30 +30,29 @@ Finlande.
|
||||
|
||||
Les services NETig sont proposés sans facturation liée à leur utilisation.
|
||||
Certains sont accessibles au public ; d’autres sont réservés aux membres
|
||||
à jour de leur cotisation.
|
||||
de l’association.
|
||||
|
||||
Conformément aux statuts, toute demande d’adhésion est examinée par le Noyau.
|
||||
L’adhésion prend effet après acceptation de la demande et paiement de la
|
||||
cotisation annuelle fixée par l’Assemblée générale. Elle dure un an et se
|
||||
renouvelle à chaque échéance si la cotisation est payée. La création d’un
|
||||
compte utilisateur, lorsqu’elle sera proposée, ne vaudra pas à elle seule
|
||||
adhésion à l’association.
|
||||
Toute personne physique ou morale peut demander à adhérer à l’association,
|
||||
à condition d’accepter ses statuts et ses principes. Le Noyau examine les
|
||||
demandes et décide de l’admission. L’adhésion prend effet à la date de
|
||||
son acceptation et est valable sans limitation de durée. La création d’un compte
|
||||
utilisateur ne vaut pas, à elle seule, adhésion à l’association.
|
||||
|
||||
En cas d’impayé, une relance laisse trente jours pour régler la cotisation.
|
||||
Pendant ce délai, le membre n’est plus considéré comme à jour : il ne peut
|
||||
pas voter en Assemblée générale et ses accès aux services réservés aux
|
||||
membres à jour peuvent être suspendus. À défaut de paiement à l’expiration
|
||||
de ce délai, l’adhésion prend fin.
|
||||
|
||||
Les dons sont libres et volontaires. Ils contribuent au financement des
|
||||
infrastructures, ne remplacent pas la cotisation nécessaire à l’adhésion
|
||||
et ne donnent droit à aucun accès ou avantage particulier.
|
||||
Aucune cotisation ni aucun don n’est exigé pour adhérer, conserver la
|
||||
qualité de membre ou exercer les droits qui y sont attachés. Les dons sont
|
||||
libres, volontaires et sans contrepartie. NETig invite les membres et les
|
||||
utilisateurs qui le peuvent à soutenir financièrement l’association, selon
|
||||
leurs moyens. Cette participation contribue au financement des
|
||||
infrastructures et à la pérennité des services, mais ne conditionne ni
|
||||
l’adhésion, ni les droits des membres, ni l’accès aux services et ne donne
|
||||
droit à aucun avantage particulier.
|
||||
|
||||
L’accès à chaque service dépend des ressources disponibles et peut être
|
||||
limité. Une disponibilité permanente n’est pas garantie. L’état des services
|
||||
est consultable sur la [page de statut](https://status.netig.net/status/services).
|
||||
Les interruptions de maintenance peuvent être annoncées par la
|
||||
[liste de diffusion dédiée](https://list.netig.net/subscription/form).
|
||||
est consultable sur la page de statut :
|
||||
[page de statut](https://status.netig.net/status/services). Les interruptions
|
||||
de maintenance peuvent être annoncées par la liste de diffusion dédiée :
|
||||
[liste de diffusion](https://list.netig.net/subscription/form).
|
||||
|
||||
### Utilisation des services
|
||||
|
||||
@@ -71,11 +70,12 @@ propres copies lorsque cela est possible.
|
||||
|
||||
La personne responsable d’un service peut limiter ou suspendre un accès
|
||||
de manière proportionnée en cas d’abus ou de risque pour la sécurité,
|
||||
les données, le fonctionnement ou les ressources du service. Elle informe
|
||||
la personne concernée et le Noyau des motifs de la mesure.
|
||||
les données, le fonctionnement ou les ressources du service. Elle en
|
||||
informe la personne concernée ainsi que le Noyau, en indiquant les motifs
|
||||
de la mesure.
|
||||
|
||||
La personne concernée peut demander au Noyau de réexaminer cette mesure.
|
||||
Le Noyau répond sous quinze jours. Si le Noyau a pris ou confirmé la mesure,
|
||||
Celui-ci répond sous quinze jours. Si le Noyau a pris ou confirmé la mesure,
|
||||
la personne concernée ou tout membre peut demander son réexamen par
|
||||
l’Assemblée générale. La suspension d’un accès ne met pas fin à la qualité
|
||||
de membre.
|
||||
@@ -101,13 +101,16 @@ la personne ou de la structure qui détermine actuellement les finalités
|
||||
et les moyens des traitements].
|
||||
|
||||
La présente notice décrit les traitements réalisés sur le site netig.net,
|
||||
notamment par son formulaire de contact. Les services hébergés sur d’autres
|
||||
adresses peuvent mettre en œuvre des traitements propres ; leurs modalités
|
||||
spécifiques doivent être présentées dans les services concernés.
|
||||
notamment par son formulaire de contact et par les fonctions
|
||||
d’authentification réservées aux comptes créés par l’administration. Les
|
||||
services hébergés sur d’autres adresses peuvent mettre en œuvre des
|
||||
traitements propres ; leurs modalités spécifiques doivent être présentées
|
||||
dans les services concernés.
|
||||
|
||||
À la date de cette notice, le site netig.net ne propose pas encore de
|
||||
création de compte utilisateur ni d’adhésion en ligne. Les informations
|
||||
relatives à ces fonctions seront ajoutées avant leur mise en service.
|
||||
À la date de cette notice, le site netig.net ne propose pas encore
|
||||
d’inscription publique ni de demande d’adhésion en ligne. Ces fonctionnalités
|
||||
et les traitements associés feront l’objet d’une mise à jour de la notice
|
||||
avant leur mise en service.
|
||||
|
||||
### Données traitées et finalités
|
||||
|
||||
@@ -115,10 +118,18 @@ Le formulaire de contact recueille le nom, l’adresse électronique, l’objet
|
||||
et le contenu du message. Ces informations sont utilisées pour répondre
|
||||
aux demandes et assurer le suivi des échanges.
|
||||
|
||||
Pour les comptes déjà créés, l’adresse électronique sert d’identifiant.
|
||||
Une empreinte du mot de passe est conservée pour permettre
|
||||
l’authentification ; le mot de passe n’est pas enregistré en clair. Les
|
||||
informations d’identité associées au compte, lorsqu’elles sont renseignées,
|
||||
peuvent comprendre le type de membre, le prénom, le nom ou la dénomination
|
||||
de la personne morale. Ces données sont utilisées pour gérer les comptes
|
||||
et l’administration du site.
|
||||
|
||||
Des données techniques nécessaires au fonctionnement et à la sécurité du
|
||||
site peuvent également être traitées, notamment dans les journaux du
|
||||
serveur. Leur nature et leur durée de conservation doivent être adaptées
|
||||
à leur utilité réelle.
|
||||
site peuvent également être traitées, notamment les données de session et
|
||||
les journaux du serveur. Leur nature et leur durée de conservation doivent
|
||||
être adaptées à leur utilité réelle.
|
||||
|
||||
Les données ne sont ni vendues ni utilisées à des fins publicitaires.
|
||||
|
||||
@@ -126,16 +137,19 @@ Les données ne sont ni vendues ni utilisées à des fins publicitaires.
|
||||
|
||||
Les messages sont traités dans le cadre de l’intérêt légitime à répondre
|
||||
aux sollicitations adressées au projet NETig et à assurer le suivi des
|
||||
échanges. Les données techniques nécessaires à la sécurité sont traitées
|
||||
dans l’intérêt légitime de protéger le site, les services et leurs
|
||||
utilisateurs.
|
||||
échanges. Les données nécessaires à l’authentification et à la gestion
|
||||
des comptes sont traitées dans l’intérêt légitime de sécuriser
|
||||
l’administration du site. Les données techniques nécessaires à la sécurité
|
||||
sont traitées dans l’intérêt légitime de protéger le site, les services
|
||||
et leurs utilisateurs.
|
||||
|
||||
### Destinataires et hébergement
|
||||
|
||||
Les messages sont transmis à l’adresse [contact@netig.net](mailto:contact@netig.net)
|
||||
et peuvent être consultés par les personnes habilitées à répondre aux
|
||||
demandes. Les données techniques peuvent être accessibles aux personnes
|
||||
chargées de l’administration des infrastructures et aux prestataires
|
||||
Les messages sont transmis à l’adresse
|
||||
[contact@netig.net](mailto:contact@netig.net) et peuvent être consultés par
|
||||
les personnes habilitées à répondre aux demandes. Les données des comptes
|
||||
et les données techniques peuvent être accessibles aux personnes habilitées
|
||||
à administrer le site et les infrastructures, ainsi qu’aux prestataires
|
||||
techniques concernés.
|
||||
|
||||
L’hébergement principal est assuré par Hetzner Online GmbH. Des sauvegardes
|
||||
@@ -147,12 +161,15 @@ Les messages reçus sont conservés dans la messagerie le temps nécessaire
|
||||
au traitement de la demande et au suivi des échanges, puis supprimés,
|
||||
sauf nécessité de conservation plus longue ou obligation légale.
|
||||
|
||||
Les journaux techniques et les sauvegardes peuvent conserver certaines
|
||||
données après leur suppression des systèmes actifs. Les durées de
|
||||
conservation effectivement appliquées doivent être précisées avant
|
||||
l’ouverture des services concernés :
|
||||
Les données des comptes sont conservées pendant la durée nécessaire à leur
|
||||
gestion et à la sécurisation du site. Les journaux techniques et les
|
||||
sauvegardes peuvent conserver certaines données après leur suppression des
|
||||
systèmes actifs. Les durées de conservation effectivement appliquées doivent
|
||||
être précisées avant l’ouverture des services concernés :
|
||||
|
||||
- **Messages de contact :** [durée à définir].
|
||||
- **Comptes et fiches associées :** [durée à définir].
|
||||
- **Données de session :** [durée à définir].
|
||||
- **Journaux techniques :** [durée à définir].
|
||||
- **Sauvegardes :** [durée de rétention à définir].
|
||||
|
||||
@@ -163,15 +180,15 @@ l’accès à vos données, leur rectification ou leur effacement, la limitation
|
||||
de leur traitement et vous opposer à certains traitements. Vous pouvez
|
||||
également demander la portabilité lorsque ce droit s’applique.
|
||||
|
||||
Pour exercer vos droits, écrivez à [contact@netig.net](mailto:contact@netig.net).
|
||||
Vous pouvez également introduire une réclamation auprès de la
|
||||
[CNIL](https://www.cnil.fr/).
|
||||
Pour exercer vos droits, écrivez à
|
||||
[contact@netig.net](mailto:contact@netig.net). Vous pouvez également
|
||||
introduire une réclamation auprès de la [CNIL](https://www.cnil.fr/).
|
||||
|
||||
### Cookies
|
||||
|
||||
Le site utilise des cookies techniques nécessaires au fonctionnement
|
||||
des sessions et à la sécurité. Ils ne sont pas utilisés à des fins de
|
||||
publicité ou de suivi de navigation.
|
||||
des sessions et à la sécurité, notamment pour l’authentification. Ils ne
|
||||
sont pas utilisés à des fins de publicité ou de suivi de navigation.
|
||||
|
||||
## Contact
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
class Netig
|
||||
private
|
||||
|
||||
def require_core_member!(r)
|
||||
rodauth.require_account
|
||||
|
||||
core_member = DB[:members]
|
||||
.join(:memberships, member_id: :id)
|
||||
.where(
|
||||
Sequel[:members][:account_id] => rodauth.account_id,
|
||||
Sequel[:members][:kind] => "individual",
|
||||
Sequel[:members][:core_member] => true,
|
||||
Sequel[:memberships][:status] => "accepted",
|
||||
Sequel[:memberships][:ended_at] => nil
|
||||
)
|
||||
.count
|
||||
.positive?
|
||||
|
||||
return if core_member
|
||||
|
||||
r.halt [
|
||||
403,
|
||||
{ "Content-Type" => "text/plain; charset=utf-8" },
|
||||
["Accès interdit."]
|
||||
]
|
||||
end
|
||||
end
|
||||
@@ -35,7 +35,8 @@ class Netig < Roda
|
||||
logout_redirect "/"
|
||||
end
|
||||
|
||||
require_relative "routes/admin"
|
||||
require_relative "lib/authorization"
|
||||
require_relative "routes/noyau"
|
||||
require_relative "routes/contact"
|
||||
|
||||
route do |r|
|
||||
|
||||
@@ -490,23 +490,23 @@ summary:focus-visible {
|
||||
/* Admin
|
||||
------------------------------------------------------------------------ */
|
||||
|
||||
.admin-table {
|
||||
.members-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.admin-table th,
|
||||
.admin-table td {
|
||||
.members-table th,
|
||||
.members-table td {
|
||||
padding: 10px 16px;
|
||||
border-bottom: 1px solid var(--color-shadow-light);
|
||||
}
|
||||
|
||||
.admin-table th {
|
||||
.members-table th {
|
||||
color: var(--color-highlight);
|
||||
}
|
||||
|
||||
.admin-table td {
|
||||
.members-table td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
class Netig
|
||||
hash_branch "admin" do |r|
|
||||
require_admin!(r)
|
||||
|
||||
@page_title = "Admin — NETig"
|
||||
@page_description = "Interface d'administration de NETig."
|
||||
@canonical_url = "https://netig.net/admin"
|
||||
|
||||
r.is do
|
||||
r.get do
|
||||
view "admin"
|
||||
end
|
||||
end
|
||||
|
||||
r.on "members" do
|
||||
r.is do
|
||||
r.get do
|
||||
@page_title = "Adhérents — Admin — NETig"
|
||||
|
||||
@members = DB[:members]
|
||||
.join(:accounts, id: :account_id)
|
||||
.select_all(:members)
|
||||
.select_append(Sequel[:accounts][:email].as(:email))
|
||||
.order(Sequel[:members][:id])
|
||||
.all
|
||||
|
||||
view "admin/members"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def require_admin!(r)
|
||||
rodauth.require_account
|
||||
|
||||
admin = DB[:members].where(
|
||||
account_id: rodauth.account_id,
|
||||
admin: true
|
||||
).get(:admin)
|
||||
|
||||
return if admin
|
||||
|
||||
r.halt [
|
||||
403,
|
||||
{ "Content-Type" => "text/plain; charset=utf-8" },
|
||||
["Accès interdit."]
|
||||
]
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,34 @@
|
||||
|
||||
class Netig
|
||||
hash_branch "noyau" do |r|
|
||||
require_core_member!(r)
|
||||
|
||||
@page_title = "Noyau — NETig"
|
||||
@page_description = "Espace de gestion de l'association NETig."
|
||||
@canonical_url = "https://netig.net/noyau"
|
||||
|
||||
r.is do
|
||||
r.get do
|
||||
view "noyau"
|
||||
end
|
||||
end
|
||||
|
||||
r.on "members" do
|
||||
r.is do
|
||||
r.get do
|
||||
@page_title = "Adhérents — Noyau — NETig"
|
||||
|
||||
@members = DB[:members]
|
||||
.join(:accounts, id: :account_id)
|
||||
.select_all(:members)
|
||||
.select_append(Sequel[:accounts][:email].as(:email))
|
||||
.order(Sequel[:members][:id])
|
||||
.all
|
||||
|
||||
view "noyau/members"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
+1
-2
@@ -113,8 +113,7 @@
|
||||
<section id="association" class="section-association">
|
||||
<div class="content">
|
||||
<h2>Aidez-nous à continuer !</h2>
|
||||
<p>Les services sont financés grâce à vos adhésions et vos dons. Votre soutien nous aide à couvrir les frais d'hébergement et à maintenir les services accessibles.</p>
|
||||
<a class="button" href="/temporary_page">Adhérer ➜</a>
|
||||
<p>Les services ne sont financés que par vos dons. Votre soutien nous aide à couvrir les frais d'hébergement et à maintenir les services accessibles.</p>
|
||||
<a class="button" href="/temporary_page">Faire un don ➜</a>
|
||||
</div>
|
||||
</section>
|
||||
@@ -1,9 +1,9 @@
|
||||
<section class="page-section">
|
||||
<div class="content">
|
||||
<h1>Administration de NETig</h1>
|
||||
<h1>Espace du Noyau</h1>
|
||||
|
||||
<p>
|
||||
<a class="button" href="/admin/members">
|
||||
<a class="button" href="/noyau/members">
|
||||
Gérer les adhérents
|
||||
</a>
|
||||
</p>
|
||||
@@ -5,13 +5,12 @@
|
||||
<% if @members.empty? %>
|
||||
<p>Aucun adhérent enregistré.</p>
|
||||
<% else %>
|
||||
<table class="admin-table">
|
||||
<table class="members-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Identité</th>
|
||||
<th>Type</th>
|
||||
<th>Adresse électronique</th>
|
||||
<th>Administration</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
@@ -28,7 +27,6 @@
|
||||
"Personne physique" : "Personne morale" %>
|
||||
</td>
|
||||
<td><%= member[:email] %></td>
|
||||
<td><%= member[:admin] ? "Oui" : "Non" %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
@@ -36,3 +34,4 @@
|
||||
<% end %>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
Reference in new issue
Block a user