decidim: public example process + isoc participant seed

This commit is contained in:
Hernâni Marques 2026-08-17 15:38:43 +02:00
parent 609056615e
commit 03e5c0d3ad
No known key found for this signature in database
GPG key ID: CB5738652768F7E9
6 changed files with 186 additions and 0 deletions

View file

@ -31,3 +31,11 @@ Stock Decidim still emits `#dc-dialog-wrapper` (Accept all / essential / Setting
| listen | `:9027` `:9026` | | listen | `:9027` `:9026` |
login-health: probes + containers + linger + these units enabled. Loopback HTTP on :9027 is **301** (app wants HTTPS; TLS is Caddy). Probe allows 301. After reboot: login-health only unless asked. login-health: probes + containers + linger + these units enabled. Loopback HTTP on :9027 is **301** (app wants HTTPS; TLS is Caddy). Probe allows 301. After reboot: login-health only unless asked.
## Public example + isoc
- Process **example** (published, not private): `https://decidim.hacktivism.ch/processes/example`
- One published meeting in that process (readable without login).
- Homepage block `highlighted_processes` published.
- Participant `isoc` on the host (`users.env`); password not in this repo.
- Seed: `scripts/decidim/seed-example.sh` / `configs/decidim/seed_example.rb`.

View file

@ -11,3 +11,7 @@ SMTP_USERNAME=unused
SMTP_PASSWORD=unused SMTP_PASSWORD=unused
SMTP_PORT=25 SMTP_PORT=25
QUEUE_ADAPTER=sidekiq QUEUE_ADAPTER=sidekiq
DECIDIM_ISOC_EMAIL=isoc@hacktivism.ch
DECIDIM_ISOC_PASSWORD=@inline-secret@
DECIDIM_ISOC_NAME=isoc
DECIDIM_ISOC_NICKNAME=isoc

View file

@ -18,8 +18,11 @@ Privacy: no third-party trackers. Stock GDPR banner is hidden (`#dc-dialog-wrapp
cd ~/koopa-decidim && set -a && source .env && set +a && podman-compose up -d cd ~/koopa-decidim && set -a && source .env && set +a && podman-compose up -d
scripts/decidim/install-systemd.sh scripts/decidim/install-systemd.sh
scripts/decidim/apply-branding.sh scripts/decidim/apply-branding.sh
scripts/decidim/seed-example.sh # public process /processes/example + optional isoc user
``` ```
Public example (no account): `https://decidim.hacktivism.ch/processes/example`
Caddy: `sudo /home/hernani/koopa-caddy/apply.sh` Caddy: `sudo /home/hernani/koopa-caddy/apply.sh`
Daylog: `2026/2026-08-17--decidim.md`. Daylog: `2026/2026-08-17--decidim.md`.

View file

@ -44,6 +44,7 @@ services:
- ./theme/hacktivism.css:/code/public/hacktivism.css:ro - ./theme/hacktivism.css:/code/public/hacktivism.css:ro
- ./theme/hacktivism-consent.js:/code/public/hacktivism-consent.js:ro - ./theme/hacktivism-consent.js:/code/public/hacktivism-consent.js:ro
- ./bootstrap.rb:/code/lib/koopa_bootstrap.rb:ro - ./bootstrap.rb:/code/lib/koopa_bootstrap.rb:ro
- ./seed_example.rb:/code/lib/koopa_seed_example.rb:ro
- ./assets/img/logo.svg:/code/public/hacktivism-logo.svg:ro - ./assets/img/logo.svg:/code/public/hacktivism-logo.svg:ro
- ./assets/img/favicon.svg:/code/public/hacktivism-favicon.svg:ro - ./assets/img/favicon.svg:/code/public/hacktivism-favicon.svg:ro
- decidim-storage:/code/storage - decidim-storage:/code/storage

View file

@ -0,0 +1,139 @@
# frozen_string_literal: true
# Public example process + meeting (readable without an account).
# Optional participant from env: DECIDIM_ISOC_EMAIL / DECIDIM_ISOC_PASSWORD.
# Usage: bundle exec rails runner /code/lib/koopa_seed_example.rb
def t(en, de, fr)
{ "en" => en, "de" => de, "fr" => fr }
end
def html(en, de, fr)
t("<p>#{en}</p>", "<p>#{de}</p>", "<p>#{fr}</p>")
end
def fail_model!(record)
raise "#{record.class}: #{record.errors.full_messages.join("; ")}"
end
host = ENV.fetch("DECIDIM_HOST", "decidim.hacktivism.ch")
org = Decidim::Organization.find_by!(host: host)
admin = Decidim::User.find_by!(email: ENV.fetch("DECIDIM_ADMIN_EMAIL"), organization: org)
org.update!(force_users_to_authenticate_before_access_organization: false)
slug = "example"
process = Decidim::ParticipatoryProcess.find_or_initialize_by(organization: org, slug: slug)
process.assign_attributes(
title: t("Example activity", "Beispielaktivität", "Activité exemple"),
subtitle: t(
"Public demo — no account needed to read",
"Öffentliches Beispiel — Lesen ohne Konto",
"Démo publique — lecture sans compte"
),
short_description: html(
"A published participatory process so visitors can see Decidim without signing in.",
"Ein veröffentlichter Beteiligungsprozess, den Besucherinnen ohne Anmeldung lesen können.",
"Un processus participatif publié, lisible sans compte."
),
description: html(
"This is a small public example on hacktivism. Meetings and the process page are visible to anyone. Signing in is only needed to take part.",
"Kleines öffentliches Beispiel auf hacktivism. Prozessseite und Treffen sind für alle sichtbar. Anmelden nur zum Mitmachen.",
"Petit exemple public sur hacktivism. La page du processus et la rencontre sont visibles sans compte. La connexion sert uniquement à participer."
),
start_date: Date.current,
end_date: Date.current + 180,
published_at: process.published_at || Time.current,
private_space: false,
promoted: true,
scopes_enabled: false,
weight: 1
)
process.save || fail_model!(process)
puts "process id=#{process.id} slug=#{process.slug} published=#{process.published_at}"
step = process.steps.find_or_initialize_by(position: 1)
step.assign_attributes(
title: t("Open", "Offen", "Ouvert"),
description: html("Example step.", "Beispielphase.", "Étape exemple."),
start_date: Date.current,
end_date: Date.current + 180,
active: true
)
step.save || fail_model!(step)
puts "step id=#{step.id} active=#{step.active}"
meetings = Decidim::Component.find_or_initialize_by(
participatory_space: process,
manifest_name: "meetings"
)
meetings.assign_attributes(
name: t("Meetings", "Treffen", "Rencontres"),
published_at: meetings.published_at || Time.current,
visible: true,
weight: 1
)
meetings.save || fail_model!(meetings)
puts "meetings component id=#{meetings.id} published=#{meetings.published_at}"
start_at = Time.current.utc.change(hour: 18, min: 0) + 7.days
finish_at = start_at + 2.hours
meeting = Decidim::Meetings::Meeting.find_or_initialize_by(
component: meetings,
author: admin
)
if meeting.new_record? || meeting.title.blank?
meeting.title = t("Open example meeting", "Offenes Beispieltreffen", "Rencontre exemple ouverte")
end
meeting.assign_attributes(
description: html(
"Anyone can open this meeting page without an account. It is a demo activity on decidim.hacktivism.ch.",
"Diese Treffen-Seite ist ohne Konto lesbar. Beispielaktivität auf decidim.hacktivism.ch.",
"Cette page de rencontre est lisible sans compte. Activité exemple sur decidim.hacktivism.ch."
),
start_time: meeting.start_time || start_at,
end_time: meeting.end_time || finish_at,
address: "hacktivism",
location: t("Online / public", "Online / öffentlich", "En ligne / public"),
location_hints: t("No registration required to read.", "Zum Lesen keine Anmeldung.", "Pas d'inscription pour lire."),
type_of_meeting: "in_person",
registration_type: "registration_disabled",
registrations_enabled: false,
private_meeting: false,
transparent: true,
published_at: meeting.published_at || Time.current,
comments_enabled: true
)
meeting.save || fail_model!(meeting)
puts "meeting id=#{meeting.id} published=#{meeting.published_at} start=#{meeting.start_time}"
block = Decidim::ContentBlock.find_or_initialize_by(
organization: org,
scope_name: "homepage",
manifest_name: "highlighted_processes"
)
block.weight ||= 45
block.published_at ||= Time.current
block.save || fail_model!(block)
puts "homepage highlighted_processes published=#{block.published_at}"
isoc_email = ENV["DECIDIM_ISOC_EMAIL"].to_s.strip
isoc_password = ENV["DECIDIM_ISOC_PASSWORD"].to_s
if isoc_email.empty? || isoc_password.empty?
puts "isoc user skipped (DECIDIM_ISOC_EMAIL / DECIDIM_ISOC_PASSWORD unset)"
else
isoc = Decidim::User.find_or_initialize_by(email: isoc_email, organization: org)
isoc.name = ENV.fetch("DECIDIM_ISOC_NAME", "isoc")
isoc.nickname = ENV.fetch("DECIDIM_ISOC_NICKNAME", "isoc")
isoc.password = isoc_password
isoc.password_confirmation = isoc_password
isoc.admin = false
isoc.confirmed_at ||= Time.current
isoc.tos_agreement = true
isoc.accepted_tos_version = org.tos_version
isoc.locale = org.default_locale
isoc.save || fail_model!(isoc)
puts "isoc user id=#{isoc.id} email=#{isoc.email} nick=#{isoc.nickname} admin=#{isoc.admin} confirmed=#{isoc.confirmed_at}"
end
puts "public process: https://#{host}/processes/#{process.slug}"
puts "public meeting: https://#{host}/processes/#{process.slug}/f/#{meetings.id}/meetings/#{meeting.id}"

31
scripts/decidim/seed-example.sh Executable file
View file

@ -0,0 +1,31 @@
#!/usr/bin/env bash
# Publish public example process/meeting + optional isoc user from users.env.
set -euo pipefail
cd "${HOME}/koopa-decidim"
set -a
# shellcheck disable=SC1091
source .env
# shellcheck disable=SC1091
source users.env
set +a
src=""
if [ -f "${HOME}/src/koopa/koopa-admin-log/configs/decidim/seed_example.rb" ]; then
src="${HOME}/src/koopa/koopa-admin-log/configs/decidim/seed_example.rb"
elif [ -f ./seed_example.rb ]; then
src="./seed_example.rb"
else
echo "ERROR: seed_example.rb not found" >&2
exit 1
fi
podman cp "${src}" koopa-decidim:/code/lib/koopa_seed_example.rb
podman exec \
-e DECIDIM_HOST="${DECIDIM_HOST:-decidim.hacktivism.ch}" \
-e DECIDIM_ADMIN_EMAIL \
-e DECIDIM_ISOC_EMAIL \
-e DECIDIM_ISOC_PASSWORD \
-e DECIDIM_ISOC_NAME \
-e DECIDIM_ISOC_NICKNAME \
koopa-decidim bundle exec rails runner /code/lib/koopa_seed_example.rb
echo "seed done. public: https://decidim.hacktivism.ch/processes/example"