Imrpove migrations
This commit is contained in:
1 parent
f386499d2f
commit
4f28a59c7e
7 files changed
+187
-88
No files matched your search
@@ -3,8 +3,11 @@
|
|||||||
## À faire
|
## À faire
|
||||||
|
|
||||||
- limiter le spam sur `/contact/send`
|
- limiter le spam sur `/contact/send`
|
||||||
- développer les comptes utilisateurs et leur interface
|
- développer l'inscription des utilisateurs et la vérification des adresses électroniques
|
||||||
- afficher les recettes et dépenses sur la page d'accueil
|
- développer les demandes d'adhésion et leur examen par le Noyau
|
||||||
|
- développer l'espace personnel des adhérents
|
||||||
|
- 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
|
||||||
|
|
||||||
## Développement
|
## Développement
|
||||||
|
|
||||||
@@ -24,12 +27,22 @@ SMTP_PASSWORD=...
|
|||||||
Générer `SESSION_SECRET` avec `openssl rand -hex 64`.
|
Générer `SESSION_SECRET` avec `openssl rand -hex 64`.
|
||||||
Ne pas versionner le fichier `.env`.
|
Ne pas versionner le fichier `.env`.
|
||||||
|
|
||||||
Appliquer les migrations :
|
Créer ou mettre à jour la base de données :
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
bundle exec ruby bin/migrate
|
bundle exec ruby bin/migrate
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Lors de la première installation, créer le compte du premier administrateur :
|
||||||
|
|
||||||
|
```sh
|
||||||
|
bundle exec ruby bin/initialize-admin
|
||||||
|
```
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
Démarrer le serveur de développement :
|
Démarrer le serveur de développement :
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
@@ -44,12 +57,19 @@ bundle exec irb -r dotenv/load -r ./netig.rb
|
|||||||
|
|
||||||
## Production
|
## Production
|
||||||
|
|
||||||
Docker Compose fournit les variables d'environnement via `env_file`
|
Docker Compose fournit les variables d'environnement via `env_file` et définit
|
||||||
et définit `RACK_ENV=production`.
|
`RACK_ENV=production`.
|
||||||
|
|
||||||
Exécuter les migrations dans le conteneur applicatif avant de
|
Exécuter les migrations dans le conteneur applicatif avant de démarrer la
|
||||||
démarrer la nouvelle version :
|
nouvelle version :
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
bundle exec ruby bin/migrate
|
bundle exec ruby bin/migrate
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Lors de la première installation, créer le premier administrateur depuis le
|
||||||
|
conteneur applicatif :
|
||||||
|
|
||||||
|
```sh
|
||||||
|
bundle exec ruby bin/initialize-admin
|
||||||
|
```
|
||||||
@@ -42,6 +42,12 @@ abort "Opération annulée." unless %w[o oui].include?(
|
|||||||
console.gets&.strip&.downcase
|
console.gets&.strip&.downcase
|
||||||
)
|
)
|
||||||
|
|
||||||
|
verified_status_id = DB[:account_statuses]
|
||||||
|
.where(name: "Verified")
|
||||||
|
.get(:id)
|
||||||
|
|
||||||
|
abort "Statut Verified introuvable." unless verified_status_id
|
||||||
|
|
||||||
auth = Rodauth.lib do
|
auth = Rodauth.lib do
|
||||||
db DB
|
db DB
|
||||||
enable :create_account
|
enable :create_account
|
||||||
@@ -57,6 +63,10 @@ DB.transaction do
|
|||||||
|
|
||||||
account_id = auth.account_id_for_login(login: email)
|
account_id = auth.account_id_for_login(login: email)
|
||||||
|
|
||||||
|
DB[:accounts]
|
||||||
|
.where(id: account_id)
|
||||||
|
.update(status_id: verified_status_id)
|
||||||
|
|
||||||
DB[:members].insert(
|
DB[:members].insert(
|
||||||
account_id: account_id,
|
account_id: account_id,
|
||||||
kind: "individual",
|
kind: "individual",
|
||||||
|
|||||||
@@ -1,19 +1,68 @@
|
|||||||
Sequel.migration do
|
Sequel.migration do
|
||||||
up do
|
up do
|
||||||
|
create_table(:account_statuses) do
|
||||||
|
Integer :id, primary_key: true
|
||||||
|
String :name, null: false, unique: true
|
||||||
|
end
|
||||||
|
|
||||||
|
from(:account_statuses).import(
|
||||||
|
[:id, :name],
|
||||||
|
[
|
||||||
|
[1, "Unverified"],
|
||||||
|
[2, "Verified"],
|
||||||
|
[3, "Closed"]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
db = self
|
||||||
|
|
||||||
create_table(:accounts) do
|
create_table(:accounts) do
|
||||||
primary_key :id, type: :Bignum
|
primary_key :id, type: :Bignum
|
||||||
|
|
||||||
|
foreign_key :status_id, :account_statuses,
|
||||||
|
null: false,
|
||||||
|
default: 1
|
||||||
|
|
||||||
String :email, null: false
|
String :email, null: false
|
||||||
|
|
||||||
index :email, unique: true
|
if db.supports_partial_indexes?
|
||||||
|
index :email, unique: true, where: { status_id: [1, 2] }
|
||||||
|
else
|
||||||
|
index :email, unique: true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table(:account_password_hashes) do
|
create_table(:account_password_hashes) do
|
||||||
foreign_key :id, :accounts, primary_key: true, type: :Bignum
|
foreign_key :id, :accounts,
|
||||||
|
primary_key: true,
|
||||||
|
type: :Bignum
|
||||||
|
|
||||||
String :password_hash, null: false
|
String :password_hash, null: false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
create_table(:account_verification_keys) do
|
||||||
|
foreign_key :id, :accounts,
|
||||||
|
primary_key: true,
|
||||||
|
type: :Bignum
|
||||||
|
|
||||||
|
String :key, null: false
|
||||||
|
|
||||||
|
DateTime :requested_at,
|
||||||
|
null: false,
|
||||||
|
default: Sequel::CURRENT_TIMESTAMP
|
||||||
|
|
||||||
|
DateTime :email_last_sent,
|
||||||
|
null: false,
|
||||||
|
default: Sequel::CURRENT_TIMESTAMP
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
down do
|
down do
|
||||||
drop_table(:account_password_hashes, :accounts)
|
drop_table(
|
||||||
|
:account_verification_keys,
|
||||||
|
:account_password_hashes,
|
||||||
|
:accounts,
|
||||||
|
:account_statuses
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -12,6 +12,8 @@ Sequel.migration do
|
|||||||
String :last_name
|
String :last_name
|
||||||
String :organization_name
|
String :organization_name
|
||||||
|
|
||||||
|
TrueClass :admin, null: false, default: false
|
||||||
|
|
||||||
index :account_id, unique: true
|
index :account_id, unique: true
|
||||||
|
|
||||||
constraint :members_kind_valid,
|
constraint :members_kind_valid,
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
Sequel.migration do
|
|
||||||
up do
|
|
||||||
alter_table(:members) do
|
|
||||||
add_column :admin, TrueClass, null: false, default: false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
down do
|
|
||||||
alter_table(:members) do
|
|
||||||
drop_column :admin
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
Sequel.migration do
|
||||||
|
up do
|
||||||
|
create_table(:memberships) do
|
||||||
|
primary_key :id, type: :Bignum
|
||||||
|
|
||||||
|
foreign_key :member_id, :members,
|
||||||
|
type: :Bignum,
|
||||||
|
null: false
|
||||||
|
|
||||||
|
String :status, null: false, default: "pending"
|
||||||
|
|
||||||
|
DateTime :requested_at,
|
||||||
|
null: false,
|
||||||
|
default: Sequel::CURRENT_TIMESTAMP
|
||||||
|
|
||||||
|
DateTime :decided_at
|
||||||
|
|
||||||
|
foreign_key :recorded_by, :members,
|
||||||
|
type: :Bignum
|
||||||
|
|
||||||
|
DateTime :ended_at
|
||||||
|
String :end_reason
|
||||||
|
|
||||||
|
index :status
|
||||||
|
|
||||||
|
# Un seul dossier en attente ou une seule adhésion
|
||||||
|
# en cours par adhérent.
|
||||||
|
index :member_id,
|
||||||
|
unique: true,
|
||||||
|
where: { status: ["pending", "accepted"], ended_at: nil }
|
||||||
|
|
||||||
|
constraint :memberships_status_valid,
|
||||||
|
Sequel.lit("status IN ('pending', 'accepted', 'rejected')")
|
||||||
|
|
||||||
|
constraint :memberships_decision_consistent,
|
||||||
|
Sequel.lit(
|
||||||
|
"(status = 'pending' AND decided_at IS NULL " \
|
||||||
|
"AND recorded_by IS NULL) " \
|
||||||
|
"OR (status IN ('accepted', 'rejected') " \
|
||||||
|
"AND decided_at IS NOT NULL AND recorded_by IS NOT NULL)"
|
||||||
|
)
|
||||||
|
|
||||||
|
constraint :memberships_end_consistent,
|
||||||
|
Sequel.lit(
|
||||||
|
"(ended_at IS NULL AND end_reason IS NULL) " \
|
||||||
|
"OR (status = 'accepted' AND ended_at IS NOT NULL " \
|
||||||
|
"AND end_reason IN ('resignation', 'death', " \
|
||||||
|
"'dissolution', 'exclusion'))"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
down do
|
||||||
|
drop_table(:memberships)
|
||||||
|
end
|
||||||
|
end
|
||||||
+40
-65
@@ -28,30 +28,26 @@ Ses principes sont :
|
|||||||
- le partage ouvert des savoirs et des compétences informatiques.
|
- le partage ouvert des savoirs et des compétences informatiques.
|
||||||
|
|
||||||
L'association est sans but lucratif. Ses services sont proposés sans
|
L'association est sans but lucratif. Ses services sont proposés sans
|
||||||
facturation liée à leur utilisation. Ses ressources, notamment les
|
facturation liée à leur utilisation. Les dons volontaires contribuent au
|
||||||
cotisations des membres et les dons volontaires, servent à financer et
|
financement des infrastructures et à la pérennité des services. L’association
|
||||||
pérenniser ses infrastructures. Aucun bénéfice n’est distribué aux membres.
|
invite les membres et les utilisateurs qui le peuvent à la soutenir
|
||||||
|
financièrement, selon leurs moyens. Cette participation est importante pour
|
||||||
|
assurer la continuité des services. Les dons sont libres, sans contrepartie
|
||||||
|
et ne conditionnent ni l’adhésion, ni les droits des membres, ni l’accès aux
|
||||||
|
services. Aucun bénéfice n’est distribué aux membres.
|
||||||
|
|
||||||
## Article 3 — Adhésion
|
## Article 3 — Adhésion
|
||||||
|
|
||||||
Peut adhérer toute personne physique ou morale acceptant les statuts et
|
Peut adhérer toute personne physique ou morale acceptant les statuts et
|
||||||
les principes de l’association. Le Noyau examine les demandes.
|
les principes de l’association. Le Noyau examine les demandes et décide
|
||||||
|
de l’admission.
|
||||||
|
|
||||||
L’Assemblée générale (ci-après « AG ») fixe la cotisation annuelle. Après
|
L’adhésion prend effet à la date de son acceptation et est valable sans
|
||||||
acceptation et paiement, l’adhésion dure un an et se renouvelle à chaque
|
limitation de durée. Aucune cotisation ni aucun don n’est exigé pour adhérer,
|
||||||
échéance si la cotisation est payée. Un paiement anticipé ou effectué
|
conserver la qualité de membre ou exercer les droits qui y sont attachés.
|
||||||
pendant le délai de relance ne change pas l’échéance.
|
|
||||||
|
|
||||||
En cas d’impayé, une relance laisse trente jours pour payer. L’adhésion
|
L’adhésion prend fin par démission notifiée, décès, dissolution de la
|
||||||
est maintenue pendant ce délai, mais le membre n’est plus à jour de sa
|
personne morale ou exclusion (article 7).
|
||||||
cotisation : il ne peut pas voter en AG et ses accès aux services réservés
|
|
||||||
aux membres à jour peuvent être suspendus par le Noyau ou le responsable
|
|
||||||
du service. À défaut de paiement à l’expiration du délai, l’adhésion prend fin.
|
|
||||||
|
|
||||||
L’adhésion prend également fin par démission notifiée, décès, dissolution
|
|
||||||
de la personne morale ou exclusion (article 7). La démission n’annule pas
|
|
||||||
l'obligation de régler les cotisations en retard ni celle due pour l’année
|
|
||||||
en cours.
|
|
||||||
|
|
||||||
## Article 4 — Assemblée générale
|
## Article 4 — Assemblée générale
|
||||||
|
|
||||||
@@ -89,22 +85,21 @@ modifications statutaires et à la dissolution.
|
|||||||
|
|
||||||
### Voix et procurations
|
### Voix et procurations
|
||||||
|
|
||||||
Chaque membre à jour de sa cotisation, personne physique ou morale,
|
Chaque membre, personne physique ou morale, dispose d’une voix délibérative.
|
||||||
dispose d’une voix. La voix d’une personne morale est exercée par son
|
La voix d’une personne morale est exercée par son représentant habilité.
|
||||||
représentant habilité. Une personne physique également membre à titre
|
Une personne physique également membre à titre personnel qui représente
|
||||||
personnel qui représente une ou plusieurs personnes morales membres
|
une ou plusieurs personnes morales membres exerce une voix en son nom et
|
||||||
exerce une voix en son nom et une voix pour chacune d’elles.
|
une voix pour chacune d’elles.
|
||||||
|
|
||||||
Tout membre à jour peut se faire représenter par un membre personne
|
Tout membre peut se faire représenter par un membre personne physique.
|
||||||
physique à jour. Une personne morale donne procuration par son
|
Une personne morale donne procuration par son représentant habilité.
|
||||||
représentant habilité. Une même personne peut détenir au plus deux
|
Une même personne peut détenir au plus deux procurations, en plus des voix
|
||||||
procurations, en plus des voix qu’elle exerce en son nom ou comme
|
qu’elle exerce en son nom ou comme représentant d’une ou plusieurs personnes
|
||||||
représentant d’une ou plusieurs personnes morales.
|
morales.
|
||||||
|
|
||||||
Les voix délibératives sont celles des membres à jour de leur cotisation.
|
Chaque voix délibérative compte séparément pour le calcul des seuils et des
|
||||||
Chaque voix délibérative compte séparément pour le calcul des seuils et
|
quorums prévus par les statuts ; les fractions sont arrondies à l’entier
|
||||||
des quorums prévus par les statuts ; les fractions sont arrondies à
|
supérieur.
|
||||||
l’entier supérieur.
|
|
||||||
|
|
||||||
### Décisions
|
### Décisions
|
||||||
|
|
||||||
@@ -224,9 +219,9 @@ principes de l’article 2 ni modifier les statuts.
|
|||||||
|
|
||||||
## Article 6 — Ressources et comptabilité
|
## Article 6 — Ressources et comptabilité
|
||||||
|
|
||||||
Les ressources comprennent les cotisations, dons, subventions, recettes
|
Les ressources comprennent les dons volontaires, les subventions, les
|
||||||
d’activités compatibles avec l’objet et les principes de l’association
|
recettes d’activités compatibles avec l’objet et les principes de
|
||||||
et toute autre ressource autorisée par la loi.
|
l’association et toute autre ressource autorisée par la loi.
|
||||||
|
|
||||||
Les fonctions sont bénévoles. Les frais engagés pour l’association peuvent
|
Les fonctions sont bénévoles. Les frais engagés pour l’association peuvent
|
||||||
être remboursés sur justificatifs, selon les modalités du Noyau. Nul ne
|
être remboursés sur justificatifs, selon les modalités du Noyau. Nul ne
|
||||||
@@ -318,14 +313,14 @@ substantielle impose une nouvelle AG et fait repartir le délai de
|
|||||||
trente jours.
|
trente jours.
|
||||||
|
|
||||||
La première AG ne délibère que si deux tiers au moins des voix
|
La première AG ne délibère que si deux tiers au moins des voix
|
||||||
délibératives des membres à jour sont présentes ou représentées. À
|
délibératives sont présentes ou représentées. À défaut de quorum, une
|
||||||
défaut de quorum, une seconde AG est convoquée par le Noyau ou, si la
|
seconde AG est convoquée par le Noyau ou, si la première AG a été
|
||||||
première AG a été convoquée par des membres, par ces mêmes membres.
|
convoquée par des membres, par ces mêmes membres. Sa convocation est
|
||||||
Sa convocation est envoyée dans les quinze jours suivant le constat
|
envoyée dans les quinze jours suivant le constat de l’absence de quorum.
|
||||||
de l’absence de quorum. Elle se tient au moins quinze jours après
|
Elle se tient au moins quinze jours après l’envoi de sa convocation.
|
||||||
l’envoi de sa convocation. Elle reprend le même ordre du jour et le même
|
Elle reprend le même ordre du jour et le même projet, et ne délibère
|
||||||
projet, et ne délibère valablement que si un tiers au moins des voix
|
valablement que si un tiers au moins des voix délibératives est présent
|
||||||
délibératives des membres à jour est présent ou représenté.
|
ou représenté.
|
||||||
|
|
||||||
Si le quorum de la seconde AG n’est pas atteint, le projet n’est pas
|
Si le quorum de la seconde AG n’est pas atteint, le projet n’est pas
|
||||||
adopté. Il peut être soumis à une nouvelle procédure dans les conditions
|
adopté. Il peut être soumis à une nouvelle procédure dans les conditions
|
||||||
@@ -334,31 +329,11 @@ du présent article.
|
|||||||
La modification ou la dissolution est adoptée à la majorité des deux
|
La modification ou la dissolution est adoptée à la majorité des deux
|
||||||
tiers des suffrages exprimés. Toutefois, toute modification statutaire
|
tiers des suffrages exprimés. Toutefois, toute modification statutaire
|
||||||
ayant pour effet d’augmenter les engagements des membres requiert
|
ayant pour effet d’augmenter les engagements des membres requiert
|
||||||
l’accord unanime de tous les membres, y compris ceux qui ne sont pas
|
l’accord unanime de tous les membres. Cet accord peut être recueilli
|
||||||
à jour de leur cotisation. Cet accord peut être recueilli par écrit
|
par écrit en dehors de l’AG.
|
||||||
en dehors de l’AG.
|
|
||||||
|
|
||||||
En cas de dissolution, l’AG désigne un ou plusieurs liquidateurs et
|
En cas de dissolution, l’AG désigne un ou plusieurs liquidateurs et
|
||||||
attribue l’actif net, après règlement des dettes, à un organisme à but
|
attribue l’actif net, après règlement des dettes, à un organisme à but
|
||||||
non lucratif poursuivant un objet compatible avec celui de NETig.
|
non lucratif poursuivant un objet compatible avec celui de NETig.
|
||||||
Aucun actif n’est distribué aux membres.
|
Aucun actif n’est distribué aux membres.
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Statuts adoptés par l’Assemblée générale constitutive.**
|
|
||||||
|
|
||||||
Fait à __________________________, le ____ / ____ / ______
|
|
||||||
|
|
||||||
**Signatures**
|
|
||||||
|
|
||||||
Nom : __________________________________________
|
|
||||||
|
|
||||||
Signature : _____________________________________
|
|
||||||
|
|
||||||
Nom : __________________________________________
|
|
||||||
|
|
||||||
Signature : _____________________________________
|
|
||||||
|
|
||||||
Nom : __________________________________________
|
|
||||||
|
|
||||||
Signature : _____________________________________
|
|
||||||
Reference in new issue
Block a user