Compare commits
21 Commits
main
...
MK/meeting
| Author | SHA1 | Date |
|---|---|---|
|
|
a8d6503b60 | 4 months ago |
|
|
eb3e45f016 | 4 months ago |
|
|
1f4cb41256 | 4 months ago |
|
|
7337cec025 | 4 months ago |
|
|
218df6aaab | 4 months ago |
|
|
5978e6ab5b | 5 months ago |
|
|
eb2cd6c68c | 5 months ago |
|
|
b0fb7bcfce | 6 months ago |
|
|
01b52feafe | 6 months ago |
|
|
ef7dac6d75 | 6 months ago |
|
|
8192297c51 | 6 months ago |
|
|
370b212597 | 8 months ago |
|
|
757408cfd9 | 8 months ago |
|
|
c3c207f64d | 8 months ago |
|
|
6388ccd15b | 8 months ago |
|
|
83ffd83830 | 8 months ago |
|
|
e16765e7af | 8 months ago |
|
|
eb0769b121 | 8 months ago |
|
|
f1398584cd | 8 months ago |
|
|
649e35e26c | 8 months ago |
|
|
546f2a2dd4 | 8 months ago |
@ -1,147 +0,0 @@
|
||||
name: Build and test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
APP_IMAGE_NAME: ${{ github.repository }}
|
||||
NGINX_IMAGE_NAME: ${{ github.repository }}-nginx
|
||||
|
||||
jobs:
|
||||
build-test-and-deploy:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Log in to GitHub Container Registry
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Extract metadata for application image
|
||||
id: meta-app
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.APP_IMAGE_NAME }}
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
type=sha,prefix={{branch}}-
|
||||
type=raw,value=latest,enable={{is_default_branch}}
|
||||
|
||||
- name: Extract metadata for nginx image
|
||||
id: meta-nginx
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.NGINX_IMAGE_NAME }}
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
type=sha,prefix={{branch}}-
|
||||
type=raw,value=latest,enable={{is_default_branch}}
|
||||
|
||||
- name: Build application image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: docker/production/Dockerfile
|
||||
load: true
|
||||
tags: kompass:test
|
||||
cache-from: |
|
||||
type=gha,scope=app-${{ github.ref_name }}
|
||||
type=gha,scope=app-master
|
||||
type=gha,scope=app-main
|
||||
type=registry,ref=ghcr.io/${{ github.repository }}:latest
|
||||
cache-to: type=gha,mode=max,scope=app-${{ github.ref_name }}
|
||||
build-args: |
|
||||
BUILDKIT_INLINE_CACHE=1
|
||||
|
||||
- name: Build documentation
|
||||
run: |
|
||||
# Create output directory with proper permissions
|
||||
mkdir -p docs-output
|
||||
chmod 777 docs-output
|
||||
|
||||
# Run sphinx-build inside the container
|
||||
docker run --rm \
|
||||
-v ${{ github.workspace }}/docs:/app/docs:ro \
|
||||
-v ${{ github.workspace }}/docs-output:/app/docs-output \
|
||||
kompass:test \
|
||||
bash -c "cd /app/docs && sphinx-build -b html source /app/docs-output"
|
||||
|
||||
- name: Deploy to GitHub Pages
|
||||
uses: peaceiris/actions-gh-pages@v4
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: ./docs-output
|
||||
destination_dir: ${{ github.ref == 'refs/heads/main' && '.' || github.ref_name }}
|
||||
keep_files: true
|
||||
|
||||
- name: Run tests
|
||||
run: make test-only
|
||||
|
||||
- name: Check coverage
|
||||
run: |
|
||||
COVERAGE=$(python3 -c "import json; data=json.load(open('docker/test/htmlcov/coverage.json')); print(data['totals']['percent_covered'])")
|
||||
echo "Coverage: ${COVERAGE}%"
|
||||
if (( $(echo "$COVERAGE < 100" | bc -l) )); then
|
||||
echo "Error: Coverage is ${COVERAGE}%, must be 100%"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Tag and push application image
|
||||
if: github.event_name != 'pull_request'
|
||||
run: |
|
||||
# Tag the built image with all required tags
|
||||
echo "${{ steps.meta-app.outputs.tags }}" | while read -r tag; do
|
||||
docker tag kompass:test "$tag"
|
||||
docker push "$tag"
|
||||
done
|
||||
|
||||
- name: Build and push nginx image
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: docker/production/nginx
|
||||
file: docker/production/nginx/Dockerfile
|
||||
push: true
|
||||
tags: ${{ steps.meta-nginx.outputs.tags }}
|
||||
labels: ${{ steps.meta-nginx.outputs.labels }}
|
||||
cache-from: |
|
||||
type=gha,scope=nginx-${{ github.ref_name }}
|
||||
type=gha,scope=nginx-master
|
||||
type=gha,scope=nginx-main
|
||||
type=registry,ref=ghcr.io/${{ github.repository }}-nginx:latest
|
||||
cache-to: type=gha,mode=max,scope=nginx-${{ github.ref_name }}
|
||||
build-args: |
|
||||
BUILDKIT_INLINE_CACHE=1
|
||||
|
||||
- name: Output image tags
|
||||
if: github.event_name != 'pull_request'
|
||||
run: |
|
||||
echo "Application image tags:"
|
||||
echo "${{ steps.meta-app.outputs.tags }}"
|
||||
echo ""
|
||||
echo "Nginx image tags:"
|
||||
echo "${{ steps.meta-nginx.outputs.tags }}"
|
||||
@ -1,2 +0,0 @@
|
||||
This repository contains third-party assets. Attributions are either placed in the file itself or
|
||||
in a file `NOTICE.txt` in the respective folder.
|
||||
@ -1,12 +0,0 @@
|
||||
confirm_mail = """
|
||||
Hiho custom test test {name},
|
||||
|
||||
du hast bei der JDAV %(SEKTION)s eine E-Mail Adresse hinterlegt. Da bei uns alle Kommunikation
|
||||
per Email funktioniert, brauchen wir eine Bestätigung {whattoconfirm}.
|
||||
|
||||
Custom!
|
||||
|
||||
{link}
|
||||
|
||||
Test test
|
||||
Deine JDAV test test %(SEKTION)s"""
|
||||
|
After Width: | Height: | Size: 48 KiB |
@ -1,40 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 27.3.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 48 48" style="enable-background:new 0 0 48 48;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{display:none;}
|
||||
.st1{display:inline;fill:#254D49;}
|
||||
.st2{display:inline;opacity:0.27;fill:url(#SVGID_1_);}
|
||||
.st3{fill:none;stroke:#1B2E2C;stroke-width:3;stroke-miterlimit:10;}
|
||||
.st4{fill:#1B2E2C;}
|
||||
.st5{fill:none;stroke:#508480;stroke-width:3.2;stroke-miterlimit:10;}
|
||||
.st6{fill:#BADDD9;}
|
||||
.st7{fill:#508480;}
|
||||
.st8{opacity:0.36;}
|
||||
.st9{opacity:0.24;fill:#FFFFFF;}
|
||||
</style>
|
||||
<g id="Hintergrund_x5F_Uni" class="st0">
|
||||
<rect class="st1" width="48" height="48"/>
|
||||
</g>
|
||||
<g id="Verlauf" class="st0">
|
||||
<radialGradient id="SVGID_1_" cx="23.348" cy="21.0566" r="25.4002" fx="3.9002" fy="4.7179" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" style="stop-color:#000000;stop-opacity:0"/>
|
||||
<stop offset="1" style="stop-color:#000000"/>
|
||||
</radialGradient>
|
||||
<circle class="st2" cx="23.6" cy="23.6" r="22.9"/>
|
||||
</g>
|
||||
<g id="Logo_x5F_Schatten">
|
||||
<circle class="st3" cx="24.3" cy="24.3" r="21.7"/>
|
||||
<polygon class="st4" points="21.4,22.9 15.8,42.4 27.5,25.7 33.2,6.2 "/>
|
||||
</g>
|
||||
<g id="LogooVordergrund">
|
||||
<circle class="st5" cx="23.7" cy="23.7" r="21.7"/>
|
||||
<g>
|
||||
<polygon class="st6" points="14.9,41.8 26.6,25.1 20.5,22.2 "/>
|
||||
<polygon class="st7" points="32.3,5.5 20.5,22.2 26.6,25.1 "/>
|
||||
<polyline class="st8" points="14.9,41.8 26.6,25.1 32.3,5.5 "/>
|
||||
<circle class="st9" cx="23.6" cy="23.6" r="1.6"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.6 KiB |
@ -1,39 +0,0 @@
|
||||
# Generated by Django 4.2.20 on 2025-10-11 15:43
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
def set_status_from_old_fields(apps, schema_editor):
|
||||
"""
|
||||
Set the status field based on the existing submitted and confirmed fields.
|
||||
- If confirmed is True, status = CONFIRMED (2)
|
||||
- If submitted is True but confirmed is False, status = SUBMITTED (1)
|
||||
- Otherwise, status = UNSUBMITTED (0)
|
||||
"""
|
||||
Statement = apps.get_model('finance', 'Statement')
|
||||
UNSUBMITTED, SUBMITTED, CONFIRMED = 0, 1, 2
|
||||
|
||||
for statement in Statement.objects.all():
|
||||
if statement.confirmed:
|
||||
statement.status = CONFIRMED
|
||||
elif statement.submitted:
|
||||
statement.status = SUBMITTED
|
||||
else:
|
||||
statement.status = UNSUBMITTED
|
||||
statement.save(update_fields=['status'])
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('finance', '0009_statement_ljp_to'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='statement',
|
||||
name='status',
|
||||
field=models.IntegerField(choices=[(0, 'In preparation'), (1, 'Submitted'), (2, 'Confirmed')], default=0, verbose_name='Status'),
|
||||
),
|
||||
migrations.RunPython(set_status_from_old_fields, reverse_code=migrations.RunPython.noop),
|
||||
]
|
||||
@ -1,21 +0,0 @@
|
||||
# Generated by Django 4.2.20 on 2025-10-11 16:01
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('finance', '0010_statement_status'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='statement',
|
||||
name='confirmed',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='statement',
|
||||
name='submitted',
|
||||
),
|
||||
]
|
||||
@ -1,28 +0,0 @@
|
||||
# Generated by Django 4.2.20 on 2025-10-12 19:16
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('finance', '0011_remove_statement_confirmed_and_submitted'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='StatementOnExcursionProxy',
|
||||
fields=[
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Statement',
|
||||
'verbose_name_plural': 'Statements',
|
||||
'abstract': False,
|
||||
'proxy': True,
|
||||
'default_permissions': ('add_global', 'change_global', 'view_global', 'delete_global', 'list_global', 'view'),
|
||||
'indexes': [],
|
||||
'constraints': [],
|
||||
},
|
||||
bases=('finance.statement',),
|
||||
),
|
||||
]
|
||||
@ -1,70 +0,0 @@
|
||||
import django.test
|
||||
from django.apps import apps
|
||||
from django.db import connection
|
||||
from django.db.migrations.executor import MigrationExecutor
|
||||
|
||||
|
||||
class StatusMigrationTestCase(django.test.TransactionTestCase):
|
||||
"""Test the migration from submitted/confirmed fields to status field."""
|
||||
|
||||
app = 'finance'
|
||||
migrate_from = [('finance', '0009_statement_ljp_to')]
|
||||
migrate_to = [('finance', '0010_statement_status')]
|
||||
|
||||
def setUp(self):
|
||||
# Get the state before migration
|
||||
executor = MigrationExecutor(connection)
|
||||
executor.migrate(self.migrate_from)
|
||||
|
||||
# Get the old models (before migration)
|
||||
old_apps = executor.loader.project_state(self.migrate_from).apps
|
||||
self.Statement = old_apps.get_model(self.app, 'Statement')
|
||||
|
||||
# Create statements with different combinations of submitted/confirmed
|
||||
# created_by is nullable, so we don't need to create a Member
|
||||
self.unsubmitted = self.Statement.objects.create(
|
||||
short_description='Unsubmitted Statement',
|
||||
submitted=False,
|
||||
confirmed=False
|
||||
)
|
||||
|
||||
self.submitted = self.Statement.objects.create(
|
||||
short_description='Submitted Statement',
|
||||
submitted=True,
|
||||
confirmed=False
|
||||
)
|
||||
|
||||
self.confirmed = self.Statement.objects.create(
|
||||
short_description='Confirmed Statement',
|
||||
submitted=True,
|
||||
confirmed=True
|
||||
)
|
||||
|
||||
def test_status_field_migration(self):
|
||||
"""Test that status field is correctly set from old submitted/confirmed fields."""
|
||||
# Run the migration
|
||||
executor = MigrationExecutor(connection)
|
||||
executor.loader.build_graph()
|
||||
executor.migrate(self.migrate_to)
|
||||
|
||||
# Get the new models (after migration)
|
||||
new_apps = executor.loader.project_state(self.migrate_to).apps
|
||||
Statement = new_apps.get_model(self.app, 'Statement')
|
||||
|
||||
# Constants from the Statement model
|
||||
UNSUBMITTED = 0
|
||||
SUBMITTED = 1
|
||||
CONFIRMED = 2
|
||||
|
||||
# Verify the migration worked correctly
|
||||
unsubmitted = Statement.objects.get(pk=self.unsubmitted.pk)
|
||||
self.assertEqual(unsubmitted.status, UNSUBMITTED,
|
||||
'Statement with submitted=False, confirmed=False should have status=UNSUBMITTED')
|
||||
|
||||
submitted = Statement.objects.get(pk=self.submitted.pk)
|
||||
self.assertEqual(submitted.status, SUBMITTED,
|
||||
'Statement with submitted=True, confirmed=False should have status=SUBMITTED')
|
||||
|
||||
confirmed = Statement.objects.get(pk=self.confirmed.pk)
|
||||
self.assertEqual(confirmed.status, CONFIRMED,
|
||||
'Statement with submitted=True, confirmed=True should have status=CONFIRMED')
|
||||
@ -1,59 +0,0 @@
|
||||
import os
|
||||
|
||||
DJANGO_LOG_LEVEL = get_var('logging', 'django_level', default='INFO')
|
||||
ROOT_LOG_LEVEL = get_var('logging', 'level', default='INFO')
|
||||
LOG_ERROR_TO_EMAIL = get_var('logging', 'email_admins', default=False)
|
||||
LOG_EMAIL_BACKEND = EMAIL_BACKEND if LOG_ERROR_TO_EMAIL else "django.core.mail.backends.console.EmailBackend"
|
||||
LOG_ERROR_INCLUDE_HTML = get_var('logging', 'error_report_include_html', default=False)
|
||||
|
||||
LOGGING = {
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False,
|
||||
"filters": {
|
||||
"require_debug_false": {
|
||||
"()": "django.utils.log.RequireDebugFalse",
|
||||
},
|
||||
"require_debug_true": {
|
||||
"()": "django.utils.log.RequireDebugTrue",
|
||||
},
|
||||
},
|
||||
"formatters": {
|
||||
"simple": {
|
||||
"format": "[{asctime}: {levelname}/{name}] {message}",
|
||||
"style": "{",
|
||||
},
|
||||
"verbose": {
|
||||
"format": "[{asctime}: {levelname}/{name}] {pathname}:{lineno} {message}",
|
||||
"style": "{",
|
||||
},
|
||||
},
|
||||
"handlers": {
|
||||
"console": {
|
||||
"class": "logging.StreamHandler",
|
||||
"formatter": "simple",
|
||||
},
|
||||
"console_verbose": {
|
||||
"class": "logging.StreamHandler",
|
||||
"formatter": "verbose",
|
||||
"level": "ERROR",
|
||||
},
|
||||
"mail_admins": {
|
||||
"level": "ERROR",
|
||||
"class": "django.utils.log.AdminEmailHandler",
|
||||
"email_backend": LOG_EMAIL_BACKEND,
|
||||
"include_html": LOG_ERROR_INCLUDE_HTML,
|
||||
"filters": ["require_debug_false"],
|
||||
},
|
||||
},
|
||||
"root": {
|
||||
"handlers": ["console"],
|
||||
"level": ROOT_LOG_LEVEL,
|
||||
},
|
||||
"loggers": {
|
||||
"django": {
|
||||
"handlers": ["console", "mail_admins"],
|
||||
"level": DJANGO_LOG_LEVEL,
|
||||
"propagate": False,
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
from django.test import TestCase, RequestFactory, override_settings
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib import admin
|
||||
from unittest.mock import Mock, patch
|
||||
from jdav_web.views import media_unprotected, custom_admin_view
|
||||
from startpage.models import Link
|
||||
|
||||
|
||||
class ViewsTestCase(TestCase):
|
||||
def setUp(self):
|
||||
self.factory = RequestFactory()
|
||||
self.user = User.objects.create_user('testuser', 'test@example.com', 'password')
|
||||
Link.objects.create(title='Test Link', url='https://example.com')
|
||||
|
||||
@override_settings(DEBUG=True)
|
||||
def test_media_unprotected_debug_true(self):
|
||||
request = self.factory.get('/media/test.jpg')
|
||||
with patch('jdav_web.views.serve') as mock_serve:
|
||||
mock_serve.return_value = Mock()
|
||||
result = media_unprotected(request, 'test.jpg')
|
||||
mock_serve.assert_called_once()
|
||||
|
||||
def test_custom_admin_view(self):
|
||||
request = self.factory.get('/admin/')
|
||||
request.user = self.user
|
||||
with patch.object(admin.site, 'get_app_list') as mock_get_app_list:
|
||||
mock_get_app_list.return_value = []
|
||||
response = custom_admin_view(request)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
mock_get_app_list.assert_called_once_with(request)
|
||||
@ -1,34 +0,0 @@
|
||||
from django.test import TestCase, override_settings
|
||||
from unittest.mock import patch, Mock
|
||||
from mailer.mailutils import send, SENT, NOT_SENT
|
||||
|
||||
|
||||
class MailUtilsTest(TestCase):
|
||||
def setUp(self):
|
||||
self.subject = "Test Subject"
|
||||
self.content = "Test Content"
|
||||
self.sender = "sender@example.com"
|
||||
self.recipient = "recipient@example.com"
|
||||
|
||||
def test_send_with_reply_to(self):
|
||||
with patch('mailer.mailutils.mail.get_connection') as mock_connection:
|
||||
mock_conn = Mock()
|
||||
mock_connection.return_value = mock_conn
|
||||
result = send(self.subject, self.content, self.sender, self.recipient, reply_to=["reply@example.com"])
|
||||
self.assertEqual(result, SENT)
|
||||
|
||||
def test_send_with_message_id(self):
|
||||
with patch('mailer.mailutils.mail.get_connection') as mock_connection:
|
||||
mock_conn = Mock()
|
||||
mock_connection.return_value = mock_conn
|
||||
result = send(self.subject, self.content, self.sender, self.recipient, message_id="<test@example.com>")
|
||||
self.assertEqual(result, SENT)
|
||||
|
||||
def test_send_exception_handling(self):
|
||||
with patch('mailer.mailutils.mail.get_connection') as mock_connection:
|
||||
mock_conn = Mock()
|
||||
mock_conn.send_messages.side_effect = Exception("Test exception")
|
||||
mock_connection.return_value = mock_conn
|
||||
with patch('builtins.print'):
|
||||
result = send(self.subject, self.content, self.sender, self.recipient)
|
||||
self.assertEqual(result, NOT_SENT)
|
||||
@ -1,121 +0,0 @@
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.db import migrations
|
||||
from django.contrib.auth.management import create_permissions
|
||||
|
||||
STANDARD_PERMS = [
|
||||
('members', 'view_member'),
|
||||
('members', 'view_freizeit'),
|
||||
('members', 'add_global_freizeit'),
|
||||
('members', 'view_memberwaitinglist'),
|
||||
('members', 'view_memberunconfirmedproxy'),
|
||||
('mailer', 'view_message'),
|
||||
('mailer', 'add_global_message'),
|
||||
('finance', 'view_statementunsubmitted'),
|
||||
('finance', 'add_global_statementunsubmitted'),
|
||||
]
|
||||
|
||||
FINANCE_PERMS = [
|
||||
('finance', 'view_bill'),
|
||||
('finance', 'view_ledger'),
|
||||
('finance', 'add_ledger'),
|
||||
('finance', 'change_ledger'),
|
||||
('finance', 'delete_ledger'),
|
||||
('finance', 'view_statementsubmitted'),
|
||||
('finance', 'view_global_statementsubmitted'),
|
||||
('finance', 'change_global_statementsubmitted'),
|
||||
('finance', 'view_transaction'),
|
||||
('finance', 'change_transaction'),
|
||||
('finance', 'add_transaction'),
|
||||
('finance', 'delete_transaction'),
|
||||
('finance', 'process_statementsubmitted'),
|
||||
('members', 'list_global_freizeit'),
|
||||
('members', 'view_global_freizeit'),
|
||||
]
|
||||
|
||||
WAITINGLIST_PERMS = [
|
||||
('members', 'view_global_memberwaitinglist'),
|
||||
('members', 'list_global_memberwaitinglist'),
|
||||
('members', 'change_global_memberwaitinglist'),
|
||||
('members', 'delete_global_memberwaitinglist'),
|
||||
]
|
||||
|
||||
TRAINING_PERMS = [
|
||||
('members', 'change_global_member'),
|
||||
('members', 'list_global_member'),
|
||||
('members', 'view_global_member'),
|
||||
('members', 'add_global_membertraining'),
|
||||
('members', 'change_global_membertraining'),
|
||||
('members', 'list_global_membertraining'),
|
||||
('members', 'view_global_membertraining'),
|
||||
('members', 'view_trainingcategory'),
|
||||
('members', 'add_trainingcategory'),
|
||||
('members', 'change_trainingcategory'),
|
||||
('members', 'delete_trainingcategory'),
|
||||
]
|
||||
|
||||
REGISTRATION_PERMS = [
|
||||
('members', 'may_manage_all_registrations'),
|
||||
('members', 'change_memberunconfirmedproxy'),
|
||||
('members', 'delete_memberunconfirmedproxy'),
|
||||
]
|
||||
|
||||
MATERIAL_PERMS = [
|
||||
('members', 'list_global_member'),
|
||||
('material', 'view_materialpart'),
|
||||
('material', 'change_materialpart'),
|
||||
('material', 'add_materialpart'),
|
||||
('material', 'delete_materialpart'),
|
||||
('material', 'view_materialcategory'),
|
||||
('material', 'change_materialcategory'),
|
||||
('material', 'add_materialcategory'),
|
||||
('material', 'delete_materialcategory'),
|
||||
('material', 'view_ownership'),
|
||||
('material', 'change_ownership'),
|
||||
('material', 'add_ownership'),
|
||||
('material', 'delete_ownership'),
|
||||
]
|
||||
|
||||
|
||||
def ensure_group_perms(apps, schema_editor, name, perm_names):
|
||||
"""
|
||||
Ensure the group `name` has the permissions `perm_names`. If the group does not
|
||||
exist, create it with the given permissions, otherwise add the missing ones.
|
||||
|
||||
This only adds permissions, already existing ones that are not listed here are not
|
||||
removed.
|
||||
"""
|
||||
db_alias = schema_editor.connection.alias
|
||||
Group = apps.get_model("auth", "Group")
|
||||
Permission = apps.get_model("auth", "Permission")
|
||||
perms = [ Permission.objects.get(codename=codename, content_type__app_label=app_label) for app_label, codename in perm_names ]
|
||||
try:
|
||||
g = Group.objects.using(db_alias).get(name=name)
|
||||
for perm in perms:
|
||||
g.permissions.add(perm)
|
||||
g.save()
|
||||
# This case is only executed if users have manually removed one of the standard groups.
|
||||
except Group.DoesNotExist: # pragma: no cover
|
||||
g = Group.objects.using(db_alias).create(name=name)
|
||||
g.permissions.set(perms)
|
||||
g.save()
|
||||
|
||||
|
||||
def update_default_permission_groups(apps, schema_editor):
|
||||
ensure_group_perms(apps, schema_editor, "Standard", STANDARD_PERMS)
|
||||
ensure_group_perms(apps, schema_editor, "Finance", FINANCE_PERMS)
|
||||
ensure_group_perms(apps, schema_editor, "Waitinglist", WAITINGLIST_PERMS)
|
||||
ensure_group_perms(apps, schema_editor, "Trainings", TRAINING_PERMS)
|
||||
ensure_group_perms(apps, schema_editor, "Registrations", REGISTRATION_PERMS)
|
||||
ensure_group_perms(apps, schema_editor, "Material", MATERIAL_PERMS)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('members', '0010_create_default_permission_groups'),
|
||||
('members', '0042_member_ticket_no'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(update_default_permission_groups, migrations.RunPython.noop),
|
||||
]
|
||||
@ -1,42 +0,0 @@
|
||||
# Generated by Django 4.2.20 on 2025-10-10 15:50
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('members', '0043_waitinglist_permissions'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='membertraining',
|
||||
name='activity',
|
||||
field=models.ManyToManyField(to='members.activitycategory', verbose_name='Activity'),
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='membertraining',
|
||||
options={'default_permissions': ('add_global', 'change_global', 'view_global', 'delete_global', 'list_global', 'view'), 'permissions': (('manage_success_trainings', 'Can edit the success status of trainings.'),), 'verbose_name': 'Training', 'verbose_name_plural': 'Trainings'},
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='membertraining',
|
||||
name='title',
|
||||
field=models.CharField(max_length=150, verbose_name='Title'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='membertraining',
|
||||
name='member',
|
||||
field=models.ForeignKey(on_delete=models.deletion.CASCADE, related_name='traininigs', to='members.member', verbose_name='Member'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='membertraining',
|
||||
name='participated',
|
||||
field=models.BooleanField(null=True, verbose_name='Participated'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='membertraining',
|
||||
name='passed',
|
||||
field=models.BooleanField(null=True, verbose_name='Passed'),
|
||||
),
|
||||
]
|
||||
@ -1,121 +0,0 @@
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.db import migrations
|
||||
from django.contrib.auth.management import create_permissions
|
||||
|
||||
STANDARD_PERMS = [
|
||||
('members', 'view_member'),
|
||||
('members', 'view_freizeit'),
|
||||
('members', 'add_global_freizeit'),
|
||||
('members', 'view_memberwaitinglist'),
|
||||
('members', 'view_memberunconfirmedproxy'),
|
||||
('mailer', 'view_message'),
|
||||
('mailer', 'add_global_message'),
|
||||
('finance', 'view_statement'),
|
||||
('finance', 'add_global_statement'),
|
||||
]
|
||||
|
||||
FINANCE_PERMS = [
|
||||
('finance', 'view_bill'),
|
||||
('finance', 'view_ledger'),
|
||||
('finance', 'add_ledger'),
|
||||
('finance', 'change_ledger'),
|
||||
('finance', 'delete_ledger'),
|
||||
('finance', 'view_global_statement'),
|
||||
('finance', 'change_global_statement'),
|
||||
('finance', 'process_statementsubmitted'),
|
||||
('finance', 'may_manage_confirmed_statements'),
|
||||
('finance', 'view_transaction'),
|
||||
('finance', 'change_transaction'),
|
||||
('finance', 'add_transaction'),
|
||||
('finance', 'delete_transaction'),
|
||||
('members', 'list_global_freizeit'),
|
||||
('members', 'view_global_freizeit'),
|
||||
]
|
||||
|
||||
WAITINGLIST_PERMS = [
|
||||
('members', 'view_global_memberwaitinglist'),
|
||||
('members', 'list_global_memberwaitinglist'),
|
||||
('members', 'change_global_memberwaitinglist'),
|
||||
('members', 'delete_global_memberwaitinglist'),
|
||||
]
|
||||
|
||||
TRAINING_PERMS = [
|
||||
('members', 'change_global_member'),
|
||||
('members', 'list_global_member'),
|
||||
('members', 'view_global_member'),
|
||||
('members', 'add_global_membertraining'),
|
||||
('members', 'change_global_membertraining'),
|
||||
('members', 'list_global_membertraining'),
|
||||
('members', 'view_global_membertraining'),
|
||||
('members', 'view_trainingcategory'),
|
||||
('members', 'add_trainingcategory'),
|
||||
('members', 'change_trainingcategory'),
|
||||
('members', 'delete_trainingcategory'),
|
||||
]
|
||||
|
||||
REGISTRATION_PERMS = [
|
||||
('members', 'may_manage_all_registrations'),
|
||||
('members', 'change_memberunconfirmedproxy'),
|
||||
('members', 'delete_memberunconfirmedproxy'),
|
||||
]
|
||||
|
||||
MATERIAL_PERMS = [
|
||||
('members', 'list_global_member'),
|
||||
('material', 'view_materialpart'),
|
||||
('material', 'change_materialpart'),
|
||||
('material', 'add_materialpart'),
|
||||
('material', 'delete_materialpart'),
|
||||
('material', 'view_materialcategory'),
|
||||
('material', 'change_materialcategory'),
|
||||
('material', 'add_materialcategory'),
|
||||
('material', 'delete_materialcategory'),
|
||||
('material', 'view_ownership'),
|
||||
('material', 'change_ownership'),
|
||||
('material', 'add_ownership'),
|
||||
('material', 'delete_ownership'),
|
||||
]
|
||||
|
||||
|
||||
def ensure_group_perms(apps, schema_editor, name, perm_names):
|
||||
"""
|
||||
Ensure the group `name` has the permissions `perm_names`. If the group does not
|
||||
exist, create it with the given permissions, otherwise add the missing ones.
|
||||
|
||||
This only adds permissions, already existing ones that are not listed here are not
|
||||
removed.
|
||||
"""
|
||||
db_alias = schema_editor.connection.alias
|
||||
Group = apps.get_model("auth", "Group")
|
||||
Permission = apps.get_model("auth", "Permission")
|
||||
perms = [ Permission.objects.get(codename=codename, content_type__app_label=app_label) for app_label, codename in perm_names ]
|
||||
try:
|
||||
g = Group.objects.using(db_alias).get(name=name)
|
||||
for perm in perms:
|
||||
g.permissions.add(perm)
|
||||
g.save()
|
||||
# This case is only executed if users have manually removed one of the standard groups.
|
||||
except Group.DoesNotExist: # pragma: no cover
|
||||
g = Group.objects.using(db_alias).create(name=name)
|
||||
g.permissions.set(perms)
|
||||
g.save()
|
||||
|
||||
|
||||
def update_default_permission_groups(apps, schema_editor):
|
||||
ensure_group_perms(apps, schema_editor, "Standard", STANDARD_PERMS)
|
||||
ensure_group_perms(apps, schema_editor, "Finance", FINANCE_PERMS)
|
||||
ensure_group_perms(apps, schema_editor, "Waitinglist", WAITINGLIST_PERMS)
|
||||
ensure_group_perms(apps, schema_editor, "Trainings", TRAINING_PERMS)
|
||||
ensure_group_perms(apps, schema_editor, "Registrations", REGISTRATION_PERMS)
|
||||
ensure_group_perms(apps, schema_editor, "Material", MATERIAL_PERMS)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('finance', '0012_statementonexcursionproxy'),
|
||||
('members', '0044_membertraining_activity_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(update_default_permission_groups, migrations.RunPython.noop),
|
||||
]
|
||||
@ -1,40 +0,0 @@
|
||||
{% 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>
|
||||
› {% translate 'Demote to waiter' %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2>{% translate "Request registration form" %}</h2>
|
||||
<p>
|
||||
{% blocktrans %}Do you want to ask {{ member }} to upload their registration form?{% endblocktrans %}
|
||||
</p>
|
||||
<p>
|
||||
{% if member.registration_form %}
|
||||
{% blocktrans %}Warning: {{ member }} has already uploaded a registration form.{% endblocktrans %}
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
<input class="default" style="color: $default-link-color" type="submit" name="apply" value="{% translate 'Request registration form' %}">
|
||||
<a href="#" class="button cancel-link">{% translate "Cancel" %}</a>
|
||||
</form>
|
||||
{% endblock %}
|
||||
@ -1,48 +0,0 @@
|
||||
{% 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>
|
||||
› {% translate 'Demote to waiter' %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2>{% translate "Demote to waiter" %}</h2>
|
||||
<p>
|
||||
{% trans "Do you want to demote the following unconfirmed registrations to waiters?" %}
|
||||
</p>
|
||||
<p>
|
||||
<ul>
|
||||
{% for member in queryset %}
|
||||
<li>
|
||||
<a href="{% url 'admin:members_memberunconfirmedproxy_change' 3 %}">{{ member }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
{% if form %}
|
||||
{{form}}
|
||||
{% endif %}
|
||||
<input type="hidden" name="action" value="demote_to_waiter_action">
|
||||
<input class="default" style="color: $default-link-color" type="submit" name="apply" value="{% translate 'Demote' %}">
|
||||
<a href="#" class="button cancel-link">{% translate "Cancel" %}</a>
|
||||
</form>
|
||||
{% endblock %}
|
||||
@ -1,80 +0,0 @@
|
||||
from django.test import TestCase
|
||||
from django.template import Context, Template
|
||||
from datetime import datetime, date, timedelta
|
||||
from members.templatetags.tex_extras import index, datetime_short, date_short, date_vs, time_short, add, plus
|
||||
from members.templatetags.overview_extras import blToColor, render_bool
|
||||
|
||||
|
||||
class TexExtrasTestCase(TestCase):
|
||||
def setUp(self):
|
||||
self.test_date = date(2024, 3, 15)
|
||||
self.test_datetime = datetime(2024, 3, 15, 14, 30)
|
||||
self.test_list = ['a', 'b', 'c']
|
||||
|
||||
def test_index_valid_position(self):
|
||||
result = index(self.test_list, 1)
|
||||
self.assertEqual(result, 'b')
|
||||
|
||||
def test_index_invalid_position(self):
|
||||
result = index(self.test_list, 5)
|
||||
self.assertEqual(result, '')
|
||||
|
||||
def test_index_type_error(self):
|
||||
result = index(123, 1)
|
||||
self.assertEqual(result, '')
|
||||
|
||||
def test_datetime_short(self):
|
||||
result = datetime_short(self.test_datetime)
|
||||
self.assertEqual(result, '15.03.2024 14:30')
|
||||
|
||||
def test_date_short(self):
|
||||
result = date_short(self.test_date)
|
||||
self.assertEqual(result, '15.03.24')
|
||||
|
||||
def test_date_vs(self):
|
||||
result = date_vs(self.test_date)
|
||||
self.assertEqual(result, '15.03.')
|
||||
|
||||
def test_time_short(self):
|
||||
result = time_short(self.test_datetime)
|
||||
self.assertEqual(result, '14:30')
|
||||
|
||||
def test_add_with_days(self):
|
||||
result = add(self.test_date, 5)
|
||||
self.assertEqual(result, date(2024, 3, 20))
|
||||
|
||||
def test_add_without_days(self):
|
||||
result = add(self.test_date, None)
|
||||
self.assertEqual(result, self.test_date)
|
||||
|
||||
def test_plus_with_second_number(self):
|
||||
result = plus(10, 5)
|
||||
self.assertEqual(result, 15)
|
||||
|
||||
def test_plus_without_second_number(self):
|
||||
result = plus(10, None)
|
||||
self.assertEqual(result, 10)
|
||||
|
||||
|
||||
class OverviewExtrasTestCase(TestCase):
|
||||
def test_blToColor_truthy_value(self):
|
||||
result = blToColor(True)
|
||||
self.assertEqual(result, 'green')
|
||||
|
||||
def test_blToColor_falsy_value(self):
|
||||
result = blToColor(False)
|
||||
self.assertEqual(result, 'red')
|
||||
|
||||
def test_render_bool_non_boolean_value(self):
|
||||
with self.assertRaises(ValueError):
|
||||
render_bool("not_a_boolean")
|
||||
|
||||
def test_render_bool_true(self):
|
||||
result = render_bool(True)
|
||||
self.assertIn('#bcd386', result)
|
||||
self.assertIn('icon-tick', result)
|
||||
|
||||
def test_render_bool_false(self):
|
||||
result = render_bool(False)
|
||||
self.assertIn('#dba4a4', result)
|
||||
self.assertIn('icon-cross', result)
|
||||
@ -1,31 +1,8 @@
|
||||
{% extends "startpage/base_subsite.html" %}
|
||||
{% load static common i18n %}
|
||||
{% load static %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% include "startpage/impressum_content.html" %}
|
||||
|
||||
{% block attribution %}
|
||||
<h1>{% trans "Attributions" %}</h1>
|
||||
|
||||
<p>
|
||||
{% trans "The source code of this website is licensed under" %}
|
||||
<a href="https://www.gnu.org/licenses/agpl-3.0.en.html">AGPLv3</a>.
|
||||
{% trans "Copyright © 2025 JDAV Sektion " %} {% settings_value 'SEKTION' %}
|
||||
{% trans "for the content of this website." %}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
{% trans "External assets used on this website:" %}
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
{% trans "Background image" %}:
|
||||
<a href="https://commons.wikimedia.org/wiki/File:Alps_Panorama_(4954145205).jpg">Reza</a>, <a href="https://creativecommons.org/licenses/by/2.0">CC BY 2.0</a>, via Wikimedia Commons
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@ -1,25 +0,0 @@
|
||||
span.statement-unsubmitted, span.statement-submitted, span.statement-confirmed {
|
||||
color: black;
|
||||
padding: 4px;
|
||||
padding-left: 6px;
|
||||
padding-right: 6px;
|
||||
border-radius: 10px;
|
||||
width: 20px;
|
||||
min-width: 20px;
|
||||
max-width: 20px;
|
||||
}
|
||||
|
||||
span.statement-submitted {
|
||||
background-color: #e8e8bd;
|
||||
color: black;
|
||||
}
|
||||
|
||||
span.statement-unsubmitted {
|
||||
background-color: #f0dada;
|
||||
color: black;
|
||||
}
|
||||
|
||||
span.statement-confirmed {
|
||||
background-color: #e0eec5;
|
||||
color: black;
|
||||
}
|
||||
@ -1,3 +0,0 @@
|
||||
- `climber.png`:
|
||||
Paul Sherman (https://commons.wikimedia.org/wiki/File:Rock_climbing_vector.svg),
|
||||
Public Domain, via Wikimedia Commons
|
||||
|
After Width: | Height: | Size: 48 KiB |
@ -1,40 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 27.3.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 48 48" style="enable-background:new 0 0 48 48;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{display:none;}
|
||||
.st1{display:inline;fill:#254D49;}
|
||||
.st2{display:inline;opacity:0.27;fill:url(#SVGID_1_);}
|
||||
.st3{fill:none;stroke:#1B2E2C;stroke-width:3;stroke-miterlimit:10;}
|
||||
.st4{fill:#1B2E2C;}
|
||||
.st5{fill:none;stroke:#508480;stroke-width:3.2;stroke-miterlimit:10;}
|
||||
.st6{fill:#BADDD9;}
|
||||
.st7{fill:#508480;}
|
||||
.st8{opacity:0.36;}
|
||||
.st9{opacity:0.24;fill:#FFFFFF;}
|
||||
</style>
|
||||
<g id="Hintergrund_x5F_Uni" class="st0">
|
||||
<rect class="st1" width="48" height="48"/>
|
||||
</g>
|
||||
<g id="Verlauf" class="st0">
|
||||
<radialGradient id="SVGID_1_" cx="23.348" cy="21.0566" r="25.4002" fx="3.9002" fy="4.7179" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" style="stop-color:#000000;stop-opacity:0"/>
|
||||
<stop offset="1" style="stop-color:#000000"/>
|
||||
</radialGradient>
|
||||
<circle class="st2" cx="23.6" cy="23.6" r="22.9"/>
|
||||
</g>
|
||||
<g id="Logo_x5F_Schatten">
|
||||
<circle class="st3" cx="24.3" cy="24.3" r="21.7"/>
|
||||
<polygon class="st4" points="21.4,22.9 15.8,42.4 27.5,25.7 33.2,6.2 "/>
|
||||
</g>
|
||||
<g id="LogooVordergrund">
|
||||
<circle class="st5" cx="23.7" cy="23.7" r="21.7"/>
|
||||
<g>
|
||||
<polygon class="st6" points="14.9,41.8 26.6,25.1 20.5,22.2 "/>
|
||||
<polygon class="st7" points="32.3,5.5 20.5,22.2 26.6,25.1 "/>
|
||||
<polyline class="st8" points="14.9,41.8 26.6,25.1 32.3,5.5 "/>
|
||||
<circle class="st9" cx="23.6" cy="23.6" r="1.6"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.6 KiB |
@ -1,40 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 27.3.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 48 48" style="enable-background:new 0 0 48 48;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{display:none;}
|
||||
.st1{display:inline;fill:#254D49;}
|
||||
.st2{opacity:0.27;fill:url(#SVGID_1_);}
|
||||
.st3{fill:none;stroke:#1B2E2C;stroke-width:3;stroke-miterlimit:10;}
|
||||
.st4{fill:#1B2E2C;}
|
||||
.st5{fill:none;stroke:#508480;stroke-width:3.2;stroke-miterlimit:10;}
|
||||
.st6{fill:#BADDD9;}
|
||||
.st7{fill:#508480;}
|
||||
.st8{opacity:0.36;}
|
||||
.st9{opacity:0.24;fill:#FFFFFF;}
|
||||
</style>
|
||||
<g id="Hintergrund_x5F_Uni" class="st0">
|
||||
<rect class="st1" width="48" height="48"/>
|
||||
</g>
|
||||
<g id="Verlauf">
|
||||
<radialGradient id="SVGID_1_" cx="23.348" cy="21.0566" r="25.4002" fx="3.9002" fy="4.7179" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" style="stop-color:#000000;stop-opacity:0"/>
|
||||
<stop offset="1" style="stop-color:#000000"/>
|
||||
</radialGradient>
|
||||
<circle class="st2" cx="23.6" cy="23.6" r="22.9"/>
|
||||
</g>
|
||||
<g id="Logo_x5F_Schatten">
|
||||
<circle class="st3" cx="24.3" cy="24.3" r="21.7"/>
|
||||
<polygon class="st4" points="21.4,22.9 15.8,42.4 27.5,25.7 33.2,6.2 "/>
|
||||
</g>
|
||||
<g id="LogooVordergrund">
|
||||
<circle class="st5" cx="23.7" cy="23.7" r="21.7"/>
|
||||
<g>
|
||||
<polygon class="st6" points="14.9,41.8 26.6,25.1 20.5,22.2 "/>
|
||||
<polygon class="st7" points="32.3,5.5 20.5,22.2 26.6,25.1 "/>
|
||||
<polyline class="st8" points="14.9,41.8 26.6,25.1 32.3,5.5 "/>
|
||||
<circle class="st9" cx="23.6" cy="23.6" r="1.6"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 251 KiB |
|
Before Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
@ -1,100 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="56.216759mm"
|
||||
height="56.216759mm"
|
||||
viewBox="0 0 56.216757 56.216759"
|
||||
version="1.1"
|
||||
id="svg5"
|
||||
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
|
||||
sodipodi:docname="favicon.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview7"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
showgrid="false"
|
||||
inkscape:zoom="2.149246"
|
||||
inkscape:cx="-9.305589"
|
||||
inkscape:cy="38.618194"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1131"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs2">
|
||||
<rect
|
||||
x="182.14978"
|
||||
y="169.88068"
|
||||
width="232.517"
|
||||
height="79.842117"
|
||||
id="rect1516" />
|
||||
</defs>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-29.946331,-23.342808)">
|
||||
<circle
|
||||
style="fill:#57ab27;fill-opacity:1;stroke-width:1.48706;paint-order:markers fill stroke"
|
||||
id="path1730-6-1"
|
||||
cx="58.05471"
|
||||
cy="51.451187"
|
||||
r="28.108379" />
|
||||
<path
|
||||
id="path3966-9-1"
|
||||
style="fill:#ffffff;stroke-width:1.25619;paint-order:markers fill stroke"
|
||||
inkscape:transform-center-x="-3.782124"
|
||||
inkscape:transform-center-y="-4.3700306"
|
||||
d="m 80.920792,53.466318 c -0.470466,3.311904 -13.350103,2.12902 -13.587434,2.635683 -0.679604,1.45084 3.938362,4.608269 6.042483,9.523902 1.290814,3.015588 -7.047323,-4.101451 -9.96792,-2.601752 -2.920596,1.499698 1.923956,15.743775 -1.35023,16.024675 -3.274187,0.2809 -5.545456,-15.647445 -6.494518,-16.033885 0,0 -14.24792,4.094643 -12.199826,1.483245 2.677707,-3.414185 9.25763,-4.828116 7.202174,-7.479738 -1.999671,-2.579656 -17.963879,8.442198 -19.103134,5.432682 -1.139256,-3.009516 14.035148,-8.666125 13.827521,-10.163424 -0.228782,-1.649843 -14.98569,-4.161215 -14.129021,-7.377038 0.856668,-3.215822 16.386111,0.75886 17.148239,-0.297092 0.816496,-1.131285 -6.937786,-9.696012 -4.409117,-11.776169 2.528672,-2.080158 9.745361,8.500431 10.087158,5.182534 0.123275,-1.196669 -2.960867,-14.105709 0.371765,-14.334482 3.332631,-0.228774 7.580901,13.354936 8.041922,13.749376 0.699867,0.598794 5.430215,-12.068543 8.236543,-10.279927 2.806326,1.788615 -4.56826,14.76871 -4.56889,14.956184 -8.48e-4,0.253286 17.004343,-6.237848 18.142636,-3.187729 1.13829,3.050119 -13.372314,8.616356 -13.110355,9.467028 0.306445,1.091863 10.29047,1.764021 9.820004,5.075927 z"
|
||||
sodipodi:nodetypes="ssssssssssssssssssscs" />
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#57ab27;fill-opacity:1;stroke-width:0.551392;paint-order:markers fill stroke"
|
||||
id="path6994"
|
||||
inkscape:flatsided="false"
|
||||
sodipodi:sides="8"
|
||||
sodipodi:cx="55.687187"
|
||||
sodipodi:cy="56.318855"
|
||||
sodipodi:r1="10.57478"
|
||||
sodipodi:r2="5.2873902"
|
||||
sodipodi:arg1="0.47788294"
|
||||
sodipodi:arg2="0.87058202"
|
||||
inkscape:rounded="0.5"
|
||||
inkscape:randomized="0.129"
|
||||
d="m 65.047164,60.016711 c -1.043329,2.898852 -4.58494,-0.903394 -7.278213,0.616665 -2.693273,1.520059 3.29224,6.067166 0.367555,6.407593 -2.924685,0.340427 0.630911,-6.090507 -2.288698,-6.186604 -2.919608,-0.0961 -2.860116,5.86842 -5.572988,4.998628 -2.712872,-0.869792 3.356668,-2.945529 1.635993,-5.647407 -1.720675,-2.701878 -5.056026,0.874989 -6.446919,-1.853343 -1.390894,-2.728333 5.701768,1.667645 5.601562,-1.509319 -0.100206,-3.176963 -5.011127,-1.483341 -3.626569,-4.163713 1.384558,-2.680371 2.490677,3.259555 4.40284,0.852349 1.912162,-2.407207 -3.184342,-6.105625 -0.367555,-6.407593 2.816787,-0.301968 1.987545,4.704949 5.164071,4.71759 3.176526,0.01264 0.335826,-7.989334 2.697614,-6.257907 2.361789,1.731427 -0.301995,4.45675 1.239381,6.906686 1.541377,2.449936 5.616663,-1.066225 6.44692,1.853343 0.830256,2.919568 -5.402008,-1.40305 -5.601563,1.509319 -0.199555,2.912368 4.669898,1.264861 3.626569,4.163713 z"
|
||||
inkscape:transform-center-x="0.14670795"
|
||||
inkscape:transform-center-y="-0.080514039"
|
||||
transform="matrix(1.0087409,0,0,1.0087409,2.0271192,-6.9908862)" />
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke-width:0.551392;paint-order:markers fill stroke"
|
||||
id="path6994-80"
|
||||
inkscape:flatsided="false"
|
||||
sodipodi:sides="8"
|
||||
sodipodi:cx="55.687187"
|
||||
sodipodi:cy="56.318855"
|
||||
sodipodi:r1="10.57478"
|
||||
sodipodi:r2="5.2873902"
|
||||
sodipodi:arg1="0.47788294"
|
||||
sodipodi:arg2="0.87058202"
|
||||
inkscape:rounded="0.5"
|
||||
inkscape:randomized="0.129"
|
||||
d="m 65.047164,60.016711 c -1.043329,2.898852 -4.58494,-0.903394 -7.278213,0.616665 -2.693273,1.520059 3.29224,6.067166 0.367555,6.407593 -2.924685,0.340427 0.630911,-6.090507 -2.288698,-6.186604 -2.919608,-0.0961 -2.860116,5.86842 -5.572988,4.998628 -2.712872,-0.869792 3.356668,-2.945529 1.635993,-5.647407 -1.720675,-2.701878 -5.056026,0.874989 -6.446919,-1.853343 -1.390894,-2.728333 5.701768,1.667645 5.601562,-1.509319 -0.100206,-3.176963 -5.011127,-1.483341 -3.626569,-4.163713 1.384558,-2.680371 2.490677,3.259555 4.40284,0.852349 1.912162,-2.407207 -3.184342,-6.105625 -0.367555,-6.407593 2.816787,-0.301968 1.987545,4.704949 5.164071,4.71759 3.176526,0.01264 0.335826,-7.989334 2.697614,-6.257907 2.361789,1.731427 -0.301995,4.45675 1.239381,6.906686 1.541377,2.449936 5.616663,-1.066225 6.44692,1.853343 0.830256,2.919568 -5.402008,-1.40305 -5.601563,1.509319 -0.199555,2.912368 4.669898,1.264861 3.626569,4.163713 z"
|
||||
inkscape:transform-center-x="-0.94540916"
|
||||
inkscape:transform-center-y="0.54557406"
|
||||
transform="matrix(-0.2826781,-0.253817,0.253817,-0.2826781,60.377101,79.593343)" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 894 B |
|
Before Width: | Height: | Size: 284 B After Width: | Height: | Size: 8.6 KiB |
@ -1,4 +0,0 @@
|
||||
The files in this folder are adapted from the Django JET project
|
||||
(formerly at https://github.com/geex-arts/django-jet, now at https://github.com/assem-ch/django-jet-reboot).
|
||||
|
||||
Django JET is released under AGPLv3 (https://www.gnu.org/licenses/agpl-3.0.en.html).
|
||||
@ -1,4 +0,0 @@
|
||||
The fonts in this directory are licensed under the Open Font License (https://openfontlicense.org/).
|
||||
|
||||
- Roboto font: https://fonts.google.com/specimen/Roboto
|
||||
- Oswald font: https://fonts.google.com/specimen/Oswald
|
||||
@ -1,3 +0,0 @@
|
||||
- `background.jpeg`:
|
||||
Reza (https://commons.wikimedia.org/wiki/File:Alps_Panorama_(4954145205).jpg),
|
||||
CC BY 2.0 <https://creativecommons.org/licenses/by/2.0>, via Wikimedia Commons
|
||||
|
Before Width: | Height: | Size: 348 KiB After Width: | Height: | Size: 139 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
@ -1,100 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="56.216759mm"
|
||||
height="56.216759mm"
|
||||
viewBox="0 0 56.216757 56.216759"
|
||||
version="1.1"
|
||||
id="svg5"
|
||||
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
|
||||
sodipodi:docname="favicon.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview7"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
showgrid="false"
|
||||
inkscape:zoom="2.149246"
|
||||
inkscape:cx="-9.305589"
|
||||
inkscape:cy="38.618194"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1131"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs2">
|
||||
<rect
|
||||
x="182.14978"
|
||||
y="169.88068"
|
||||
width="232.517"
|
||||
height="79.842117"
|
||||
id="rect1516" />
|
||||
</defs>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-29.946331,-23.342808)">
|
||||
<circle
|
||||
style="fill:#57ab27;fill-opacity:1;stroke-width:1.48706;paint-order:markers fill stroke"
|
||||
id="path1730-6-1"
|
||||
cx="58.05471"
|
||||
cy="51.451187"
|
||||
r="28.108379" />
|
||||
<path
|
||||
id="path3966-9-1"
|
||||
style="fill:#ffffff;stroke-width:1.25619;paint-order:markers fill stroke"
|
||||
inkscape:transform-center-x="-3.782124"
|
||||
inkscape:transform-center-y="-4.3700306"
|
||||
d="m 80.920792,53.466318 c -0.470466,3.311904 -13.350103,2.12902 -13.587434,2.635683 -0.679604,1.45084 3.938362,4.608269 6.042483,9.523902 1.290814,3.015588 -7.047323,-4.101451 -9.96792,-2.601752 -2.920596,1.499698 1.923956,15.743775 -1.35023,16.024675 -3.274187,0.2809 -5.545456,-15.647445 -6.494518,-16.033885 0,0 -14.24792,4.094643 -12.199826,1.483245 2.677707,-3.414185 9.25763,-4.828116 7.202174,-7.479738 -1.999671,-2.579656 -17.963879,8.442198 -19.103134,5.432682 -1.139256,-3.009516 14.035148,-8.666125 13.827521,-10.163424 -0.228782,-1.649843 -14.98569,-4.161215 -14.129021,-7.377038 0.856668,-3.215822 16.386111,0.75886 17.148239,-0.297092 0.816496,-1.131285 -6.937786,-9.696012 -4.409117,-11.776169 2.528672,-2.080158 9.745361,8.500431 10.087158,5.182534 0.123275,-1.196669 -2.960867,-14.105709 0.371765,-14.334482 3.332631,-0.228774 7.580901,13.354936 8.041922,13.749376 0.699867,0.598794 5.430215,-12.068543 8.236543,-10.279927 2.806326,1.788615 -4.56826,14.76871 -4.56889,14.956184 -8.48e-4,0.253286 17.004343,-6.237848 18.142636,-3.187729 1.13829,3.050119 -13.372314,8.616356 -13.110355,9.467028 0.306445,1.091863 10.29047,1.764021 9.820004,5.075927 z"
|
||||
sodipodi:nodetypes="ssssssssssssssssssscs" />
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#57ab27;fill-opacity:1;stroke-width:0.551392;paint-order:markers fill stroke"
|
||||
id="path6994"
|
||||
inkscape:flatsided="false"
|
||||
sodipodi:sides="8"
|
||||
sodipodi:cx="55.687187"
|
||||
sodipodi:cy="56.318855"
|
||||
sodipodi:r1="10.57478"
|
||||
sodipodi:r2="5.2873902"
|
||||
sodipodi:arg1="0.47788294"
|
||||
sodipodi:arg2="0.87058202"
|
||||
inkscape:rounded="0.5"
|
||||
inkscape:randomized="0.129"
|
||||
d="m 65.047164,60.016711 c -1.043329,2.898852 -4.58494,-0.903394 -7.278213,0.616665 -2.693273,1.520059 3.29224,6.067166 0.367555,6.407593 -2.924685,0.340427 0.630911,-6.090507 -2.288698,-6.186604 -2.919608,-0.0961 -2.860116,5.86842 -5.572988,4.998628 -2.712872,-0.869792 3.356668,-2.945529 1.635993,-5.647407 -1.720675,-2.701878 -5.056026,0.874989 -6.446919,-1.853343 -1.390894,-2.728333 5.701768,1.667645 5.601562,-1.509319 -0.100206,-3.176963 -5.011127,-1.483341 -3.626569,-4.163713 1.384558,-2.680371 2.490677,3.259555 4.40284,0.852349 1.912162,-2.407207 -3.184342,-6.105625 -0.367555,-6.407593 2.816787,-0.301968 1.987545,4.704949 5.164071,4.71759 3.176526,0.01264 0.335826,-7.989334 2.697614,-6.257907 2.361789,1.731427 -0.301995,4.45675 1.239381,6.906686 1.541377,2.449936 5.616663,-1.066225 6.44692,1.853343 0.830256,2.919568 -5.402008,-1.40305 -5.601563,1.509319 -0.199555,2.912368 4.669898,1.264861 3.626569,4.163713 z"
|
||||
inkscape:transform-center-x="0.14670795"
|
||||
inkscape:transform-center-y="-0.080514039"
|
||||
transform="matrix(1.0087409,0,0,1.0087409,2.0271192,-6.9908862)" />
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke-width:0.551392;paint-order:markers fill stroke"
|
||||
id="path6994-80"
|
||||
inkscape:flatsided="false"
|
||||
sodipodi:sides="8"
|
||||
sodipodi:cx="55.687187"
|
||||
sodipodi:cy="56.318855"
|
||||
sodipodi:r1="10.57478"
|
||||
sodipodi:r2="5.2873902"
|
||||
sodipodi:arg1="0.47788294"
|
||||
sodipodi:arg2="0.87058202"
|
||||
inkscape:rounded="0.5"
|
||||
inkscape:randomized="0.129"
|
||||
d="m 65.047164,60.016711 c -1.043329,2.898852 -4.58494,-0.903394 -7.278213,0.616665 -2.693273,1.520059 3.29224,6.067166 0.367555,6.407593 -2.924685,0.340427 0.630911,-6.090507 -2.288698,-6.186604 -2.919608,-0.0961 -2.860116,5.86842 -5.572988,4.998628 -2.712872,-0.869792 3.356668,-2.945529 1.635993,-5.647407 -1.720675,-2.701878 -5.056026,0.874989 -6.446919,-1.853343 -1.390894,-2.728333 5.701768,1.667645 5.601562,-1.509319 -0.100206,-3.176963 -5.011127,-1.483341 -3.626569,-4.163713 1.384558,-2.680371 2.490677,3.259555 4.40284,0.852349 1.912162,-2.407207 -3.184342,-6.105625 -0.367555,-6.407593 2.816787,-0.301968 1.987545,4.704949 5.164071,4.71759 3.176526,0.01264 0.335826,-7.989334 2.697614,-6.257907 2.361789,1.731427 -0.301995,4.45675 1.239381,6.906686 1.541377,2.449936 5.616663,-1.066225 6.44692,1.853343 0.830256,2.919568 -5.402008,-1.40305 -5.601563,1.509319 -0.199555,2.912368 4.669898,1.264861 3.626569,4.163713 z"
|
||||
inkscape:transform-center-x="-0.94540916"
|
||||
inkscape:transform-center-y="0.54557406"
|
||||
transform="matrix(-0.2826781,-0.253817,0.253817,-0.2826781,60.377101,79.593343)" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
@ -1,102 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="33.394791mm"
|
||||
height="38.402649mm"
|
||||
viewBox="0 0 33.39479 38.402649"
|
||||
version="1.1"
|
||||
id="svg5"
|
||||
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
|
||||
sodipodi:docname="placeholder.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#">
|
||||
<sodipodi:namedview
|
||||
id="namedview7"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
showgrid="false"
|
||||
showguides="true"
|
||||
inkscape:zoom="4.8176525"
|
||||
inkscape:cx="53.449268"
|
||||
inkscape:cy="87.179389"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1131"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1">
|
||||
<sodipodi:guide
|
||||
position="61.505519,-44.730047"
|
||||
orientation="0,-1"
|
||||
id="guide6240"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
position="121.55171,-27.740338"
|
||||
orientation="1,0"
|
||||
id="guide6242"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
position="-16.760398,-6.5643082"
|
||||
orientation="0,-1"
|
||||
id="guide6244"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
position="50.270998,-1.4630882"
|
||||
orientation="1,0"
|
||||
id="guide6246"
|
||||
inkscape:locked="false" />
|
||||
</sodipodi:namedview>
|
||||
<defs
|
||||
id="defs2" />
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-16.876211,-15.478853)">
|
||||
<path
|
||||
id="rect5358"
|
||||
style="fill:#cdcdcd;fill-opacity:1;fill-rule:nonzero;stroke-width:0.262325;paint-order:markers fill stroke"
|
||||
d="m 28.798227,38.417392 10.670704,-0.05716 c 5.784556,-0.03099 10.802072,5.45565 10.802071,8.875741 l -1e-6,2.278154 v 4.367374 l -28.549274,2e-6 -4.845516,-2e-6 v -6.31172 c 0,-5.567546 7.738888,-9.129984 11.922018,-9.152391 z"
|
||||
sodipodi:nodetypes="sssccccsss" />
|
||||
<circle
|
||||
style="fill:#cdcdcd;fill-opacity:1;fill-rule:nonzero;stroke-width:0.718272;paint-order:markers fill stroke"
|
||||
id="path11605"
|
||||
cx="33.573605"
|
||||
cy="26.010752"
|
||||
r="8.5013752" />
|
||||
</g>
|
||||
<metadata
|
||||
id="metadata12706">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/by/4.0/" />
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/by/4.0/">
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Reproduction" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Distribution" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Notice" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Attribution" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 3.4 KiB |
@ -1,41 +0,0 @@
|
||||
{% extends "admin/change_form_object_tools.html" %}
|
||||
{% load i18n admin_urls rules %}
|
||||
|
||||
{% block object-tools-items %}
|
||||
|
||||
{% if original.confirmed and perms.finance.may_manage_confirmed_statements %}
|
||||
<li>
|
||||
{% url opts|admin_urlname:'unconfirm' original.pk|admin_urlquote as invite_url %}
|
||||
<a class="historylink" href="{% add_preserved_filters invite_url %}">{% trans 'Unconfirm' %}</a>
|
||||
</li>
|
||||
<li>
|
||||
{% url opts|admin_urlname:'summary' original.pk|admin_urlquote as invite_url %}
|
||||
<a class="historylink" target="_blank" href="{% add_preserved_filters invite_url %}">{% trans 'Download summary' %}</a>
|
||||
</li>
|
||||
{% elif original.submitted and perms.finance.process_statementsubmitted %}
|
||||
<script>
|
||||
function requestWithCurrentURL(path) {
|
||||
var xpath = path + "?redirectTo=" + window.location.href;
|
||||
location.href = xpath;
|
||||
}
|
||||
</script>
|
||||
|
||||
<li>
|
||||
{% url opts|admin_urlname:'reduce_transactions' original.pk|admin_urlquote as invite_url %}
|
||||
<a value="hi" onclick='requestWithCurrentURL("{% add_preserved_filters invite_url %}")'>
|
||||
{% trans 'Reduce transactions' %}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
{% url opts|admin_urlname:'overview' original.pk|admin_urlquote as invite_url %}
|
||||
<a class="historylink" href="{% add_preserved_filters invite_url %}">{% trans 'Overview' %}</a>
|
||||
</li>
|
||||
{% elif not original.submitted %}
|
||||
<li>
|
||||
{% url opts|admin_urlname:'submit' original.pk|admin_urlquote as invite_url %}
|
||||
<a class="historylink" href="{% add_preserved_filters invite_url %}">{% trans 'Submit' %}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{{block.super}}
|
||||
|
||||
{% endblock %}
|
||||