Re(source)-Sharing
A comprehensive platform for organizations to share and book resources efficiently.
License: GPLv3
Overview
Re(source)-Sharing is a Django-based web application designed to facilitate resource sharing between organizations. The platform allows organizations to list their resources (such as rooms, equipment, vehicles, etc.) and make them available for booking by other organizations, with customizable restrictions, compensation options, and scheduling capabilities.
Key Features
- Resource Management: Create, update, and manage various types of resources with detailed descriptions and images
- Organization Management: Register and manage organizations with different activity areas and legal forms
- Booking System: Book resources with one-time or recurring schedules
- Compensation Options: Set up different compensation models for resource usage
- Access Control: Define who can access resources and when
- Restriction Management: Set restrictions on resource availability based on time or organization
- User Management: Manage users with different roles and permissions within organizations
- Email Notifications: Automated email notifications for booking confirmations, cancellations, etc.
Project Structure
The project is organized into several Django apps:
- users: User management and authentication
- resources: Resource definition, restrictions, and compensation models
- organizations: Organization management, permissions, and communication
- bookings: Booking management, scheduling, and messaging
Installation and Setup
Prerequisites
- Python 3.12+
- uv (package manager)
- PostgreSQL
- Git
Local Development Setup
-
Clone the repository:
git clone https://github.com/Haus-des-Engagements/re-sharing.git cd re-sharing -
Install uv (if not already installed):
curl -LsSf https://astral.sh/uv/install.sh | sh -
Install dependencies (uv will automatically create a virtual environment):
uv sync --extra dev export DJANGO_READ_DOT_ENV_FILE=true -
Set up the database:
createdb re-sharing uv run python manage.py migrate -
Create a superuser:
uv run python manage.py createsuperuser -
Run the development server:
uv run python manage.py runserver 0.0.0.0:8000
For more detailed setup instructions, see: https://cookiecutter-django.readthedocs.io/en/latest/developing-locally.html
Settings
For information about settings configuration, see: https://cookiecutter-django.readthedocs.io/en/latest/settings.html
Two-factor authentication
| Variable | Default | Meaning |
|---|---|---|
REQUIRE_STAFF_MFA |
True |
Staff, superusers and managers must set up two-factor authentication (authenticator app or passkey) before using the site. Set to False to switch off, e.g. locally. If a manager loses their device and recovery codes, delete their authenticator in the admin so they can set it up again. |
Agreements and SEPA direct debit
| Variable | Default | Meaning |
|---|---|---|
SEPA_CREDITOR_ID |
empty | Creditor identifier printed in pre-notifications and the SEPA file |
SEPA_CREDITOR_NAME |
empty | Creditor name in the SEPA file and on the generated mandate |
SEPA_CREDITOR_ADDRESS |
empty | Creditor address in one line, printed on the generated mandate |
SEPA_CREDITOR_IBAN / SEPA_CREDITOR_BIC |
empty | Account the debits are collected to |
SEPA_MANDATE_PREFIX |
RS |
Prefix of collection references; also marks bank transactions as possible returns |
SEPA_MANDATE_REFERENCE_PREFIX |
<SEPA_MANDATE_PREFIX>-VM |
Prefix of mandate references, followed by a running number: HDE-VM-009 continues after the highest existing HDE-VM number, so enter old paper mandates in the admin with their references first |
SEPA_RETURN_FEE |
0.00 |
Fee added to the invoice for a returned debit |
PRE_NOTIFICATION_DAYS |
14 |
Days between pre-notification and due date |
COLLECTION_LOOKAHEAD_DAYS |
45 |
How far ahead collections are created |
COLLECTION_RETURN_WINDOW_DAYS |
7 |
Days after the collection date until a debit counts as collected |
Basic Commands
Setting Up Your Users
*To create a normal user account, just go to Sign Up and fill out the form. Once you submit it, you'll see a "Verify Your E-mail Address" page. Go to your console to see a simulated email verification message. Copy the link into your browser. Now the user's email should be verified and ready to go.
- To create a superuser account:
uv run python manage.py createsuperuserFor convenience, you can keep your normal user logged in on Chrome and your superuser logged in on Firefox (or similar), so that you can see how the site behaves for both kinds of users.
Migrations
After you've made changes in a model, you have to propagate your changes to the database:
- Create new migrations:
uv run python manage.py makemigrations [app_label] - Apply migrations:
uv run python manage.py migrate [app_label]
[app_label] is optional.
Adding new apps
Our code is organised in so-called "apps", where we try to isolate functionalities and contexts:
Currently, we have the following apps:
- users
- bookings
- resources
- organizations
To create a new app, first create the new folder, then run: django-admin startapp newappname ./re-sharing/newappname.
Translations
To make strings available for translations in Django:
- Make gettext_lazy available as _:
from django.utils.translation import gettext_lazy as _ - Mark strings as translatable:
_('string to be translated) - Run
uv run python manage.py makemessages -l de(for German in this case) - Translate the strings now available in /locale/de/LC_MESSAGES/django.po
- Compile the .po file with
uv run python manage.py compilemessagesto a .mo file
Python packages
Dependencies are managed using uv and defined in pyproject.toml.
Adding or updating packages:
# Add a new dependency
uv add package-name
# Add a dev dependency
uv add --dev package-name
# Update all dependencies
uv lock --upgrade
# Sync dependencies after changes
uv sync --extra dev
The uv.lock file tracks exact versions and should be committed to version control.
Database
Postgres
Django connects to a Postgres Database. For local development a Postgres 16
container is defined in docker-compose.yml (listening on port 5433 to
avoid clashing with other local instances, data kept in a named volume):
docker compose up -d # start (data persists across restarts)
docker compose down # stop, keep data
docker compose down -v # stop and delete all data
Point Django at it with a .env file (read when DJANGO_READ_DOT_ENV_FILE=true):
DATABASE_URL=postgres://postgres:password@localhost:5433/re_sharing
To (re)create the database from a dump:
docker compose exec -T postgres pg_restore -U postgres -d re_sharing \
--clean --if-exists --no-owner --no-privileges < ~/Downloads/<dump>.dmp
uv run python manage.py migrate # apply migrations newer than the dump
Alternatively, without Docker, use a native Postgres and createdb re_sharing,
then run pg_restore / migrate against it in the same way.
Linting & Coding Style with Ruff
Before committing we locally verify the correct coding style with different tools. Ruff is a Python linter and code formatter, written in Rust. It is a aggregation of flake8, pylint, pyupgrade and many more.
Ruff comes with a linter uv run ruff check and a formatter uv run ruff format.
The linter is a wrapper around flake8, pylint, and other linters, and the formatter is a wrapper around black, isort, and other formatters.
Hint: You can also use an installed pre-commit hook with uv run pre-commit run --all-files, included:
- UV lock file sync
- Trim Trailing Whitespaces
- Fix end of files
- check Yaml
- Ruff linting and formatting
- djLint (indent html templates that contain django syntax correctly)
Testing
To run the tests, check your test coverage, and generate an HTML coverage report:
- Run tests without test coverage analysis:
uv run pytest
- If the database schema has changed, use
--create-db, as pytest will otherwise use the previous one (as it is much faster). - To see the slowest tests, use
--durations=10(to get the 10 slowest tests)
- Run test with test coverage analysis (and branch analysis) and create the html report:
uv run coverage run --branch -m pytest && uv run coverage html - You can find the report in
htmlcov/index.html.
Continuous Integration (CI)
To help keeping a good style, GitLab is running the following pipeline after pushing to the repository:
- pre-commit hook
- pytest
Usage Guide
For Organizations
Registering an Organization
- Create a user account and verify your email
- Navigate to the Organizations section and click "Register New Organization"
- Fill in the required information about your organization
- Submit the form and wait for admin approval
Managing Resources
- Once your organization is approved, navigate to the Resources section
- Click "Add New Resource" to register a resource for sharing
- Fill in the resource details, including:
- Name and description
- Resource type
- Availability schedule
- Access information
- Compensation requirements
- Upload images of the resource
- Set any restrictions on who can book the resource and when
- Publish the resource to make it available for booking
Managing Bookings
- Navigate to the Bookings section to view all booking requests for your resources
- Approve or reject booking requests
- Communicate with users through the messaging system
- View your booking calendar to see all upcoming bookings
Configuring the free bookings allowance
Organizations can be limited to a number of free bookings per calendar year (see ADR 0023). Deploying the code changes nothing; the restriction starts with this configuration in the admin:
- Flag the free room compensation with Counts against free bookings. The flag is not allowed on compensations with a rate.
- On every organization group that should be limited, set Free bookings per year and Free bookings limit valid from (for example 2027-01-01). Both fields have to be set together. Leave member, self-help and rental groups empty: a group without a number grants unlimited free bookings, and the most generous group wins.
- Create paid hourly compensations for the rooms that should stay bookable once the free bookings are used. Rooms without one become unbookable for limited organizations for the rest of the year.
- Do this when the announcement goes out: bookings starting on or after the valid-from date are priced against the allowance from that moment, earlier bookings are not touched.
Changes to the number, the date or the flag only affect bookings priced afterwards. Booking series created before the configuration keep today's pricing in the nightly extension until the transition command marks them as quota-priced. When confirming new organizations, check that an organization is not being split only to multiply its allowance.
Transition of bookings created before the quota
After the announcement grace period, bring the remaining legacy bookings of limited organizations under the quota with one command:
uv run python manage.py apply_free_bookings_quota --dry-run -v 2prints, per organization, which future bookings keep the remaining free bookings of their year (earliest dates first), which are charged with the cheapest paid compensation of the room, which are removed because the room has no paid compensation, and which series get the fallback and the quota marker. Nothing is changed.- Review the report and inform the affected organizations; the command sends no emails.
uv run python manage.py apply_free_bookings_quotaapplies it.--organizations slug ...restricts a run to some organizations, so it can be done in batches.
Running the command again is safe: a completed organization reports "nothing to do". Past and invoiced bookings are never touched.
For Users
Finding Resources
- Browse the Resources section to see available resources
- Use filters to narrow down resources by type, location, or availability
- Click on a resource to view detailed information
Booking Resources
- Select the resource you want to book
- Choose the date and time for your booking
- For recurring bookings, set the frequency and end date
- Submit your booking request
- Wait for approval from the resource owner
- Once approved, you'll receive access information for the resource
Contribution Guidelines
We welcome contributions to the Re(source)-Sharing project! Here's how you can contribute:
Reporting Issues
- Use the GitHub issue tracker to report bugs
- Provide detailed steps to reproduce the issue
- Include information about your environment
Contributing Code
- Fork the repository
- Create a new branch for your feature or bugfix
- Write tests for your changes
- Ensure all tests pass with
uv run pytest - Make sure your code follows our coding style (use
uv run ruff formatanduv run ruff check) - Submit a pull request with a clear description of your changes
Documentation
- Help improve the documentation by fixing typos or clarifying instructions
- Add examples and use cases to make the documentation more helpful
Production
Deployment
For production deployment, follow these steps:
- Set up a production server with the required dependencies
- Configure environment variables for production settings
- Set up a PostgreSQL database
- Set up Redis for caching
- Configure a web server (e.g., Nginx) and WSGI server (e.g., Gunicorn)
- Set up SSL certificates for secure connections
- Deploy the application code
- Run migrations and collect static files
- Start the application
Scheduled commands for agreements
Run these once a day, for example from cron:
# Create fee collections within the lookahead and send pre-notifications
15 6 * * * python manage.py create_agreement_collections
# Mark debits collected after the return window, detect returns, sync paid return invoices
30 2 * * * python manage.py sync_collection_payments
# End agreements whose end date has passed
45 0 * * * python manage.py end_expired_agreements
Rolling out agreements
- Deploy, set the SEPA settings listed under Settings and add the three scheduled commands.
- Create the agreement kinds in the admin. Each kind lists its application fields (key, label, type, required, help text, choices, minimum, order); answers are stored under the key, which cannot be changed once created. Deactivate a field instead of deleting it once agreements have answered it.
- Membership: yearly, the minimum amount, collection month 3 and the collection day, pre-notification "once with the approval", the member group, no accesses, no fields, applications open.
- Coworking: monthly, deposit required, notice period, the coworking group, the accesses of its entrance code, fields
desksandhours_per_week(whole numbers, minimum 1), applications open. - Office and cellar lease: monthly, fields
room(text) andarea_m2(decimal, minimum 1), applications closed until their mandates exist. - Upload the contract as a fillable PDF under "Contract template". Its form fields are filled by name when the contract is downloaded from the agreement page; the kind's page lists which fields the template has and which are filled. Names:
organization_name,organization_address,organization_phone,organization_email,organization_website,represented_by_person(checkbox),representative_name,representative_function,representative_email,amount,start_date,end_date,deposit_amount,kind_name, anddetail_<key>for the kind's application fields. Other fields stay empty for the signer. - The SEPA mandate is generated with the creditor data from the settings, the mandate reference and the bank details; it needs no upload.
- A kind's minimum amount binds applicants only; managers can enter lower amounts for existing agreements.
- Create and activate the email templates for the agreement emails (application received, manager notice, approved, rejected, ended, pre-notification, return invoice). The context offers
organization,agreement,kind,agreement_url,mandate_reference,creditor_id,creditor_name,first_collectionand, for collection emails,collection; bank details are never part of it. - Enter existing members and coworkers as active agreements, each with its paper mandate reference, signed contract and signing date: managers use "New agreement" under Manage agreements (status "Active", which adds the kind's group if missing), staff can also use the admin (which changes no groups). Neither creates collections for periods due before the agreement was entered, entrance codes or emails.
- The first yearly member run follows in the next collection cycle, monthly runs from the following month. Check the first returned debit against the matching in the nightly command.
- Rollback: remove the scheduled commands. The tables stay; registration and bookings are unaffected.
Sentry
Sentry is an error logging aggregator service. You can sign up for a free account at https://sentry.io/ or download and host it yourself. The system is set up with reasonable defaults, including 404 logging and integration with the WSGI application.
You must set the DSN url in production.