Collecting and presenting stembureaus: WaarIsMijnStemlokaal.nl
- Clone or download this project from GitHub:
- Copy
docker/docker-compose.yml.exampletodocker/docker-compose.ymland edit it- Fill in a password at
<DB_PASSWORD>
- Fill in a password at
- Copy
config.py.exampletoconfig.pyand edit it- Create a SECRET_KEY as per the instructions in the file
- Fill in your CKAN URL and CKAN API key
- Fill in the same
<DB_PASSWORD>as used indocker/docker-compose.yml - Specify the name(s) of the election(s) and its corresponding CKAN draft and publish resource IDs
- NOTE: Use the exact same
<name of election>values in the 'verkiezingen' field in 'app/data/gemeenten.json'
- NOTE: Use the exact same
- Specify email related information in order for the application to send emails
- Copy
app/data/gemeenten.json.exampletoapp/data/gemeenten.jsonand edit it- Fill in the email addresses of the gemeenten
- Add the name(s) of the election(s) for each gemeenten in which it participates. NOTE: make sure that these names are exactly the same as the name(s) of the election(s) in
app/config.py
- Buy and download the most recent 'BAG Adressen - Uitgebreid - CSV' from https://geotoko.nl/datasets?rid=24b6070d-5a92-4109-8fcd-a1d7cc000801 (NB: from the moment that gemeenten start to update the stembureaus till election day you need to buy and download the latest monthly released version of this file)
- download the 'bag-adressen-full-nl.csv.zip' file into
docker/docker-entrypoint-initdb.d/ unzip bag-adressen-full-laatst.csv.zipbag.sqlwill automatically load the data when docker starts for the first time; if you want to update the data later the you can simply go to thedockerfolder and runsudo ./update_bag.sh- Copy
docker/update_bag.sh.exampletodocker/update_bag.shand edit it- Fill in the same
<DB_PASSWORD>as used indocker/docker-compose.yml
- Fill in the same
- Copy
- download the 'bag-adressen-full-nl.csv.zip' file into
- Production
- Make sure to extract the latest MySQL backup in
docker/docker-entrypoint-initdb.dif you want to import it:gunzip latest-mysqldump-daily.sql.gz cd dockersudo docker-compose up -d- Compile the assets
- The
docker-compose upcommand above also loads the BAG data in MySQL, this can take more than 1 hour on a server (without SSD), so wait untilWaarIsMijnStemlokaal.nlloads without errors before continuing with the commands below - NOT NEEDED AS THIS DATA IS NOT UP TO DATE: Get buurt data:
sudo docker exec -it stm_app_1 /opt/stm/bin/get_address_data.sh - Set up daily backups for MySQL and CKAN
- Copy
docker/backup.sh.exampletodocker/backup.shand edit it- MySQL: Fill in the same
<DB_PASSWORD>as used indocker/docker-compose.yml - CKAN: Copy the CKAN backup command for each CKAN (concept) resource you want to backup and fill in the
<RESOURCE_ID>
- MySQL: Fill in the same
- To run manually use
sudo ./backup.sh - To set a daily cronjob at 03:46
sudo crontab -eand add the following line (change the path below to yourstembureaus/dockerdirectory path)46 3 * * * (cd <PATH_TO_stembureaus/docker> && sudo ./backup.sh)
- The resulting SQL backup files are saved in
docker/docker-entrypoint-initdb.dand the CKAN exports inexports
- Copy
- Make sure to extract the latest MySQL backup in
- Development; Flask debug will be turned on which automatically reloads any changes made to Flask files so you don't have to restart the whole application manually
- Make sure to extract the latest MySQL backup in
docker/docker-entrypoint-initdb.dif you want to import it:gunzip latest-mysqldump-daily.sql.gz cd dockersudo docker-compose -f docker-compose.yml -f docker-compose-dev.yml up -d- Compile the assets
- If you ran the
docker-compose upcommand above for the first time or if you removed thestm_stm-mysql-volumethen the BAG data will be loaded in MySQL, this can take something like 15 minutes (with an SSD), so wait untilWaarIsMijnStemlokaal.nlloads without errors before continuing with the commands below - NOT NEEDED AS THIS DATA IS NOT UP TO DATE: Get buurt data:
sudo docker exec -it stm_app_1 /opt/stm/bin/get_address_data.sh - Retrieve the IP address of the nginx container
sudo docker inspect stm_nginx_1and add it to your hosts file/etc/hosts:<IP_address> waarismijnstemlokaal.nl
- Make sure to extract the latest MySQL backup in
- Useful commands
- Run the tests:
sudo docker exec -it stm_app_1 nosetests - Remove and rebuild everything (this also removes the MySQL volume containing all gemeente, verkiezingen and BAG data (this is required if you want to load the .sql files from
docker/docker-entrypoint-initdb.dagain), but not the stembureaus data stored in CKAN)- Production:
sudo docker-compose down --rmi all && sudo docker volume rm stm_stm-mysql-volume && sudo docker-compose up -d - Development:
sudo docker-compose -f docker-compose.yml -f docker-compose-dev.yml down --rmi all && sudo docker volume rm stm_stm-mysql-volume && sudo docker-compose -f docker-compose.yml -f docker-compose-dev.yml up -d
- Production:
- Reload Nginx:
sudo docker exec stm_nginx_1 nginx -s reload - Reload uWSGI (only for production as development environment doesn't use uWSGI and automatically reloads changes):
touch uwsgi-touch-reload
- Run the tests:
- Install all packages (only need to run once after installation or when you change packages):
sudo docker exec stm_nodejs_1 yarn
Production
- Compile CSS/JS to
static/distdirectory:sudo docker exec stm_nodejs_1 yarn prod
Development
- Compile CSS/JS to
static/distdirectory (with map files):sudo docker exec stm_nodejs_1 yarn dev - Automatically compile CSS/JS when a file changes (simply refresh the page in your browser after a change):
sudo docker exec stm_nodejs_1 yarn watch
To access the CLI of the app run sudo docker exec -it stm_app_1 bash and run flask, flask ckan and flask mysql to see the available commands. Here are some CLI commands:
flask mysql add-admin-user <email>add a new admin user with the specified emailflask ckan add-new-datastore <ID_of_resource>add a new datastore in a CKAN resource; this needs to be run once after you've created a new CKAN resource, see Create new CKAN datasets and resources for new electionsflask mysql add-gemeenten-verkiezingen-usersadd all gemeenten, verkiezingen and users specified in 'app/data/gemeenten.json' to the MySQL database and send new users an invitation email
- If you want to add new elections, log in to https://data.waarismijnstemlokaal.nl/dashboard/datasets (until july 2025 this was: https://ckan.dataplatform.nl/dashboard/datasets) and click 'Dataset toevoegen'. Fill in the metadata (see earlier elections to see what to fill in). Make sure to create a 'concept' dataset besides the actual dataset. The concept dataset is used to store the stembureau data that isn't ready to be published yet.
- After filling the dataset information, click 'Data toevoegen' in order to add a new resource/bron.
sudo docker exec -it stm_mysql_1 bashmysql -p- Retrieve database password from
docker/docker-compose.ymland enter it in the prompt
- On development:
sudo docker-compose -f docker-compose.yml -f docker-compose-dev.yml build --pull nginxsudo docker-compose -f docker-compose.yml -f docker-compose-dev.yml up -d nginx
- On production:
sudo docker-compose build --pull nginxsudo docker-compose up -d nginx
- On development:
sudo docker-compose -f docker-compose.yml -f docker-compose-dev.yml build --pull appsudo docker-compose -f docker-compose.yml -f docker-compose-dev.yml up -d app
- On production:
sudo docker-compose build --pull appsudo docker-compose up -d app
sudo docker-compose pull mysqlsudo docker-compose up -d mysql- Note: if you change the major version of Mysql, then also change the version used in update_bag.sh(.example)
Use Fabric 2.x on your development machine to pull new changes from GitHub on a server and compile assets
fab deploy
If you try to visit WaarIsMijnStemlokaal.nl and get a '502 Bad Gateway', then open the console in your browser. If you see a message like (this is in Firefox):
The character encoding of the HTML document was not declared. The document will render with garbled text in some browser configurations if the document contains characters from outside the US-ASCII range. The character encoding of the page must be declared in the document or in the transfer protocol.
or if you see something like this in your Docker logs:
app_1 | invalid request block size: 21573 (max 4096)...skip nginx_1 | 2021/12/20 16:12:40 [error] 30#30: *1 upstream prematurely closed connection while reading response header from upstream, client: 172.18.0.1, server: waarismijnstemlokaal.nl, request: "GET / HTTP/1.1", upstream: "http://172.18.0.3:5000/", host: "waarismijnstemlokaal.nl"
then you are probably mixing up development and production images for the app and nginx services (to be precise, nginx uses a normal HTTP request in the development environment, but uses uwsgi in production). Stop and remove the app and nginx containers and remove the app and nginx images. Build again (use the --no-cache option) and make sure that you use sudo docker-compose -f docker-compose.yml -f docker-compose-dev.yml build --no-cache app nginx for development and simply sudo docker-compose build --no-cache app nginx for production.