Antragsgrün is an easy-to-use online tool for NGOs, political parties, and social initiatives to collaboratively discuss resolutions, party platforms, and amendments. It helps to manage candidacies and supports meetings by providing online votings, speaking lists, and many more features.
A number of organisations are using the tool successfully such as the federal association of the European and German Green Party, the German Federal Youth Council, the European Youth Forum or the National Council of German Women's Organizations. It can be easily adapted to a variety of scenarios.
Core functions:
# Using PHP8-packages from [deb.sury.org](https://deb.sury.org/):
apt-get install php8.3 php8.3-cli php8.3-fpm php8.3-intl php8.3-gd php8.3-mysql \
php8.3-opcache php8.3-curl php8.3-xml php8.3-mbstring php8.3-zip php8.3-iconv
Install the sources and dependencies from the repository:
git clone https://github.com/CatoTH/antragsgruen.git
cd antragsgruen
curl -sS https://getcomposer.org/installer | php
./composer.phar install --prefer-dist
npm install
npm run build
If you want to use the web-based installer (recommended):
touch config/INSTALLING
If you don't want to use the web-based installer:
cp config/config.template.json config/config.json
vi config/config.json # you're on your own now :-)
Set the permissions (example for Debian Linux):
sudo chown -R www-data:www-data web/assets
sudo chown -R www-data:www-data runtime
sudo chown -R www-data:www-data config #Can be skipped if you don't use the Installer
Jugendpresse Deutschland e.V. developed a container image, which is now maintained as an open source / collaborative project at github.com/devops-ansible/docker-antragsgruen.
The repository is maintained to run its workflows once a week to build the devopsansiblede/antragsgruen
image.
The latest contents of the master
branch will result in a dev_YYYYMMDD-HHII
image-tag with the build date and time mentioned as well as the development
image-tag.
The actual (new) releases by git tags in the official Motiontool repository are built into images as well. They result in the tags latest
being the latest (highest) released version, and semantic version partials mapping the corresponding versions, so vA.B.C
is the current patch level version, vA.B
is the latest released patch of the minor version, and vA
is the latest released patch of the major version.
You can find the container images published on DockerHub.
Site administrators of an installation will see an Update-Box on the right side of the administration page of a consultation. The box indicates if an update is available. If so, you can switch the whole installation into Update mode. While the update mode is active, the whole site will not be available to other users.
Once the update mode is active, the /update.php
script will be available to the site administrator. Here, the update can be performed in two to three steps:
Before using the updater, it is generally a good idea to back up all files and especially the database.
If you encounter any problem using the web-based updater, please consult the Update Troubleshooting FAQ.
config/INSTALLING
file./yii migrate
on the command line to apply database changesGenerating PDFs is performed by the PHP-Library TCPDF by default. In some cases, nicer and easier to customize PDFs can be generated though by using a separate command line tool to generate them. They need to be set up and configured by hand on the server though.
The PHP-processes need writing permissions to the folder.
If this is not possible, you need to specify an alternative writable folder by hand by adding the following line to the beginning of web/index.php
:
define("K_PATH_FONTS", "/path/to/writable/directory/");
If you run into the error "This PDF document probably uses a compression technique which is not supported by the free parser shipped with FPDI. (See https://www.setasign.com/fpdi-pdf-parser for more details)" and decide to use the commercial plugin, you can install the package using the following steps:
components/fpdi
, so there exists a subdirectory src
../composer.phar dump-autoload
After that, newer PDF files should be able to be parsed as well.
Variant 1, for a distribution with a reasonably recent version of Weasyprint (60+):
apt-get install weasyprint
Variant 2, installation using pip (requires Python 3 including VirtualEnv support):
python3 -m venv venv
source venv/bin/activate
pip install weasyprint
weasyprint --info
(Refer to: https://doc.courtbouillon.org/weasyprint/stable/first_steps.html#linux)
Add the following settings to your config.json (and adapt them to your needs):
{
"weasyprintPath": "/usr/bin/weasyprint"
}
Necessary packets on Linux (Debian):
apt-get install texlive-lang-german texlive-latex-base texlive-latex-recommended \
texlive-latex-extra texlive-humanities texlive-fonts-recommended \
texlive-xetex texlive-luatex poppler-utils
Necessary packets on Mac OS X:
Add the following settings to your config.json (and adapt them to your needs):
{
"lualatexPath": "/usr/bin/lualatexPath",
"pdfunitePath": "/usr/bin/pdfunite"
}
When LaTeX complains about scrlayer2.sty
not found, executing the SQL statement UPDATE texTemplate SET texLayout = REPLACE(texLayout, 'scrpage2', 'scrlayer-scrpage');
followed by clearing all caches (./yii cache/flush-all
) should fix this problem.
Super-Admins are administrators with some additional set of privileges not available to regular site administrators:
The list of super-admins cannot (on purpose) be changed using the Web-UI,
but has to be manually changed in the config/config.json
by adding and removing the user IDs in the adminUserIds
array.
Antragsgrün comes with built-in support for protecting user accounts from brute-force accounts. By default:
The default behavior of the CAPTCHA can be modified in the config.json
:
mode
indicates when a CAPTCHA is shown. The default throttle
requires it after three unsuccessful attempts, balancing security with trying not to bother users too much. always
always requires entering a CAPTCHA, never
disables it entirely.difficulty
defaults to normal
, which should be solvable by most users. To make it easier (no distortion of image), set it to easy
.ignoredIps
is a list of IP addresses that will never receive a CAPTCHA. This is often necessary on conventions where all delegates are sharing one WiFi IP address and unsuccessful login attempts of one delegate would otherwise trigger CAPTCHA-behavior for all others.{
"captcha": {
"mode": "always", // Options: "never", "throttle", "always"
"ignoredIps": [
"127.0.0.1",
"::1"
],
"difficulty": "easy" // Options: "easy", "normal"
}
}
By default, users have the option to secure their account with a TOTP-based second factor (supported by many apps like Authy, Google Authenticator, FreeOTP or password managers). Super-Admins can change this behavior on an per-user-basis:
The user administration of Antragsgrün can be connected to a SSO provider, for example using SAML. However, this is not part of the core distribution, as the requirements are typically too organization-specific.
To resize uploaded images in applications on the server side, and to enable uploading PDFs as images, ImageMagick needs to be installed as command line tool:
apt-get install imagemagick
should do the trick./etc/ImageMagick-6/policy.xml
and comment out <policy domain="coder" rights="none" pattern="PDF" />
if necessary.imageMagickPath
in config/config.json
.There are two ways to deploy multiple sites using one codebase, each site allowing multiple consultations. However, both of them are non-trivial.
If you want to use two completely different databases, or a different set of active plugins, you can create a separate config.json
for each installation and name them like config.db1.json
, config.db2.json
, etc. Which one is used on a request depends on the environment variable ANTRAGSGRUEN_CONFIG
that is provided to the PHP process. For example, to use config.db1.json
on the hostname db1.antragsgruen.local
on Apache, you can use the following line in the Apache configuration:
SetEnvIf Host "db1.antragsgruen.local" ANTRAGSGRUEN_CONFIG=/var/www/antragsgruen/config/config.db1.json
For command line commands, you can set this variable like this:
ANTRAGSGRUEN_CONFIG=/var/www/antragsgruen/config/config.db1.json ./yii database/migrate
Antragsgruen.de uses a site manager module on the home page that allows users to create their own sites using a web form. This is done using the multisideMode
and a plugin for the site manager. Relevant entries in the config.json
for this are:
{
"multisiteMode": true,
"siteSubdomain": null,
"domainPlain": "https://antragsgruen.de/",
"domainSubdomain": "https://<subdomain:[\\w_-]+>.antragsgruen.de/",
"plugins": ["antragsgruen_sites"]
}
Instead of "antragsgruen_sites", a custom plugin managing the authentication and authorization process and providing the custom home page is necessary for this use case. The default manager antragsgruen_sites can be used as an example for this
Redis can be used to cache the changes in amendments, user sessions, and many other aspects of the site. To enable redis, simply add a redis
configuration key to the config.json
and point it to your setup:
Add the following settings to your config.json (and adapt them to your needs):
{
"redis": {
"hostname": "localhost",
"port": 6379,
"database": 0,
"password": "mysecret" // optional
}
}
Antragsgrün already does a decent amount of caching by default, and even more when enabling Redis. An even more aggressive caching mode that caches some fully rendered HTML pages and PDFs can be enabled by enabling the following option in the config.json
:
{
"viewCacheFilePath": "/tmp/some-viewcache-directory/"
}
Note that this might in some edge case lead to old information being shown and is only meant as a last resort if hundreds to thousands of users are accessing large motions in parallel.
As a rule of thumb, this setting should be considered if you expect close to 1.000 motions and amendments or more in one consultation.
Some of the more advanced features of Antragsgrün need JWT signing set up. Right now, this is only the integration of the Live Server, but in the future this will also enable logged in access to the REST API.
First, a Public/Private key pair used for JWT authentication needs to be generated:
ssh-keygen -t rsa -b 4096 -m PEM -f bundle.pem
openssl rsa -in bundle.pem -pubout -outform PEM -out public.key
openssl pkcs8 -topk8 -inform PEM -outform PEM -in bundle.pem -out private.key -nocrypt
Move the keys to a safe place and point the jwtPrivateKey
parameter in config.json
to its absolute location, like:
{
"jwtPrivateKey": "/var/www/antragsgruen/config/jwt.key"
}
The optional Live Server can be installed to enable live updates for speaking lists (and potentially more components in the future).
As a prerequisite, JWT Signing needs to be enabled (see above). Then, the location of the RabbitMQ server, the credentials of the management API and the name of the exchange needs to configured, along with the absolute URI of the Websocket endpoint the Live Server exposes:
{
"live": {
"installationId": "std", // The ID identifying this installation at the Live Server
"wsUri": "ws://localhost:8080/websocket", // The full URI of the websocket endpoint of the Live Server
"stompJsUri": "http://localhost:8080/stomp.umd.min.js", // The full URI of a hosted StompJS library
"rabbitMqUri": "http://localhost:15672", // Base URI to the REST API of RabbitMQ
"rabbitMqExchangeName": "antragsgruen-exchange", // Created by the Live Server
"rabbitMqUsername": "guest", // Default username of RabbitMQ
"rabbitMqPassword": "guest" // Default password of RabbitMQ
}
}
You can enable debug mode by creating an empty file config/DEBUG.
To compile the JavaScript- and CSS-Files, you need to install Gulp:
npm install # Installs all required packages
npm run build # Compiles the regular JS/CSS-files
npm run watch # Listens for changes in JS/CSS-files and compiles them immediately
After updating the source code from git, do:
./composer.phar install
./yii migrate
gulp
npm install
gulp dist-install
viewer.html
and viewer.css
(look for "Antragsgrün" in the comments)The goal is to comply with both WCAG 2.0 AA and BITV2.0.
Testing is currently done the following ways:
$(element).on("click", ".subselecor", handler)
-listener that is actually targeted to dynamic child elements.Known limitations:
Module.php
which inherits from ModuleBase.php.controller
-subdirectory, the views in views
, custom commands need to be in a commands
-directory. A rather complex example containing a bit of everything can be seen in member_petitions.plugins
-list in the config.json
:{
"plugins": [
"mylayoutPlugin",
"someExtraBehavior"
]
}
The most frequent use case for plugins is custom themes / layouts. You can develop a custom theme using SASS/SCSS for Antragsgrün using the following steps:
Module.php
and Assets.php
. If your directory / plugin ID is mylayout
, the namespace of these classes needs to be app\plugins\mylayout
.Module.php
needs the static method getProvidedLayout
that returns the asset bundle. See the gruen_ci or neos for examples.plugins/mylayout/assets/mylayout.scss
. Again, use the existing plugins as an example to get the imports right.gulp
to compile the SCSS into CSSA hint regarding the AGPL license and themes: custom stylesheets and images and changes to the standard stylesheets of Antragsgrün do not have to be redistributed under an AGPL license like other changes to the Antragsgrün codebase.
Every single message in the user interface can be modified using the web-based translation tool, without having to use plugins. Just log in as admin and go to Settings -> Edit the language.
On larger setups, there might be a need to share language variants between different consultations or installations. In that case, it is possible to define language variants as plugin:
Module.php
and Assets.php
. If your directory / plugin ID is mylayout
, the namespace of these classes needs to be app\plugins\mylayout
.Module.php
needs the static method getProvidedMessagesForLanguage
that returns the languages that the plugin returns translations / adaptions for.messages/[language]
with the appropriate overrides, e.g. messages/en/motion.php
.An optional API is under development for Antragsgrün, extended by functionality as needed by external applications. Currently, starting with version 4.7.0, it gives read-only access to consultations, motions, amendments and the proposed procedure of consultations.
The API is disabled by default and can be enabled under "Settings" -> "Appearance and components of this site" -> "Enable the REST-API".
All endpoints of the API are located under /rest
. An OpenAPI-based description of the API can be found at docs/openapi.yaml. A SwaggerUI-based viewer of the documentation can be installed by uploading the swagger_ui plugin to /plugins/
and adding it to the list of plugins in config/config.json
.
antragsgruen_tests
) cp config/config_tests.template.json config/config_tests.json && vi config/config_tests.json
npm install
)test.antragsgruen.test
must point to localhost (by adding an entry to /etc/hosts) and a VirtualHost in your Apache/Nginx-Configuration pointing to the web/
-directory of this installation has to be configured. If another host name is to be used, it has to be changed in the config/TEST_DOMAIN and tests/acceptance.suite.yml.java -jar selenium-server-standalone-3.141.59.jar
vendor/bin/codecept run Acceptance
vendor/bin/codecept run Unit
vendor/bin/codecept run Unit --skip-group=database
vendor/bin/codecept run Acceptance motions/CreateCept
php -d memory_limit=1G vendor/bin/phpstan.phar analyse --configuration=phpstan.neon --generate-baseline
Suggested output: [OK] Baseline generated with 123 errors.
php -d memory_limit=1G vendor/bin/phpstan.phar analyse --configuration=phpstan.use-baseline.neon
Suggested output: [OK] No errors
If you found a security problem with Antragsgrün, please report it to: tobias@hoessl.eu. If you want to encrypt the mail, you can use this PGP-Key.