Merge branch 'main' into MK/iban_checks
@ -1,8 +1,12 @@
|
||||
build-test:
|
||||
cd docker/test; docker compose build
|
||||
|
||||
test:
|
||||
touch docker/test/coverage.xml
|
||||
chmod 666 docker/test/coverage.xml
|
||||
test: build-test
|
||||
mkdir -p docker/test/htmlcov
|
||||
chmod 777 docker/test/htmlcov
|
||||
ifeq ($(keepdb), true)
|
||||
cd docker/test; DJANGO_TEST_KEEPDB=1 docker compose up --abort-on-container-exit
|
||||
else
|
||||
cd docker/test; docker compose up --abort-on-container-exit
|
||||
sed -i 's/\/app\/jdav_web/jdav_web/g' docker/test/coverage.xml
|
||||
endif
|
||||
echo "Generated coverage report. To read it, point your browser to:\n\nfile://$$(pwd)/docker/test/htmlcov/index.html"
|
||||
|
||||
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 249 KiB |
|
After Width: | Height: | Size: 251 KiB |
@ -0,0 +1,20 @@
|
||||
:orphan: true
|
||||
|
||||
.. meta::
|
||||
:description: Miscellaneous information about the Kompass project
|
||||
|
||||
.. vale off
|
||||
|
||||
About
|
||||
=====
|
||||
|
||||
.. rst-class:: lead
|
||||
|
||||
.. attention::
|
||||
Die Seite befindet sich noch im Aufbau. -- The page is still under construction.
|
||||
|
||||
(Stand: 08.01.2025)
|
||||
|
||||
|
||||
- About the kompass project
|
||||
- About this documentation
|
||||
@ -0,0 +1,7 @@
|
||||
.. _development_manual/architecture:
|
||||
|
||||
=================
|
||||
Architecture
|
||||
=================
|
||||
|
||||
tbd
|
||||
@ -0,0 +1,85 @@
|
||||
.. _development_manual/contributing:
|
||||
|
||||
============
|
||||
Contributing
|
||||
============
|
||||
|
||||
Any form of contribution is appreciated. If you found a bug or have a feature request, please file an
|
||||
`issue <https://git.jdav-hd.merten.dev/digitales/kompass/issues>`_. If you want to help with the documentation or
|
||||
want to contribute code, please open a `pull request <https://git.jdav-hd.merten.dev/digitales/kompass/pulls>`_.
|
||||
|
||||
.. note::
|
||||
|
||||
Please read this page carefully before contributing.
|
||||
|
||||
Miscellaneous
|
||||
-------------
|
||||
|
||||
- version control with `git <https://git-scm.com/>`_
|
||||
- own gitea instance at https://git.jdav-hd.merten.dev/
|
||||
- protected ``main`` branch
|
||||
|
||||
Organization and branches
|
||||
-------------------------
|
||||
|
||||
The stable development happens on the ``main``-branch for which only maintainers have write access. Any pull request
|
||||
should hence be targeted at ``main``. Regularly, the production instances are updated to the latest ``main`` version,
|
||||
in particular these are considered to be stable.
|
||||
|
||||
If you have standard write access to the repository, feel free to create new branches. To make organization
|
||||
easier, please follow the branch naming convention: ``<username>/<feature>``.
|
||||
|
||||
The ``testing``-branch is deployed on the development instances. No development should happen there, this branch
|
||||
is regularly reset to the ``main``-branch.
|
||||
|
||||
|
||||
Workflow
|
||||
--------
|
||||
|
||||
- request a gitea account from the project maintainers
|
||||
- decide on an `issue <https://git.jdav-hd.merten.dev/digitales/kompass/issues>`_ to work on or create a new one
|
||||
- branch out to an own branch (naming convention: ``<username>/<feature>``) from the ``main``-branch
|
||||
- work on the issue and commit your changes
|
||||
- create a pull request from your branch to the ``main``-branch
|
||||
|
||||
|
||||
.. _development_manual/contributing/documentation:
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
If you want to contribute to the documentation, please follow the steps below.
|
||||
|
||||
Online (latest release version): https://jdav-hd.de/static/docs/
|
||||
|
||||
- This documentation is build `sphinx <https://www.sphinx-doc.org/>`_ and `awsome sphinx theme <https://sphinxawesome.xyz/>`_ the source code is located in ``docs/``.
|
||||
- All documentation is written in `reStructuredText <https://www.sphinx-doc.org/en/master/usage/restructuredtext/index.html>`_ and uses the `sphinx directives <https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html>`_.
|
||||
- The directives can vary due to the theme, see the `awesome sphinx theme documentation <https://sphinxawesome.xyz/demo/notes/>`_.
|
||||
- All technical documentation is written in english, user documentation is written in german.
|
||||
|
||||
To read the documentation build it locally and view it in your browser:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd docs/
|
||||
make html
|
||||
|
||||
# MacOS (with firefox)
|
||||
open -a firefox $(pwd)/docs/build/html/index.html
|
||||
# Linux (I guess?!?)
|
||||
firefox ${pwd}/docs/build/html/index.html
|
||||
|
||||
Code
|
||||
----
|
||||
|
||||
If you want to contribute code, please follow the inital setup steps in the :ref:`development_manual/setup` section. And dont forget to :ref:`document <development_manual/contributing/documentation>` your code properly and write tests.
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
Still open / to decide:
|
||||
|
||||
- linting
|
||||
- (auto) formatting
|
||||
- reliable tests via ci/cd pipeline
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
.. _development_manual/deployment:
|
||||
|
||||
=====================
|
||||
Production Deployment
|
||||
=====================
|
||||
|
||||
tbd
|
||||
@ -0,0 +1,42 @@
|
||||
.. _development_manual/index:
|
||||
|
||||
#########################
|
||||
Development Documentation
|
||||
#########################
|
||||
|
||||
This part of the documentation describes the development and maintenance of the Kompass project.
|
||||
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
|
||||
contributing
|
||||
setup
|
||||
architecture
|
||||
testing
|
||||
deployment
|
||||
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
Any form of contribution is appreciated!
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`Contributing <development_manual/contributing>`
|
||||
|
||||
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
Structure
|
||||
|
||||
- :ref:`Nutzer Dokumentation <user_manual/index>` auf deutsch
|
||||
- :ref:`Development Documentation <development_manual/index>` auf englisch
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`Contributing #Documentation <development_manual/contributing/documentation>`
|
||||
|
||||
|
||||
@ -0,0 +1,101 @@
|
||||
.. _development_manual/setup:
|
||||
|
||||
=================
|
||||
Development Setup
|
||||
=================
|
||||
|
||||
The project is run with ``docker`` and all related files are in the ``docker/`` subfolder. Besides the actual Kompass
|
||||
application, a database (postgresql) and a broker (redis) are setup and run in the docker container. No
|
||||
external services are needed for running the development container.
|
||||
|
||||
Initial installation
|
||||
--------------------
|
||||
|
||||
A working ``docker`` setup (with ``docker compose``) is required. For installation instructions see the
|
||||
`docker manual <https://docs.docker.com/engine/install/>`_.
|
||||
|
||||
1. Clone the repository and change into the directory of the repository.
|
||||
|
||||
2. Fetch submodules
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
git submodule update --init
|
||||
|
||||
|
||||
.. _step-3:
|
||||
|
||||
3. Prepare development environment: to allow automatic rebuilding upon changes in the source,
|
||||
the owner of the ``/app/jdav_web`` directory in the Docker container must match your
|
||||
user. For this, make sure that the output of ``echo UID`` and ``echo UID`` is not empty. Then run
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
export GID=${GID}
|
||||
export UID=${UID}
|
||||
|
||||
4. Start docker
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd docker/development
|
||||
docker compose up
|
||||
|
||||
This runs the docker in your current shell, which is useful to see any log output. If you want to run
|
||||
the development server in the background instead, use ``docker compose up -d``.
|
||||
|
||||
During the initial run, the container is built and all dependencies are installed which can take a few minutes.
|
||||
After successful installation, the Kompass initialization runs, which in particular sets up all tables in the
|
||||
database.
|
||||
|
||||
If you need to rebuild the container (e.g. after changing the ``requirements.txt``), execute
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker compose up --build
|
||||
|
||||
5. Setup admin user: in a separate shell, while the docker container is running, execute
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd docker/development
|
||||
docker compose exec master bash -c "cd jdav_web && python3 manage.py createsuperuser"
|
||||
|
||||
This creates an admin user for the administration interface.
|
||||
|
||||
|
||||
Development
|
||||
-----------
|
||||
|
||||
If the initial installation was successful, you can start developing. Changes to files cause an automatic
|
||||
reload of the development server. If you need to generate and perform database migrations or generate locale files,
|
||||
use
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd docker/development
|
||||
docker compose exec master bash
|
||||
cd jdav_web
|
||||
|
||||
This starts a shell in the container, where you can execute any django maintenance commands via
|
||||
``python3 manage.py <command>``. For more information, see the https://docs.djangoproject.com/en/4.0/ref/django-admin.
|
||||
|
||||
|
||||
|
||||
|
||||
Known Issues
|
||||
------------
|
||||
|
||||
- If the ``UID`` and ``GID`` variables are not setup properly, you will encounter the following error message
|
||||
after running ``docker compose up``.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
=> ERROR [master 6/7] RUN groupadd -g fritze && useradd -g -u -m -d /app fritze 0.2s
|
||||
------
|
||||
> [master 6/7] RUN groupadd -g fritze && useradd -g -u -m -d /app fritze:
|
||||
0.141 groupadd: invalid group ID 'fritze'
|
||||
------
|
||||
failed to solve: process "/bin/sh -c groupadd -g $GID $USER && useradd -g $GID -u $UID -m -d /app $USER" did not complete successfully: exit code: 3
|
||||
|
||||
In this case repeat :ref:`step 3 <step-3>` above.
|
||||
@ -0,0 +1,7 @@
|
||||
.. _development_manual/testing:
|
||||
|
||||
=================
|
||||
Testing
|
||||
=================
|
||||
|
||||
To run the tests, you can use the docker setup under ``docker/test``.
|
||||
@ -1,3 +1,5 @@
|
||||
.. _user_manual/finance:
|
||||
|
||||
Finanzen
|
||||
========
|
||||
|
||||
|
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
@ -0,0 +1,50 @@
|
||||
.. _user_manual/index:
|
||||
|
||||
####################
|
||||
Nutzer Dokumentation
|
||||
####################
|
||||
|
||||
|
||||
Der Kompass ist dein Kompass in der Jugendarbeit in deiner JDAV Sektion. Wenn du das
|
||||
erste mal hier bist, schau doch mal :ref:`user_manual/getstarted` an.
|
||||
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
|
||||
getstarted
|
||||
members
|
||||
excursions
|
||||
waitinglist
|
||||
finance
|
||||
|
||||
|
||||
Was ist der Kompass?
|
||||
--------------------
|
||||
|
||||
Der Kompass ist eine Verwaltungsplattform für die tägliche Jugendarbeit in der JDAV.
|
||||
Die wichtigsten Funktionen sind
|
||||
|
||||
- Verwaltung von Teilnehmer\*innen von Jugendgruppen
|
||||
- Organisation von Ausfahrten
|
||||
- Abwicklung von Abrechnungen
|
||||
- Senden von E-Mails
|
||||
|
||||
Neben diesen Funktionen für die tägliche Arbeit, automatisiert der Kompass die
|
||||
Aufnahme von neuen Mitgliedern und die Pflege der Daten durch
|
||||
|
||||
- Wartelistenverwaltung
|
||||
- Registrierung neuer Mitglieder
|
||||
- Rückmeldeverfahren
|
||||
|
||||
Feedback
|
||||
--------
|
||||
|
||||
Wenn Du Feedback hast, schreibe uns gerne eine E-Mail an: `digitales@jdav-hd.de <mailto:digitales@jdav-hd.de?subject=Kompass Feedback>`_.
|
||||
Der Kompass lebt davon, dass er genau unsere Probleme löst und nicht nur ein weiteres Tool ist.
|
||||
|
||||
Feedback könnte sein:
|
||||
|
||||
- Fehler in der Software (bug)
|
||||
- Verbesserungsvorschläge
|
||||
- Wünsche für neue Funktionen
|
||||
- etc. pp.
|
||||
@ -0,0 +1,26 @@
|
||||
# Generated by Django 4.0.1 on 2025-01-18 19:08
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('members', '0032_member_upload_registration_form_key'),
|
||||
('members', '0033_freizeit_approved_extra_youth_leader_count'),
|
||||
('finance', '0005_alter_bill_proof'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='statement',
|
||||
name='allowance_to',
|
||||
field=models.ManyToManyField(help_text='The youth leaders to which an allowance should be paid. The count must match the number of permitted youth leaders.', related_name='receives_allowance_for_statements', to='members.Member', verbose_name='Pay allowance to'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='statement',
|
||||
name='subsidy_to',
|
||||
field=models.ForeignKey(help_text='The person that should receive the subsidy for night and travel costs. Typically the person who paid for them.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='receives_subsidy_for_statements', to='members.member', verbose_name='Pay subsidy to'),
|
||||
),
|
||||
]
|
||||
@ -0,0 +1,19 @@
|
||||
# Generated by Django 4.0.1 on 2025-01-18 22:00
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('members', '0033_freizeit_approved_extra_youth_leader_count'),
|
||||
('finance', '0006_statement_add_allowance_to_subsidy_to'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='statement',
|
||||
name='allowance_to',
|
||||
field=models.ManyToManyField(blank=True, help_text='The youth leaders to which an allowance should be paid. The count must match the number of permitted youth leaders.', related_name='receives_allowance_for_statements', to='members.Member', verbose_name='Pay allowance to'),
|
||||
),
|
||||
]
|
||||
@ -1,3 +1,82 @@
|
||||
from django.test import TestCase
|
||||
from http import HTTPStatus
|
||||
|
||||
# Create your tests here.
|
||||
from django.test import TestCase, RequestFactory
|
||||
from django.utils import timezone
|
||||
from django.contrib.admin.sites import AdminSite
|
||||
from django.urls import reverse
|
||||
from django.conf import settings
|
||||
from .models import Termin, GRUPPE, KATEGORIE, KONDITION, TECHNIK, SAISON,\
|
||||
EVENTART, KLASSIFIZIERUNG
|
||||
from .admin import TerminAdmin
|
||||
|
||||
|
||||
class BasicTerminTestCase(TestCase):
|
||||
TERMIN_NO = 10
|
||||
|
||||
def setUp(self):
|
||||
for i in range(BasicTerminTestCase.TERMIN_NO):
|
||||
Termin.objects.create(title='Foo {}'.format(i),
|
||||
start_date=timezone.now().date(),
|
||||
end_date=timezone.now().date(),
|
||||
group=GRUPPE[0][0],
|
||||
email=settings.TEST_MAIL,
|
||||
category=KATEGORIE[0][0],
|
||||
technik=TECHNIK[0][0],
|
||||
max_participants=42,
|
||||
anforderung_hoehe=10)
|
||||
|
||||
|
||||
class TerminAdminTestCase(BasicTerminTestCase):
|
||||
def test_str(self):
|
||||
t = Termin.objects.all()[0]
|
||||
self.assertEqual(str(t), '{} {}'.format(t.title, str(t.group)))
|
||||
|
||||
def test_make_overview(self):
|
||||
factory = RequestFactory()
|
||||
admin = TerminAdmin(Termin, AdminSite())
|
||||
url = reverse('admin:ludwigsburgalpin_termin_changelist')
|
||||
request = factory.get(url)
|
||||
|
||||
response = admin.make_overview(request, Termin.objects.all())
|
||||
|
||||
self.assertEqual(response['Content-Type'], 'application/xlsx',
|
||||
'The content-type of the generated overview should be an .xlsx file.')
|
||||
|
||||
class ViewTestCase(BasicTerminTestCase):
|
||||
def test_get_index(self):
|
||||
url = reverse('ludwigsburgalpin:index')
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, HTTPStatus.OK)
|
||||
|
||||
def test_submit_termin(self):
|
||||
url = reverse('ludwigsburgalpin:index')
|
||||
response = self.client.post(url, data={
|
||||
'title': 'My Title',
|
||||
'subtitle': 'My Subtitle',
|
||||
'start_date': '2024-01-01',
|
||||
'end_date': '2024-02-01',
|
||||
'group': GRUPPE[0][0],
|
||||
'category': KATEGORIE[0][0],
|
||||
'condition': KONDITION[0][0],
|
||||
'technik': TECHNIK[0][0],
|
||||
'saison': SAISON[0][0],
|
||||
'eventart': EVENTART[0][0],
|
||||
'klassifizierung': KLASSIFIZIERUNG[0][0],
|
||||
'anforderung_hoehe': 10,
|
||||
'anforderung_strecke': 10,
|
||||
'anforderung_dauer': 10,
|
||||
'max_participants': 100,
|
||||
})
|
||||
t = Termin.objects.get(title='My Title')
|
||||
self.assertEqual(t.group, GRUPPE[0][0])
|
||||
self.assertEqual(response.status_code, HTTPStatus.OK)
|
||||
self.assertContains(response, "Termin erfolgreich eingereicht", html=True)
|
||||
|
||||
def test_submit_termin_invalid(self):
|
||||
url = reverse('ludwigsburgalpin:index')
|
||||
# many required fields are missing
|
||||
response = self.client.post(url, data={
|
||||
'title': 'My Title',
|
||||
})
|
||||
self.assertEqual(response.status_code, HTTPStatus.OK)
|
||||
self.assertContains(response, "Dieses Feld ist zwingend erforderlich.", html=True)
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.0.1 on 2025-01-18 18:27
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('members', '0032_member_upload_registration_form_key'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='freizeit',
|
||||
name='approved_extra_youth_leader_count',
|
||||
field=models.PositiveIntegerField(default=0, help_text='The number of approved youth leaders per excursion is determined by the number of participants. In special circumstances, e.g. in case of a technically demanding excursion, more youth leaders may be approved.', verbose_name='Number of additional approved youth leaders'),
|
||||
),
|
||||
]
|
||||
@ -0,0 +1,52 @@
|
||||
{% extends "admin/base_site.html" %}
|
||||
{% load i18n admin_urls static %}
|
||||
|
||||
{% block extrahead %}
|
||||
{{ block.super }}
|
||||
{{ media }}
|
||||
<script src="{% static 'admin/js/cancel.js' %}" async></script>
|
||||
<script type="text/javascript" src="{% static "admin/js/vendor/jquery/jquery.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "admin/js/jquery.init.js" %}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block bodyclass %}{{ block.super }} app-{{ opts.app_label }} model-{{ opts.model_name }} invite-waiter
|
||||
{% endblock %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<div class="breadcrumbs">
|
||||
<a href="{% url 'admin:index' %}">{% translate 'Home' %}</a>
|
||||
› <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ opts.app_config.verbose_name }}</a>
|
||||
› <a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a>
|
||||
› <a href="{% url opts|admin_urlname:'change' object.pk|admin_urlquote %}">{{ object|truncatewords:"18" }}</a>
|
||||
› {% translate 'Generate SJR application' %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<p>
|
||||
{% blocktrans %}Here you can generate an allowance application for the SJR.{% endblocktrans %}
|
||||
</p>
|
||||
<p>
|
||||
{% blocktrans %}The application needs to be complemented with an invoice from the trip as proof.{% endblocktrans %}
|
||||
</p>
|
||||
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
<p>
|
||||
<table>
|
||||
{{ form }}
|
||||
</table>
|
||||
</p>
|
||||
<p>
|
||||
{% blocktrans %}Please send this application form to the jdav finance officer via email.{% endblocktrans %}
|
||||
</p>
|
||||
<br>
|
||||
<input type="hidden" name="action" value="sjr_application">
|
||||
<input type="hidden" name="sjr_application">
|
||||
<input class="default" style="color: $default-link-color" type="submit" name="apply"
|
||||
value="{% translate 'Generate' %}">
|
||||
<a href="#" class="button cancel-link">{% translate "Cancel" %}</a>
|
||||
</form>
|
||||
|
||||
|
||||
{% endblock %}
|
||||