The story of this project begins when, due to COVID-19, we have converted our regular office into a hybrid of regular and hot-desk assignments. We needed to find a solution for desk reservations, transparency of that, and detailed logging of who was in the office for epidemic purposes.
I've quickly evaluated a couple of existing solutions, but they were either too big and complicated and/or too expensive. As I assumed that other people would have the same challenge I had, I decided to spend my after-hours time making an open-source tailored system for the need. Yes - it is free as speech, not as beer.
- It allows people to book / change / unbook desks (or even parking stalls) in the office.
- It allows people to check who else will be in the office.
- It works on mobile.
- All is done in an easy, visual way.
- Generate a report of past bookings and export it to Excel file
- Seats can be limited to certain people, so other people cannot book them (it is called assigned seats).
- Seats can be disabled, so people don't see them at all.
- Multiple zones (maps) can be created, for example, floors or parking.
- Zones can be grouped. One person can have only one seat booked simultaneously in a zone group (so you can have one group for floors and another group for parking stalls).
- Admin(s) can book / modify / unbook seat for any user.
- Full admin interface to add/remove/edit maps, zones, groups, and users.
- SAML2.0 support - via Apache mod_auth_mellon module.
- Translations - currently, English and Polish are supported.
- Approvals - the main goal of the system was to make it autonomous and management-free. So I don't intend to implement approval flows.
- Timezone support - the selected time is always in the same timezone as a zone. It works well and is simple. But in case someone would like to have a couple of zones in different timezones and keep the
one person one seat at a given time
rule across these timezones, this will fail.
To be honest, I was not paying much attention to browser compatibility, nor was I extensively testing it on other browsers than Chrome and Firefox. Nevertheless, all modern browsers should be supported (definitely not IE).
It is so easy to run it via docker compose that I have removed the demo, which was available some time ago.
During the first run on an empty database, WARP will populate the database schema and create an admin user.
Default admin credentials are: admin:noneshallpass
The preferred way to deploy is to run it via Docker. You need a working docker, and I won't cover it here.
From the command line:
# clone the repository
$ git clone https://github.com/sebo-b/warp.git
$ cd warp
$ docker compose -f demo_compose.yaml up
After that, open http://127.0.0.1:8080 in your browser and log in as admin
with password noneshallpass
.
From the command line:
# clone the repository
$ git clone https://github.com/sebo-b/warp.git
$ cd warp
# build docker image (you can skip hash if you don't want to track it)
$ export GIT_HASH=`git log -1 --format=%h`
$ docker build -t warp:latest -t warp:$GIT_HASH .
# install postrgres (what I cover here is a simplistic way just to run a demo)
$ docker pull postgres
$ docker run --name warp-demo-db -e POSTGRES_PASSWORD=postgres_password -d postgres
$ export WARP_DEMO_DB_IP=`docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' warp-demo-db`
# start warp
$ docker run --name warp-demo-wsgi \
> --env 'WARP_DATABASE=postgresql://postgres:postgres_password@warp-demo-db:5432/postgres' \
> --env WARP_SECRET_KEY=mysecretkey \
> --env WARP_DATABASE_INIT_SCRIPT='["sql/schema.sql","sql/sample_data.sql"]' \
> --add-host=warp-demo-db:${WARP_DEMO_DB_IP} -d warp:latest
$ export WARP_DEMO_WSGI_IP=`docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' warp-demo-wsgi`
# install nginx as wsgi rewerse proxy
$ docker pull nginx
$ docker run --add-host=warp-demo-wsgi:${WARP_DEMO_WSGI_IP} --mount type=bind,source="$(pwd)"/res/nginx.conf,target=/etc/nginx/conf.d/default.conf,readonly -d -p 127.0.0.1:8080:80 nginx
After that, open http://127.0.0.1:8080 in your browser and log in as admin
with password noneshallpass
.
You need a working Python3 environment, Node.js, and PostgreSQL, and I won't cover it here. This is not a preferred way, use it only for debugging or development purposes. Things may change, and this section can be outdated - but I assume that you know what you are doing.
From the command line:
# clone repo
$ git clone https://github.com/sebo-b/warp.git
$ cd warp
# create virtual envirnoment and activate it
$ python3 -m venv --prompt warp .venv
$ source .venv/bin/activate
# install python requirements
# if this raises an error in psycopg2, either install its all build dependencies
# or change psycopg2 to psycopg2-binary in requirements.txt
$ pip install -r requirements.txt
# compile JavaScript files
$ pushd js
$ npm ci
$ npm run build
$ popd
# setup Flask and database URL
$ export FLASK_APP=warp
$ export FLASK_ENV=development
$ export WARP_DATABASE=postgresql://warp:warp@localhost:5432/warp
# run the app
$ flash run
After that, open http://127.0.0.1:5000 in your browser and log in as admin
with password noneshallpass
.
For the production envirnoment, I recommend running Nginx and PostgreSQL on separate VMs. Then (even multiple) WARP image can be simply started via Docker and rev-proxed from Nginx.
Each configuration parameter (check config.py) can be passed via the envirnoment as WARP_varname
.
For the production environment, make sure that you have generated SECRET_KEY
used for signing cookies. It is defined in config.py.
Flask documentation mentions this method to generate it:
$ python -c 'import os; print(os.urandom(16))'
Alternatively, you can use OpenSSL and Sed:
$ openssl rand -hex 16 | sed 's/\(..\)/\\x\1/g;s/^/b"/;s/$/"/'
or wrap it into Python:
$ python -c 'from subprocess import run; print(run(["openssl","rand","16"],capture_output=True).stdout)'
Change LANGUAGE_FILE
variable in config.py
or set WARP_LANGUAGE_FILE
environment variable. Currently, language is global for the instance.
You can add them manually one by one via the users' management tab or import them directly to the database. Basically, insert users to user
table, look at the table definition in warp/sql/schema.sql.
The role is one of:
10 - admin
20 - regular user
90 - account blocked
Password is a hash used by werkzeug.security.check_password_hash
(more documentation can be found here), by default (in my configuration) it is pbkdf2:sha256 with 16 bytes salt and 260,000 iterations.
You can generate it with Python (just make sure you have activated the environment where Flask is installed):
python -c 'from getpass import getpass; from werkzeug.security import generate_password_hash; print(generate_password_hash(getpass()))'
Oh.. I was not expecting that, but you can send a beer via PayPal: https://paypal.me/sebo271
Reach me out on my mail (git log is your friend), and we can discuss.