Compare commits
10 Commits
1c0744811b
...
6285567b34
| Author | SHA1 | Date |
|---|---|---|
|
|
6285567b34 | 1 week ago |
|
|
d68b286799 | 1 week ago |
|
|
2744b1727a | 1 week ago |
|
|
c334fc59d5 | 2 weeks ago |
|
|
2090677b2d | 2 weeks ago |
|
|
78c117f300 | 2 weeks ago |
|
|
aaa1324da9 | 2 weeks ago |
|
|
1f7f33e446 | 2 weeks ago |
|
|
589527e1ac | 2 weeks ago |
|
|
91575eb280 | 2 weeks ago |
@ -0,0 +1,81 @@
|
||||
name: Check Deployment Readiness
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [labeled]
|
||||
|
||||
jobs:
|
||||
check-and-deploy:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.label.name == 'awaiting-deployment'
|
||||
permissions:
|
||||
actions: write
|
||||
pull-requests: read
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Check build workflow status
|
||||
id: check
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const prNumber = context.payload.pull_request.number;
|
||||
const headSha = context.payload.pull_request.head.sha;
|
||||
|
||||
console.log(`Checking build status for PR #${prNumber}, commit ${headSha}`);
|
||||
|
||||
// Use Check Runs API to get the status of the build workflow
|
||||
const { data: checkRuns } = await github.rest.checks.listForRef({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
ref: headSha,
|
||||
check_name: 'build'
|
||||
});
|
||||
|
||||
console.log(`Found ${checkRuns.total_count} check runs for 'build'`);
|
||||
|
||||
if (checkRuns.total_count === 0) {
|
||||
console.log('No build check found for this commit');
|
||||
core.setOutput('should_deploy', 'false');
|
||||
core.setOutput('reason', 'No build check found');
|
||||
return;
|
||||
}
|
||||
|
||||
const buildCheck = checkRuns.check_runs[0];
|
||||
console.log(`Build check status: ${buildCheck.status}, conclusion: ${buildCheck.conclusion}`);
|
||||
|
||||
// Check if build is still running
|
||||
if (buildCheck.status !== 'completed') {
|
||||
console.log('Build check is still running');
|
||||
core.setOutput('should_deploy', 'false');
|
||||
core.setOutput('reason', 'Build check is still running');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if build failed
|
||||
if (buildCheck.conclusion !== 'success') {
|
||||
console.log(`Build check failed with conclusion: ${buildCheck.conclusion}`);
|
||||
core.setOutput('should_deploy', 'false');
|
||||
core.setOutput('reason', `Build check ${buildCheck.conclusion}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Build completed successfully
|
||||
console.log('Build check completed successfully, ready to deploy');
|
||||
core.setOutput('should_deploy', 'true');
|
||||
|
||||
- name: Trigger deployment
|
||||
if: steps.check.outputs.should_deploy == 'true'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
await github.rest.actions.createWorkflowDispatch({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
workflow_id: 'deploy-pr.yml',
|
||||
ref: context.payload.pull_request.head.ref,
|
||||
inputs: {
|
||||
pr_number: context.payload.pull_request.number.toString()
|
||||
}
|
||||
});
|
||||
console.log('Deployment workflow triggered');
|
||||
@ -0,0 +1,92 @@
|
||||
name: Deploy PR to Remote Server
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
pr_number:
|
||||
description: 'PR number to deploy'
|
||||
required: true
|
||||
type: number
|
||||
|
||||
concurrency:
|
||||
group: deploy-pr-${{ inputs.pr_number }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
APP_IMAGE_NAME: ${{ github.repository }}
|
||||
NGINX_IMAGE_NAME: ${{ github.repository }}-nginx
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
environment: deploy-web
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
- name: Get PR details
|
||||
id: pr
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const prNumber = ${{ inputs.pr_number }};
|
||||
const { data: pr } = await github.rest.pulls.get({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: prNumber
|
||||
});
|
||||
core.setOutput('head_ref', pr.head.ref);
|
||||
core.setOutput('pr_number', prNumber);
|
||||
|
||||
- name: Setup SSH
|
||||
run: |
|
||||
mkdir -p ~/.ssh
|
||||
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/deploy_key
|
||||
chmod 600 ~/.ssh/deploy_key
|
||||
ssh-keyscan -H ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Deploy to remote server
|
||||
id: deploy
|
||||
run: |
|
||||
OUTPUT=$(ssh -i ~/.ssh/deploy_key -p ${{ secrets.SSH_PORT || 22 }} ${{ secrets.SSH_USERNAME }}@${{ secrets.SSH_HOST }} ${{ inputs.pr_number }})
|
||||
echo "$OUTPUT"
|
||||
DEPLOY_URL=$(echo "$OUTPUT" | tail -n 1)
|
||||
echo "url=$DEPLOY_URL" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cleanup SSH
|
||||
if: always()
|
||||
run: |
|
||||
rm -f ~/.ssh/deploy_key
|
||||
|
||||
- name: Comment deployment and documentation links
|
||||
uses: marocchino/sticky-pull-request-comment@v2
|
||||
with:
|
||||
number: ${{ steps.pr.outputs.pr_number }}
|
||||
header: deployment
|
||||
message: |
|
||||
🚀 **PR deployed successfully!**
|
||||
|
||||
**Website:** ${{ steps.deploy.outputs.url }}
|
||||
|
||||
**Documentation:** https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/${{ steps.pr.outputs.head_ref }}/
|
||||
|
||||
**Docker Images:**
|
||||
- App: `${{ env.REGISTRY }}/${{ env.APP_IMAGE_NAME }}:pr-${{ steps.pr.outputs.pr_number }}`
|
||||
- Nginx: `${{ env.REGISTRY }}/${{ env.NGINX_IMAGE_NAME }}:pr-${{ steps.pr.outputs.pr_number }}`
|
||||
|
||||
- name: Remove awaiting-deployment label
|
||||
if: always()
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
try {
|
||||
await github.rest.issues.removeLabel({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: ${{ steps.pr.outputs.pr_number }},
|
||||
name: 'awaiting-deployment'
|
||||
});
|
||||
} catch (error) {
|
||||
console.log('Label may have already been removed');
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
node {
|
||||
checkout scm
|
||||
}
|
||||
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
stages {
|
||||
stage('Build') {
|
||||
steps {
|
||||
sh "make build-test"
|
||||
}
|
||||
}
|
||||
stage('Test') {
|
||||
steps {
|
||||
sh "make test"
|
||||
recordCoverage(tools: [[parser: 'COBERTURA', pattern: 'docker/test/coverage.xml']])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
x-kompass:
|
||||
&kompass
|
||||
image: ghcr.io/chrisflav/kompass:latest
|
||||
env_file: docker.env
|
||||
environment:
|
||||
- DJANGO_SETTINGS_MODULE=jdav_web.settings
|
||||
- KOMPASS_CONFIG_DIR_PATH=/app/config/
|
||||
restart: always
|
||||
depends_on:
|
||||
- db
|
||||
- redis
|
||||
- cache
|
||||
|
||||
services:
|
||||
master:
|
||||
<<: *kompass
|
||||
entrypoint: /app/docker/production/entrypoint-master.sh
|
||||
volumes:
|
||||
- uwsgi_data:/tmp/uwsgi/
|
||||
- web_static:/app/static/
|
||||
- web_static:/var/www/jdav_web/static/
|
||||
- ./config:/app/config:ro
|
||||
|
||||
nginx:
|
||||
image: ghcr.io/chrisflav/kompass-nginx:latest
|
||||
restart: always
|
||||
volumes:
|
||||
- uwsgi_data:/tmp/uwsgi/
|
||||
- web_static:/var/www/jdav_web/static/:ro
|
||||
ports:
|
||||
- "3000:80"
|
||||
depends_on:
|
||||
- master
|
||||
|
||||
db:
|
||||
restart: always
|
||||
image: mariadb:latest
|
||||
env_file: docker.env
|
||||
|
||||
cache:
|
||||
restart: always
|
||||
image: memcached:alpine
|
||||
|
||||
redis:
|
||||
restart: always
|
||||
image: redis:6-alpine
|
||||
|
||||
celery_worker:
|
||||
<<: *kompass
|
||||
entrypoint: /app/docker/production/entrypoint-celery-worker.sh
|
||||
volumes:
|
||||
- ./config:/app/config:ro
|
||||
|
||||
celery_beat:
|
||||
<<: *kompass
|
||||
entrypoint: /app/docker/production/entrypoint-celery-beat.sh
|
||||
volumes:
|
||||
- ./config:/app/config:ro
|
||||
|
||||
volumes:
|
||||
uwsgi_data:
|
||||
web_static:
|
||||
@ -1,28 +1,26 @@
|
||||
import os
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Creates a super-user non-interactively if it doesn't exist."
|
||||
|
||||
def handle(self, *args, **options):
|
||||
User = get_user_model()
|
||||
|
||||
username = os.environ.get('DJANGO_SUPERUSER_USERNAME', '')
|
||||
password = os.environ.get('DJANGO_SUPERUSER_PASSWORD', '')
|
||||
username = os.environ.get("DJANGO_SUPERUSER_USERNAME", "")
|
||||
password = os.environ.get("DJANGO_SUPERUSER_PASSWORD", "")
|
||||
|
||||
if not username or not password:
|
||||
self.stdout.write(
|
||||
self.style.WARNING('Superuser data was not set. Skipping.')
|
||||
)
|
||||
self.stdout.write(self.style.WARNING("Superuser data was not set. Skipping."))
|
||||
return
|
||||
|
||||
if not User.objects.filter(username=username).exists():
|
||||
User.objects.create_superuser(username=username, password=password)
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS('Successfully created superuser.')
|
||||
)
|
||||
self.stdout.write(self.style.SUCCESS("Successfully created superuser."))
|
||||
else:
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS('Superuser with configured username already exists. Skipping.')
|
||||
self.style.SUCCESS("Superuser with configured username already exists. Skipping.")
|
||||
)
|
||||
|
||||
@ -1,10 +1,17 @@
|
||||
from django.db import models
|
||||
from rules.contrib.models import RulesModelBase, RulesModelMixin
|
||||
from rules.contrib.models import RulesModelBase
|
||||
from rules.contrib.models import RulesModelMixin
|
||||
|
||||
|
||||
# Create your models here.
|
||||
class CommonModel(models.Model, RulesModelMixin, metaclass=RulesModelBase):
|
||||
class Meta:
|
||||
abstract = True
|
||||
default_permissions = (
|
||||
'add_global', 'change_global', 'view_global', 'delete_global', 'list_global', 'view',
|
||||
"add_global",
|
||||
"change_global",
|
||||
"view_global",
|
||||
"delete_global",
|
||||
"list_global",
|
||||
"view",
|
||||
)
|
||||
|
||||
@ -1,136 +1,293 @@
|
||||
# Generated by Django 4.0.1 on 2023-03-29 22:16
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('members', '0002_remove_member_not_waiting_and_more'),
|
||||
("members", "0002_remove_member_not_waiting_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Ledger',
|
||||
name="Ledger",
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=30, verbose_name='Name')),
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
|
||||
),
|
||||
),
|
||||
("name", models.CharField(max_length=30, verbose_name="Name")),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Ledger',
|
||||
'verbose_name_plural': 'Ledgers',
|
||||
"verbose_name": "Ledger",
|
||||
"verbose_name_plural": "Ledgers",
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Statement',
|
||||
name="Statement",
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('short_description', models.CharField(blank=True, max_length=30, verbose_name='Short description')),
|
||||
('explanation', models.TextField(blank=True, verbose_name='Explanation')),
|
||||
('night_cost', models.DecimalField(decimal_places=2, default=0, max_digits=5, verbose_name='Price per night')),
|
||||
('submitted', models.BooleanField(default=False, verbose_name='Submitted')),
|
||||
('submitted_date', models.DateTimeField(default=None, null=True, verbose_name='Submitted on')),
|
||||
('confirmed', models.BooleanField(default=False, verbose_name='Confirmed')),
|
||||
('confirmed_date', models.DateTimeField(default=None, null=True, verbose_name='Paid on')),
|
||||
('confirmed_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='confirmed_statements', to='members.member', verbose_name='Authorized by')),
|
||||
('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='created_statements', to='members.member', verbose_name='Created by')),
|
||||
('excursion', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='members.freizeit', verbose_name='Associated excursion')),
|
||||
('submitted_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='submitted_statements', to='members.member', verbose_name='Submitted by')),
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
|
||||
),
|
||||
),
|
||||
(
|
||||
"short_description",
|
||||
models.CharField(blank=True, max_length=30, verbose_name="Short description"),
|
||||
),
|
||||
("explanation", models.TextField(blank=True, verbose_name="Explanation")),
|
||||
(
|
||||
"night_cost",
|
||||
models.DecimalField(
|
||||
decimal_places=2, default=0, max_digits=5, verbose_name="Price per night"
|
||||
),
|
||||
),
|
||||
("submitted", models.BooleanField(default=False, verbose_name="Submitted")),
|
||||
(
|
||||
"submitted_date",
|
||||
models.DateTimeField(default=None, null=True, verbose_name="Submitted on"),
|
||||
),
|
||||
("confirmed", models.BooleanField(default=False, verbose_name="Confirmed")),
|
||||
(
|
||||
"confirmed_date",
|
||||
models.DateTimeField(default=None, null=True, verbose_name="Paid on"),
|
||||
),
|
||||
(
|
||||
"confirmed_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="confirmed_statements",
|
||||
to="members.member",
|
||||
verbose_name="Authorized by",
|
||||
),
|
||||
),
|
||||
(
|
||||
"created_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="created_statements",
|
||||
to="members.member",
|
||||
verbose_name="Created by",
|
||||
),
|
||||
),
|
||||
(
|
||||
"excursion",
|
||||
models.OneToOneField(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
to="members.freizeit",
|
||||
verbose_name="Associated excursion",
|
||||
),
|
||||
),
|
||||
(
|
||||
"submitted_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="submitted_statements",
|
||||
to="members.member",
|
||||
verbose_name="Submitted by",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Statement',
|
||||
'verbose_name_plural': 'Statements',
|
||||
'permissions': [('may_edit_submitted_statements', 'Is allowed to edit submitted statements')],
|
||||
"verbose_name": "Statement",
|
||||
"verbose_name_plural": "Statements",
|
||||
"permissions": [
|
||||
("may_edit_submitted_statements", "Is allowed to edit submitted statements")
|
||||
],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Transaction',
|
||||
name="Transaction",
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('reference', models.TextField(verbose_name='Reference')),
|
||||
('amount', models.DecimalField(decimal_places=2, max_digits=6, verbose_name='Amount')),
|
||||
('confirmed', models.BooleanField(default=False, verbose_name='Paid')),
|
||||
('confirmed_date', models.DateTimeField(default=None, null=True, verbose_name='Paid on')),
|
||||
('confirmed_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='confirmed_transactions', to='members.member', verbose_name='Authorized by')),
|
||||
('ledger', models.ForeignKey(default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, to='finance.ledger', verbose_name='Ledger')),
|
||||
('member', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='members.member', verbose_name='Recipient')),
|
||||
('statement', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='finance.statement', verbose_name='Statement')),
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
|
||||
),
|
||||
),
|
||||
("reference", models.TextField(verbose_name="Reference")),
|
||||
(
|
||||
"amount",
|
||||
models.DecimalField(decimal_places=2, max_digits=6, verbose_name="Amount"),
|
||||
),
|
||||
("confirmed", models.BooleanField(default=False, verbose_name="Paid")),
|
||||
(
|
||||
"confirmed_date",
|
||||
models.DateTimeField(default=None, null=True, verbose_name="Paid on"),
|
||||
),
|
||||
(
|
||||
"confirmed_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="confirmed_transactions",
|
||||
to="members.member",
|
||||
verbose_name="Authorized by",
|
||||
),
|
||||
),
|
||||
(
|
||||
"ledger",
|
||||
models.ForeignKey(
|
||||
default=None,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
to="finance.ledger",
|
||||
verbose_name="Ledger",
|
||||
),
|
||||
),
|
||||
(
|
||||
"member",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="members.member",
|
||||
verbose_name="Recipient",
|
||||
),
|
||||
),
|
||||
(
|
||||
"statement",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="finance.statement",
|
||||
verbose_name="Statement",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Transaction',
|
||||
'verbose_name_plural': 'Transactions',
|
||||
"verbose_name": "Transaction",
|
||||
"verbose_name_plural": "Transactions",
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Receipt',
|
||||
name="Receipt",
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('short_description', models.CharField(max_length=30, verbose_name='Short description')),
|
||||
('amount', models.DecimalField(decimal_places=2, max_digits=6)),
|
||||
('comments', models.TextField()),
|
||||
('ledger', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='finance.ledger', verbose_name='Ledger')),
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
|
||||
),
|
||||
),
|
||||
(
|
||||
"short_description",
|
||||
models.CharField(max_length=30, verbose_name="Short description"),
|
||||
),
|
||||
("amount", models.DecimalField(decimal_places=2, max_digits=6)),
|
||||
("comments", models.TextField()),
|
||||
(
|
||||
"ledger",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="finance.ledger",
|
||||
verbose_name="Ledger",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Bill',
|
||||
name="Bill",
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('short_description', models.CharField(max_length=30, verbose_name='Short description')),
|
||||
('explanation', models.TextField(blank=True, verbose_name='Explanation')),
|
||||
('amount', models.DecimalField(decimal_places=2, default=0, max_digits=6)),
|
||||
('costs_covered', models.BooleanField(default=False, verbose_name='Covered')),
|
||||
('refunded', models.BooleanField(default=False, verbose_name='Refunded')),
|
||||
('proof', models.ImageField(blank=True, upload_to='bill_images', verbose_name='Proof')),
|
||||
('paid_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='members.member', verbose_name='Paid by')),
|
||||
('statement', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='finance.statement', verbose_name='Statement')),
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
|
||||
),
|
||||
),
|
||||
(
|
||||
"short_description",
|
||||
models.CharField(max_length=30, verbose_name="Short description"),
|
||||
),
|
||||
("explanation", models.TextField(blank=True, verbose_name="Explanation")),
|
||||
("amount", models.DecimalField(decimal_places=2, default=0, max_digits=6)),
|
||||
("costs_covered", models.BooleanField(default=False, verbose_name="Covered")),
|
||||
("refunded", models.BooleanField(default=False, verbose_name="Refunded")),
|
||||
(
|
||||
"proof",
|
||||
models.ImageField(blank=True, upload_to="bill_images", verbose_name="Proof"),
|
||||
),
|
||||
(
|
||||
"paid_by",
|
||||
models.ForeignKey(
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
to="members.member",
|
||||
verbose_name="Paid by",
|
||||
),
|
||||
),
|
||||
(
|
||||
"statement",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="finance.statement",
|
||||
verbose_name="Statement",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Bill',
|
||||
'verbose_name_plural': 'Bills',
|
||||
"verbose_name": "Bill",
|
||||
"verbose_name_plural": "Bills",
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='StatementConfirmed',
|
||||
fields=[
|
||||
],
|
||||
name="StatementConfirmed",
|
||||
fields=[],
|
||||
options={
|
||||
'verbose_name': 'Paid statement',
|
||||
'verbose_name_plural': 'Paid statements',
|
||||
'permissions': (('may_manage_confirmed_statements', 'Can view and manage confirmed statements.'),),
|
||||
'proxy': True,
|
||||
'indexes': [],
|
||||
'constraints': [],
|
||||
"verbose_name": "Paid statement",
|
||||
"verbose_name_plural": "Paid statements",
|
||||
"permissions": (
|
||||
(
|
||||
"may_manage_confirmed_statements",
|
||||
"Can view and manage confirmed statements.",
|
||||
),
|
||||
),
|
||||
"proxy": True,
|
||||
"indexes": [],
|
||||
"constraints": [],
|
||||
},
|
||||
bases=('finance.statement',),
|
||||
bases=("finance.statement",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='StatementSubmitted',
|
||||
fields=[
|
||||
],
|
||||
name="StatementSubmitted",
|
||||
fields=[],
|
||||
options={
|
||||
'verbose_name': 'Submitted statement',
|
||||
'verbose_name_plural': 'Submitted statements',
|
||||
'permissions': (('may_manage_submitted_statements', 'Can view and manage submitted statements.'),),
|
||||
'proxy': True,
|
||||
'indexes': [],
|
||||
'constraints': [],
|
||||
"verbose_name": "Submitted statement",
|
||||
"verbose_name_plural": "Submitted statements",
|
||||
"permissions": (
|
||||
(
|
||||
"may_manage_submitted_statements",
|
||||
"Can view and manage submitted statements.",
|
||||
),
|
||||
),
|
||||
"proxy": True,
|
||||
"indexes": [],
|
||||
"constraints": [],
|
||||
},
|
||||
bases=('finance.statement',),
|
||||
bases=("finance.statement",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='StatementUnSubmitted',
|
||||
fields=[
|
||||
],
|
||||
name="StatementUnSubmitted",
|
||||
fields=[],
|
||||
options={
|
||||
'verbose_name': 'Statement in preparation',
|
||||
'verbose_name_plural': 'Statements in preparation',
|
||||
'proxy': True,
|
||||
'indexes': [],
|
||||
'constraints': [],
|
||||
"verbose_name": "Statement in preparation",
|
||||
"verbose_name_plural": "Statements in preparation",
|
||||
"proxy": True,
|
||||
"indexes": [],
|
||||
"constraints": [],
|
||||
},
|
||||
bases=('finance.statement',),
|
||||
bases=("finance.statement",),
|
||||
),
|
||||
]
|
||||
|
||||
@ -1,18 +1,20 @@
|
||||
# Generated by Django 4.0.1 on 2024-12-02 00:22
|
||||
|
||||
from django.db import migrations, models
|
||||
from django.db import migrations
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('finance', '0003_alter_bill_options_and_more'),
|
||||
("finance", "0003_alter_bill_options_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='bill',
|
||||
name='amount',
|
||||
field=models.DecimalField(decimal_places=2, default=0, max_digits=6, verbose_name='Amount'),
|
||||
model_name="bill",
|
||||
name="amount",
|
||||
field=models.DecimalField(
|
||||
decimal_places=2, default=0, max_digits=6, verbose_name="Amount"
|
||||
),
|
||||
),
|
||||
]
|
||||
|
||||
@ -1,19 +1,20 @@
|
||||
# Generated by Django 4.0.1 on 2024-12-26 09:45
|
||||
|
||||
from django.db import migrations
|
||||
import utils
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('finance', '0004_alter_bill_amount'),
|
||||
("finance", "0004_alter_bill_amount"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='bill',
|
||||
name='proof',
|
||||
field=utils.RestrictedFileField(blank=True, upload_to='bill_images', verbose_name='Proof'),
|
||||
model_name="bill",
|
||||
name="proof",
|
||||
field=utils.RestrictedFileField(
|
||||
blank=True, upload_to="bill_images", verbose_name="Proof"
|
||||
),
|
||||
),
|
||||
]
|
||||
|
||||
@ -1,26 +1,38 @@
|
||||
# Generated by Django 4.0.1 on 2025-01-18 19:08
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations
|
||||
from django.db import models
|
||||
|
||||
|
||||
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'),
|
||||
("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'),
|
||||
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'),
|
||||
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",
|
||||
),
|
||||
),
|
||||
]
|
||||
|
||||
@ -1,19 +1,25 @@
|
||||
# Generated by Django 4.0.1 on 2025-01-18 22:00
|
||||
|
||||
from django.db import migrations, models
|
||||
from django.db import migrations
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('members', '0033_freizeit_approved_extra_youth_leader_count'),
|
||||
('finance', '0006_statement_add_allowance_to_subsidy_to'),
|
||||
("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'),
|
||||
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,25 +1,39 @@
|
||||
# Generated by Django 4.0.1 on 2025-01-23 22:16
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('members', '0033_freizeit_approved_extra_youth_leader_count'),
|
||||
('finance', '0007_alter_statement_allowance_to'),
|
||||
("members", "0033_freizeit_approved_extra_youth_leader_count"),
|
||||
("finance", "0007_alter_statement_allowance_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.', related_name='receives_allowance_for_statements', to='members.Member', verbose_name='Pay allowance to'),
|
||||
model_name="statement",
|
||||
name="allowance_to",
|
||||
field=models.ManyToManyField(
|
||||
blank=True,
|
||||
help_text="The youth leaders to which an allowance should be paid.",
|
||||
related_name="receives_allowance_for_statements",
|
||||
to="members.Member",
|
||||
verbose_name="Pay allowance to",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='statement',
|
||||
name='subsidy_to',
|
||||
field=models.ForeignKey(blank=True, 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'),
|
||||
model_name="statement",
|
||||
name="subsidy_to",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
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",
|
||||
),
|
||||
),
|
||||
]
|
||||
|
||||
@ -1,20 +1,28 @@
|
||||
# Generated by Django 4.2.20 on 2025-04-03 21:04
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('members', '0039_membertraining_certificate_attendance'),
|
||||
('finance', '0008_alter_statement_allowance_to_and_more'),
|
||||
("members", "0039_membertraining_certificate_attendance"),
|
||||
("finance", "0008_alter_statement_allowance_to_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='statement',
|
||||
name='ljp_to',
|
||||
field=models.ForeignKey(blank=True, help_text='The person that should receive the ljp contributions for the participants. Should be only selected if an ljp request was submitted.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='receives_ljp_for_statements', to='members.member', verbose_name='Pay ljp contributions to'),
|
||||
model_name="statement",
|
||||
name="ljp_to",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="The person that should receive the ljp contributions for the participants. Should be only selected if an ljp request was submitted.",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="receives_ljp_for_statements",
|
||||
to="members.member",
|
||||
verbose_name="Pay ljp contributions to",
|
||||
),
|
||||
),
|
||||
]
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,3 +1,3 @@
|
||||
from .celery import app as celery_app
|
||||
|
||||
__all__ = ('celery_app',)
|
||||
__all__ = ("celery_app",)
|
||||
|
||||
@ -1,14 +1,13 @@
|
||||
import os
|
||||
from celery import Celery
|
||||
|
||||
from django.conf import settings
|
||||
from celery import Celery
|
||||
|
||||
# set the default Django settings module for the 'celery' program.
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'jdav_web.settings')
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "jdav_web.settings")
|
||||
|
||||
app = Celery()
|
||||
app.config_from_object('django.conf:settings')
|
||||
app.config_from_object("django.conf:settings")
|
||||
app.autodiscover_tasks()
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.start() # pragma: no cover
|
||||
if __name__ == "__main__":
|
||||
app.start() # pragma: no cover
|
||||
|
||||
@ -1,17 +1,18 @@
|
||||
# ruff: noqa F821
|
||||
|
||||
CACHES = {
|
||||
'default': {
|
||||
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
|
||||
'LOCATION': get_var('django', 'memcached_url', default='127.0.0.1:11211'),
|
||||
'OPTIONS': {
|
||||
'no_delay': True,
|
||||
'ignore_exc': True,
|
||||
'max_pool_size': 4,
|
||||
'use_pooling': True,
|
||||
}
|
||||
"default": {
|
||||
"BACKEND": "django.core.cache.backends.memcached.PyMemcacheCache",
|
||||
"LOCATION": get_var("django", "memcached_url", default="cache:11211"),
|
||||
"OPTIONS": {
|
||||
"no_delay": True,
|
||||
"ignore_exc": True,
|
||||
"max_pool_size": 4,
|
||||
"use_pooling": True,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
CACHE_MIDDLEWARE_ALIAS = 'default'
|
||||
CACHE_MIDDLEWARE_ALIAS = "default"
|
||||
CACHE_MIDDLEWARE_SECONDS = 1
|
||||
CACHE_MIDDLEWARE_KEY_PREFIX = ''
|
||||
|
||||
CACHE_MIDDLEWARE_KEY_PREFIX = ""
|
||||
|
||||
@ -1,17 +1,19 @@
|
||||
# ruff: noqa F821
|
||||
|
||||
# Email setup
|
||||
|
||||
EMAIL_HOST = get_var('mail', 'host', default='localhost')
|
||||
EMAIL_PORT = get_var('mail', 'port', default=587 if deployed else 25)
|
||||
EMAIL_HOST_USER = get_var('mail', 'user', default='user')
|
||||
EMAIL_HOST_PASSWORD = get_var('mail', 'password', default='secret')
|
||||
EMAIL_USE_TLS = get_var('mail', 'tls', default=True if deployed else False)
|
||||
EMAIL_BACKEND = 'djcelery_email.backends.CeleryEmailBackend'
|
||||
EMAIL_HOST = get_var("mail", "host", default="localhost")
|
||||
EMAIL_PORT = get_var("mail", "port", default=587 if deployed else 25)
|
||||
EMAIL_HOST_USER = get_var("mail", "user", default="user")
|
||||
EMAIL_HOST_PASSWORD = get_var("mail", "password", default="secret")
|
||||
EMAIL_USE_TLS = get_var("mail", "tls", default=True if deployed else False)
|
||||
EMAIL_BACKEND = "djcelery_email.backends.CeleryEmailBackend"
|
||||
|
||||
# Celery Email Setup
|
||||
|
||||
CELERY_EMAIL_TASK_CONFIG = {
|
||||
'rate_limit' : '10/m' # * CELERY_EMAIL_CHUNK_SIZE (default: 10)
|
||||
"rate_limit": "10/m" # * CELERY_EMAIL_CHUNK_SIZE (default: 10)
|
||||
}
|
||||
|
||||
DEFAULT_SENDING_MAIL = get_var('mail', 'default_sending_address', default='kompass@localhost')
|
||||
DEFAULT_SENDING_NAME = get_var('mail', 'default_sending_name', default='Kompass')
|
||||
DEFAULT_SENDING_MAIL = get_var("mail", "default_sending_address", default="kompass@localhost")
|
||||
DEFAULT_SENDING_NAME = get_var("mail", "default_sending_name", default="Kompass")
|
||||
|
||||
@ -1,64 +1,116 @@
|
||||
# ruff: noqa F821
|
||||
|
||||
# JET options (admin interface)
|
||||
|
||||
JET_SIDE_MENU_COMPACT = True
|
||||
JET_DEFAULT_THEME = 'jdav-green'
|
||||
JET_DEFAULT_THEME = "jdav-green"
|
||||
JET_CHANGE_FORM_SIBLING_LINKS = False
|
||||
|
||||
JET_SIDE_MENU_ITEMS = [
|
||||
{'label': 'Teilnehmer*innenverwaltung', 'app_label': 'members', 'items': [
|
||||
{'name': 'member', 'label': 'Alle Teilnehmer*innen', 'permissions': ['members.view_member']},
|
||||
{'name': 'freizeit', 'permissions': ['members.view_freizeit']},
|
||||
{'name': 'group', 'permissions': ['members.view_group']},
|
||||
{'name': 'membernotelist', 'permissions': ['members.view_membernotelist']},
|
||||
{'name': 'klettertreff', 'permissions': ['members.view_klettertreff']},
|
||||
]},
|
||||
{'label': 'Neue Mitglieder', 'app_label': 'members', 'permissions': ['members.view_memberunconfirmedproxy'], 'items': [
|
||||
{'name': 'memberunconfirmedproxy', 'permissions': ['members.view_memberunconfirmedproxy']},
|
||||
{'name': 'memberwaitinglist', 'permissions': ['members.view_memberwaitinglist']},
|
||||
]},
|
||||
{'label': 'Ausbildung', 'app_label': 'members', 'permissions': ['members.view_membertraining'], 'items': [
|
||||
{'name': 'membertraining', 'permissions': ['members.view_membertraining']},
|
||||
{'name': 'trainingcategory', 'permissions': ['members.view_trainingcategory']},
|
||||
{'name': 'activitycategory', 'permissions': ['members.view_activitycategory']},
|
||||
]},
|
||||
{'app_label': 'mailer', 'items': [
|
||||
{'name': 'message', 'permissions': ['mailer.view_message']},
|
||||
{'name': 'emailaddress', 'permissions': ['mailer.view_emailaddress']},
|
||||
]},
|
||||
{'app_label': 'finance', 'items': [
|
||||
{'name': 'statement', 'permissions': ['finance.view_statement']},
|
||||
{'name': 'ledger', 'permissions': ['finance.view_ledger']},
|
||||
{'name': 'bill', 'permissions': ['finance.view_bill', 'finance.view_bill_admin']},
|
||||
{'name': 'transaction', 'permissions': ['finance.view_transaction']},
|
||||
]},
|
||||
{'app_label': 'logindata', 'permissions': ['auth'], 'items': [
|
||||
{'name': 'authgroup', 'permissions': ['auth.group'] },
|
||||
{'name': 'logindatum', 'permissions': ['auth.user']},
|
||||
{'name': 'registrationpassword', 'permissions': ['auth.user']},
|
||||
]},
|
||||
{'app_label': 'django_celery_beat', 'permissions': ['django_celery_beat'], 'items': [
|
||||
{'name': 'crontabschedule'},
|
||||
{'name': 'clockedschedule'},
|
||||
{'name': 'intervalschedule'},
|
||||
{'name': 'periodictask'},
|
||||
{'name': 'solarschedule'},
|
||||
]},
|
||||
{'app_label': 'ludwigsburgalpin', 'permissions': ['ludwigsburgalpin'], 'items': [
|
||||
{'name': 'termin', 'permissions': ['ludwigsburgalpin.view_termin']},
|
||||
]},
|
||||
{'app_label': 'material', 'permissions': ['material.view_materialpart'], 'items': [
|
||||
{'name': 'materialcategory', 'permissions': ['material.view_materialcategory']},
|
||||
{'name': 'materialpart', 'permissions': ['material.view_materialpart']},
|
||||
]},
|
||||
{'app_label': 'startpage', 'permissions': ['startpage'], 'items': [
|
||||
{'name': 'section', 'permissions': ['startpage.view_section']},
|
||||
{'name': 'post', 'permissions': ['startpage.view_post']},
|
||||
{'name': 'link', 'permissions': ['startpage.view_link']},
|
||||
]},
|
||||
{'label': 'Externe Links', 'items' : [
|
||||
{ 'label': 'Nextcloud', 'url': CLOUD_LINK, 'url_blank': True },
|
||||
{ 'label': 'DAV 360', 'url': DAV_360_LINK, 'url_blank': True },
|
||||
{ 'label': 'Julei-Wiki', 'url': WIKI_LINK, 'url_blank': True },
|
||||
{ 'label': 'Kompass Dokumentation', 'url': DOCS_LINK, 'url_blank': True },
|
||||
]},
|
||||
{
|
||||
"label": "Teilnehmer*innenverwaltung",
|
||||
"app_label": "members",
|
||||
"items": [
|
||||
{
|
||||
"name": "member",
|
||||
"label": "Alle Teilnehmer*innen",
|
||||
"permissions": ["members.view_member"],
|
||||
},
|
||||
{"name": "freizeit", "permissions": ["members.view_freizeit"]},
|
||||
{"name": "group", "permissions": ["members.view_group"]},
|
||||
{"name": "membernotelist", "permissions": ["members.view_membernotelist"]},
|
||||
{"name": "klettertreff", "permissions": ["members.view_klettertreff"]},
|
||||
],
|
||||
},
|
||||
{
|
||||
"label": "Neue Mitglieder",
|
||||
"app_label": "members",
|
||||
"permissions": ["members.view_memberunconfirmedproxy"],
|
||||
"items": [
|
||||
{
|
||||
"name": "memberunconfirmedproxy",
|
||||
"permissions": ["members.view_memberunconfirmedproxy"],
|
||||
},
|
||||
{"name": "memberwaitinglist", "permissions": ["members.view_memberwaitinglist"]},
|
||||
],
|
||||
},
|
||||
{
|
||||
"label": "Ausbildung",
|
||||
"app_label": "members",
|
||||
"permissions": ["members.view_membertraining"],
|
||||
"items": [
|
||||
{"name": "membertraining", "permissions": ["members.view_membertraining"]},
|
||||
{"name": "trainingcategory", "permissions": ["members.view_trainingcategory"]},
|
||||
{"name": "activitycategory", "permissions": ["members.view_activitycategory"]},
|
||||
],
|
||||
},
|
||||
{
|
||||
"app_label": "mailer",
|
||||
"items": [
|
||||
{"name": "message", "permissions": ["mailer.view_message"]},
|
||||
{"name": "emailaddress", "permissions": ["mailer.view_emailaddress"]},
|
||||
],
|
||||
},
|
||||
{
|
||||
"app_label": "finance",
|
||||
"items": [
|
||||
{"name": "statement", "permissions": ["finance.view_statement"]},
|
||||
{"name": "ledger", "permissions": ["finance.view_ledger"]},
|
||||
{"name": "bill", "permissions": ["finance.view_bill", "finance.view_bill_admin"]},
|
||||
{"name": "transaction", "permissions": ["finance.view_transaction"]},
|
||||
],
|
||||
},
|
||||
{
|
||||
"app_label": "logindata",
|
||||
"permissions": ["auth"],
|
||||
"items": [
|
||||
{"name": "authgroup", "permissions": ["auth.group"]},
|
||||
{"name": "logindatum", "permissions": ["auth.user"]},
|
||||
{"name": "registrationpassword", "permissions": ["auth.user"]},
|
||||
],
|
||||
},
|
||||
{
|
||||
"app_label": "django_celery_beat",
|
||||
"permissions": ["django_celery_beat"],
|
||||
"items": [
|
||||
{"name": "crontabschedule"},
|
||||
{"name": "clockedschedule"},
|
||||
{"name": "intervalschedule"},
|
||||
{"name": "periodictask"},
|
||||
{"name": "solarschedule"},
|
||||
],
|
||||
},
|
||||
{
|
||||
"app_label": "ludwigsburgalpin",
|
||||
"permissions": ["ludwigsburgalpin"],
|
||||
"items": [
|
||||
{"name": "termin", "permissions": ["ludwigsburgalpin.view_termin"]},
|
||||
],
|
||||
},
|
||||
{
|
||||
"app_label": "material",
|
||||
"permissions": ["material.view_materialpart"],
|
||||
"items": [
|
||||
{"name": "materialcategory", "permissions": ["material.view_materialcategory"]},
|
||||
{"name": "materialpart", "permissions": ["material.view_materialpart"]},
|
||||
],
|
||||
},
|
||||
{
|
||||
"app_label": "startpage",
|
||||
"permissions": ["startpage"],
|
||||
"items": [
|
||||
{"name": "section", "permissions": ["startpage.view_section"]},
|
||||
{"name": "post", "permissions": ["startpage.view_post"]},
|
||||
{"name": "link", "permissions": ["startpage.view_link"]},
|
||||
],
|
||||
},
|
||||
{
|
||||
"label": "Externe Links",
|
||||
"items": [
|
||||
{"label": "Nextcloud", "url": CLOUD_LINK, "url_blank": True},
|
||||
{"label": "DAV 360", "url": DAV_360_LINK, "url_blank": True},
|
||||
{"label": "Julei-Wiki", "url": WIKI_LINK, "url_blank": True},
|
||||
{"label": "Kompass Dokumentation", "url": DOCS_LINK, "url_blank": True},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
@ -1,86 +1,98 @@
|
||||
# ruff: noqa F821
|
||||
|
||||
# contact data
|
||||
|
||||
SEKTION = get_var('section', 'name', default='Heyo')
|
||||
SEKTION_STREET = get_var('section', 'street', default='Street')
|
||||
SEKTION_TOWN = get_var('section', 'town', default='12345 Town')
|
||||
SEKTION_TELEPHONE = get_var('section', 'telephone', default='0123456789')
|
||||
SEKTION_TELEFAX = get_var('section', 'telefax', default=SEKTION_TELEPHONE)
|
||||
SEKTION_CONTACT_MAIL = get_var('section', 'contact_mail', default='info@example.org')
|
||||
SEKTION_BOARD_MAIL = get_var('section', 'board_mail', default=SEKTION_CONTACT_MAIL)
|
||||
SEKTION_CRISIS_INTERVENTION_MAIL = get_var('section', 'crisis_intervention_mail',
|
||||
default=SEKTION_BOARD_MAIL)
|
||||
SEKTION_FINANCE_MAIL = get_var('section', 'finance_mail', default=SEKTION_CONTACT_MAIL)
|
||||
SEKTION_IBAN = get_var('section', 'iban', default='Foo 123')
|
||||
SEKTION_ACCOUNT_HOLDER = get_var('section', 'account_holder',
|
||||
default='Foo')
|
||||
|
||||
RESPONSIBLE_MAIL = get_var('section', 'responsible_mail', default='foo@example.org')
|
||||
DIGITAL_MAIL = get_var('section', 'digital_mail', default='bar@example.org')
|
||||
SEKTION = get_var("section", "name", default="Heyo")
|
||||
SEKTION_STREET = get_var("section", "street", default="Street")
|
||||
SEKTION_TOWN = get_var("section", "town", default="12345 Town")
|
||||
SEKTION_TELEPHONE = get_var("section", "telephone", default="0123456789")
|
||||
SEKTION_TELEFAX = get_var("section", "telefax", default=SEKTION_TELEPHONE)
|
||||
SEKTION_CONTACT_MAIL = get_var("section", "contact_mail", default="info@example.org")
|
||||
SEKTION_BOARD_MAIL = get_var("section", "board_mail", default=SEKTION_CONTACT_MAIL)
|
||||
SEKTION_CRISIS_INTERVENTION_MAIL = get_var(
|
||||
"section", "crisis_intervention_mail", default=SEKTION_BOARD_MAIL
|
||||
)
|
||||
SEKTION_FINANCE_MAIL = get_var("section", "finance_mail", default=SEKTION_CONTACT_MAIL)
|
||||
SEKTION_IBAN = get_var("section", "iban", default="Foo 123")
|
||||
SEKTION_ACCOUNT_HOLDER = get_var("section", "account_holder", default="Foo")
|
||||
|
||||
RESPONSIBLE_MAIL = get_var("section", "responsible_mail", default="foo@example.org")
|
||||
DIGITAL_MAIL = get_var("section", "digital_mail", default="bar@example.org")
|
||||
|
||||
# LJP
|
||||
|
||||
V32_HEAD_ORGANISATION = get_var('LJP', 'v32_head_organisation', default='not configured')
|
||||
LJP_CONTRIBUTION_PER_DAY = get_var('LJP', 'contribution_per_day', default=25)
|
||||
LJP_TAX = get_var('LJP', 'tax', default=0)
|
||||
V32_HEAD_ORGANISATION = get_var("LJP", "v32_head_organisation", default="not configured")
|
||||
LJP_CONTRIBUTION_PER_DAY = get_var("LJP", "contribution_per_day", default=25)
|
||||
LJP_TAX = get_var("LJP", "tax", default=0)
|
||||
|
||||
# echo
|
||||
|
||||
# used to generate the personalized echo password
|
||||
ECHO_PASSWORD_BIRTHDATE_FORMAT = get_var('echo', 'password_birthdate_format', default='%d.%m.%Y')
|
||||
ECHO_PASSWORD_BIRTHDATE_FORMAT = get_var("echo", "password_birthdate_format", default="%d.%m.%Y")
|
||||
# grace period in days after which echo keys expire
|
||||
ECHO_GRACE_PERIOD = get_var('echo', 'grace_period', default=30)
|
||||
ECHO_GRACE_PERIOD = get_var("echo", "grace_period", default=30)
|
||||
|
||||
# Waiting list configuration parameters, all numbers are in days
|
||||
|
||||
GRACE_PERIOD_WAITING_CONFIRMATION = get_var('waitinglist', 'grace_period_confirmation', default=30)
|
||||
WAITING_CONFIRMATION_FREQUENCY = get_var('waitinglist', 'confirmation_frequency', default=90)
|
||||
CONFIRMATION_REMINDER_FREQUENCY = get_var('waitinglist', 'confirmation_reminder_frequency', default=30)
|
||||
MAX_REMINDER_COUNT = get_var('waitinglist', 'max_reminder_count', default=3)
|
||||
GRACE_PERIOD_WAITING_CONFIRMATION = get_var("waitinglist", "grace_period_confirmation", default=30)
|
||||
WAITING_CONFIRMATION_FREQUENCY = get_var("waitinglist", "confirmation_frequency", default=90)
|
||||
CONFIRMATION_REMINDER_FREQUENCY = get_var(
|
||||
"waitinglist", "confirmation_reminder_frequency", default=30
|
||||
)
|
||||
MAX_REMINDER_COUNT = get_var("waitinglist", "max_reminder_count", default=3)
|
||||
|
||||
# misc
|
||||
|
||||
# the maximal number of members that get sent congratulations for highest activity on aprils fools day
|
||||
CONGRATULATE_MEMBERS_MAX = get_var('misc', 'congratulate_members_max', default=10)
|
||||
CONGRATULATE_MEMBERS_MAX = get_var("misc", "congratulate_members_max", default=10)
|
||||
# expiry duration of a good conduct certificate in months
|
||||
MAX_AGE_GOOD_CONDUCT_CERTIFICATE_MONTHS = get_var('misc', 'max_age_good_conduct_certificate_months', default=24)
|
||||
MAX_AGE_GOOD_CONDUCT_CERTIFICATE_MONTHS = get_var(
|
||||
"misc", "max_age_good_conduct_certificate_months", default=24
|
||||
)
|
||||
# accepted email domains for inviting users
|
||||
ALLOWED_EMAIL_DOMAINS_FOR_INVITE_AS_USER = get_var('misc', 'allowed_email_domains_for_invite_as_user',
|
||||
default=['example.org'])
|
||||
ALLOWED_EMAIL_DOMAINS_FOR_INVITE_AS_USER = get_var(
|
||||
"misc", "allowed_email_domains_for_invite_as_user", default=["example.org"]
|
||||
)
|
||||
# send all mails from the assocation's contact mail or from personal association mails
|
||||
SEND_FROM_ASSOCIATION_EMAIL = get_var('misc', 'send_from_association_email', default=False)
|
||||
SEND_FROM_ASSOCIATION_EMAIL = get_var("misc", "send_from_association_email", default=False)
|
||||
# domain for association email and generated urls
|
||||
DOMAIN = get_var('misc', 'domain', default='example.org')
|
||||
|
||||
GROUP_CHECKLIST_N_WEEKS = get_var('misc', 'group_checklist_n_weeks', default=18)
|
||||
GROUP_CHECKLIST_N_MEMBERS = get_var('misc', 'group_checklist_n_members', default=20)
|
||||
GROUP_CHECKLIST_TEXT = get_var('misc', 'group_checklist_text',
|
||||
default="""Anwesende Jugendleitende und Teilnehmende werden mit einem
|
||||
Kreuz ($\\times$) markiert und die ausgefüllte Liste zum Anfang der Gruppenstunde an der Kasse
|
||||
abgegeben. Zum Ende wird sie wieder abgeholt. Wenn die Punkte auf einer Karte fast aufgebraucht
|
||||
sind, notiert die Kasse die verbliebenen Eintritte (3, 2, 1) unter dem Kreuz.""")
|
||||
DOMAIN = get_var("misc", "domain", default="example.org")
|
||||
|
||||
GROUP_CHECKLIST_N_WEEKS = get_var("misc", "group_checklist_n_weeks", default=18)
|
||||
GROUP_CHECKLIST_N_MEMBERS = get_var("misc", "group_checklist_n_members", default=20)
|
||||
GROUP_CHECKLIST_TEXT = get_var(
|
||||
"misc",
|
||||
"group_checklist_text",
|
||||
default="""Anwesende Jugendleitende und Teilnehmende werden mit einem
|
||||
Kreuz ($\\times$) markiert und die ausgefüllte Liste zum Anfang der Gruppenstunde an der Kasse
|
||||
abgegeben. Zum Ende wird sie wieder abgeholt. Wenn die Punkte auf einer Karte fast aufgebraucht
|
||||
sind, notiert die Kasse die verbliebenen Eintritte (3, 2, 1) unter dem Kreuz.""",
|
||||
)
|
||||
|
||||
# finance
|
||||
|
||||
ALLOWANCE_PER_DAY = get_var('finance', 'allowance_per_day', default=22)
|
||||
MAX_NIGHT_COST = get_var('finance', 'max_night_cost', default=11)
|
||||
ALLOWANCE_PER_DAY = get_var("finance", "allowance_per_day", default=22)
|
||||
MAX_NIGHT_COST = get_var("finance", "max_night_cost", default=11)
|
||||
|
||||
EXCURSION_ORG_FEE = get_var('finance', 'org_fee', default=10)
|
||||
EXCURSION_ORG_FEE = get_var("finance", "org_fee", default=10)
|
||||
|
||||
# links
|
||||
|
||||
CLOUD_LINK = get_var('links', 'cloud', default='https://startpage.com')
|
||||
DAV_360_LINK = get_var('links', 'dav_360', default='https://dav360.de')
|
||||
WIKI_LINK = get_var('links', 'wiki', default='https://wikipedia.org')
|
||||
DOCS_LINK = get_var('links', 'docs', default='https://github.com/chrisflav/kompass')
|
||||
REGISTRATION_FORM_DOWNLOAD_LINK = get_var('links', 'registration_form', default='https://startpage.com')
|
||||
CLOUD_LINK = get_var("links", "cloud", default="https://startpage.com")
|
||||
DAV_360_LINK = get_var("links", "dav_360", default="https://dav360.de")
|
||||
WIKI_LINK = get_var("links", "wiki", default="https://wikipedia.org")
|
||||
DOCS_LINK = get_var("links", "docs", default="https://github.com/chrisflav/kompass")
|
||||
REGISTRATION_FORM_DOWNLOAD_LINK = get_var(
|
||||
"links", "registration_form", default="https://startpage.com"
|
||||
)
|
||||
|
||||
# startpage
|
||||
|
||||
STARTPAGE_REDIRECT_URL = get_var('startpage', 'redirect_url', default='')
|
||||
ROOT_SECTION = get_var('startpage', 'root_section', default='about')
|
||||
RECENT_SECTION = get_var('startpage', 'recent_section', default='recent')
|
||||
REPORTS_SECTION = get_var('startpage', 'reports_section', default='reports')
|
||||
STARTPAGE_REDIRECT_URL = get_var("startpage", "redirect_url", default="")
|
||||
ROOT_SECTION = get_var("startpage", "root_section", default="about")
|
||||
RECENT_SECTION = get_var("startpage", "recent_section", default="recent")
|
||||
REPORTS_SECTION = get_var("startpage", "reports_section", default="reports")
|
||||
|
||||
# testing
|
||||
|
||||
TEST_MAIL = get_var('testing', 'mail', default='test@localhost')
|
||||
TEST_MAIL = get_var("testing", "mail", default="test@localhost")
|
||||
|
||||
@ -1,55 +1,58 @@
|
||||
# Generated by Django 4.0.1 on 2024-11-23 21:15
|
||||
|
||||
import django.contrib.auth.models
|
||||
from django.db import migrations, models
|
||||
from django.db import migrations
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('auth', '0012_alter_user_first_name_max_length'),
|
||||
("auth", "0012_alter_user_first_name_max_length"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='RegistrationPassword',
|
||||
name="RegistrationPassword",
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('password', models.CharField(max_length=100, verbose_name='Password')),
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
|
||||
),
|
||||
),
|
||||
("password", models.CharField(max_length=100, verbose_name="Password")),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='AuthGroup',
|
||||
fields=[
|
||||
],
|
||||
name="AuthGroup",
|
||||
fields=[],
|
||||
options={
|
||||
'verbose_name': 'Permission group',
|
||||
'verbose_name_plural': 'Permission groups',
|
||||
'proxy': True,
|
||||
'indexes': [],
|
||||
'constraints': [],
|
||||
"verbose_name": "Permission group",
|
||||
"verbose_name_plural": "Permission groups",
|
||||
"proxy": True,
|
||||
"indexes": [],
|
||||
"constraints": [],
|
||||
},
|
||||
bases=('auth.group',),
|
||||
bases=("auth.group",),
|
||||
managers=[
|
||||
('objects', django.contrib.auth.models.GroupManager()),
|
||||
("objects", django.contrib.auth.models.GroupManager()),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='LoginDatum',
|
||||
fields=[
|
||||
],
|
||||
name="LoginDatum",
|
||||
fields=[],
|
||||
options={
|
||||
'verbose_name': 'Login Datum',
|
||||
'verbose_name_plural': 'Login Data',
|
||||
'proxy': True,
|
||||
'indexes': [],
|
||||
'constraints': [],
|
||||
"verbose_name": "Login Datum",
|
||||
"verbose_name_plural": "Login Data",
|
||||
"proxy": True,
|
||||
"indexes": [],
|
||||
"constraints": [],
|
||||
},
|
||||
bases=('auth.user',),
|
||||
bases=("auth.user",),
|
||||
managers=[
|
||||
('objects', django.contrib.auth.models.UserManager()),
|
||||
("objects", django.contrib.auth.models.UserManager()),
|
||||
],
|
||||
),
|
||||
]
|
||||
|
||||
@ -1,2 +1,4 @@
|
||||
# ruff: noqa F403
|
||||
|
||||
from .oauth import *
|
||||
from .views import *
|
||||
from .oauth import *
|
||||
@ -1,46 +1,194 @@
|
||||
# Generated by Django 4.0.1 on 2023-03-29 20:40
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
from django.db import migrations
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
replaces = [('ludwigsburgalpin', '0001_initial'), ('ludwigsburgalpin', '0002_auto_20190926_1432'), ('ludwigsburgalpin', '0003_auto_20190926_1749'), ('ludwigsburgalpin', '0004_alter_termin_id'), ('ludwigsburgalpin', '0005_alter_termin_id'), ('ludwigsburgalpin', '0006_termin_anforderung_dauer_termin_anforderung_hoehe_and_more'), ('ludwigsburgalpin', '0007_alter_termin_group')]
|
||||
|
||||
dependencies = [
|
||||
replaces = [
|
||||
("ludwigsburgalpin", "0001_initial"),
|
||||
("ludwigsburgalpin", "0002_auto_20190926_1432"),
|
||||
("ludwigsburgalpin", "0003_auto_20190926_1749"),
|
||||
("ludwigsburgalpin", "0004_alter_termin_id"),
|
||||
("ludwigsburgalpin", "0005_alter_termin_id"),
|
||||
("ludwigsburgalpin", "0006_termin_anforderung_dauer_termin_anforderung_hoehe_and_more"),
|
||||
("ludwigsburgalpin", "0007_alter_termin_group"),
|
||||
]
|
||||
|
||||
dependencies = []
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Termin',
|
||||
name="Termin",
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.CharField(max_length=100, verbose_name='Titel')),
|
||||
('start_date', models.DateField(verbose_name='Von')),
|
||||
('end_date', models.DateField(verbose_name='Bis')),
|
||||
('group', models.CharField(choices=[('ASG', 'Alpinsportgruppe'), ('OGB', 'Ortsgruppe Bietigheim'), ('OGV', 'Ortsgruppe Vaihingen'), ('JUG', 'Jugend'), ('FAM', 'Familie'), ('Ü30', 'Ü30'), ('MTB', 'Mountainbike'), ('RA', 'RegioAktiv'), ('SEK', 'Sektion')], max_length=100, verbose_name='Gruppe')),
|
||||
('description', models.TextField(blank=True, verbose_name='Beschreibung')),
|
||||
('email', models.EmailField(max_length=100, verbose_name='Email')),
|
||||
('phone', models.CharField(blank=True, max_length=20, verbose_name='Telefonnumer')),
|
||||
('responsible', models.CharField(max_length=100, verbose_name='Organisator')),
|
||||
('anforderung_dauer', models.IntegerField(blank=True, default=0, validators=[django.core.validators.MinValueValidator(0)], verbose_name='Etappendauer in Stunden')),
|
||||
('anforderung_hoehe', models.IntegerField(blank=True, default=0, validators=[django.core.validators.MinValueValidator(0)], verbose_name='Höhenmeter in Meter')),
|
||||
('anforderung_strecke', models.IntegerField(blank=True, default=0, validators=[django.core.validators.MinValueValidator(0)], verbose_name='Strecke in Kilometer')),
|
||||
('category', models.CharField(choices=[('WAN', 'Wandern'), ('BW', 'Bergwandern'), ('KST', 'Klettersteig'), ('KL', 'Klettern'), ('SKI', 'Piste, Loipe'), ('SCH', 'Schneeschuhgehen'), ('ST', 'Skitour'), ('STH', 'Skihochtour'), ('HT', 'Hochtour'), ('MTB', 'Montainbike'), ('AUS', 'Ausbildung'), ('SON', 'Sonstiges z.B. Treffen')], default='SON', max_length=100, verbose_name='Kategorie')),
|
||||
('condition', models.CharField(choices=[('gering', 'gering'), ('mittel', 'mittel'), ('groß', 'groß'), ('sehr groß', 'sehr groß')], default='mittel', max_length=100, verbose_name='Kondition')),
|
||||
('equipment', models.TextField(blank=True, verbose_name='Ausrüstung')),
|
||||
('eventart', models.CharField(choices=[('Einzeltermin', 'Einzeltermin'), ('Mehrtagesevent', 'Mehrtagesevent'), ('Regelmäßiges Event/Training', 'Regelmäßiges Event/Training'), ('Tagesevent', 'Tagesevent'), ('Wochenendevent', 'Wochenendevent')], default='Einzeltermin', max_length=100, verbose_name='Eventart')),
|
||||
('klassifizierung', models.CharField(choices=[('Gemeinschaftstour', 'Gemeinschaftstour'), ('Ausbildung', 'Ausbildung')], default='Gemeinschaftstour', max_length=100, verbose_name='Klassifizierung')),
|
||||
('max_participants', models.IntegerField(default=10, validators=[django.core.validators.MinValueValidator(1)], verbose_name='Max. Teilnehmerzahl')),
|
||||
('saison', models.CharField(choices=[('ganzjährig', 'ganzjährig'), ('Indoor', 'Indoor'), ('Sommer', 'Sommer'), ('Winter', 'Winter')], default='ganzjährig', max_length=100, verbose_name='Saison')),
|
||||
('subtitle', models.CharField(blank=True, max_length=100, verbose_name='Untertitel')),
|
||||
('technik', models.CharField(choices=[('leicht', 'leicht'), ('mittel', 'mittel'), ('schwer', 'schwer'), ('sehr schwer', 'sehr schwer')], default='mittel', max_length=100, verbose_name='Technik')),
|
||||
('voraussetzungen', models.TextField(blank=True, verbose_name='Voraussetzungen')),
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
|
||||
),
|
||||
),
|
||||
("title", models.CharField(max_length=100, verbose_name="Titel")),
|
||||
("start_date", models.DateField(verbose_name="Von")),
|
||||
("end_date", models.DateField(verbose_name="Bis")),
|
||||
(
|
||||
"group",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("ASG", "Alpinsportgruppe"),
|
||||
("OGB", "Ortsgruppe Bietigheim"),
|
||||
("OGV", "Ortsgruppe Vaihingen"),
|
||||
("JUG", "Jugend"),
|
||||
("FAM", "Familie"),
|
||||
("Ü30", "Ü30"),
|
||||
("MTB", "Mountainbike"),
|
||||
("RA", "RegioAktiv"),
|
||||
("SEK", "Sektion"),
|
||||
],
|
||||
max_length=100,
|
||||
verbose_name="Gruppe",
|
||||
),
|
||||
),
|
||||
("description", models.TextField(blank=True, verbose_name="Beschreibung")),
|
||||
("email", models.EmailField(max_length=100, verbose_name="Email")),
|
||||
("phone", models.CharField(blank=True, max_length=20, verbose_name="Telefonnumer")),
|
||||
("responsible", models.CharField(max_length=100, verbose_name="Organisator")),
|
||||
(
|
||||
"anforderung_dauer",
|
||||
models.IntegerField(
|
||||
blank=True,
|
||||
default=0,
|
||||
validators=[django.core.validators.MinValueValidator(0)],
|
||||
verbose_name="Etappendauer in Stunden",
|
||||
),
|
||||
),
|
||||
(
|
||||
"anforderung_hoehe",
|
||||
models.IntegerField(
|
||||
blank=True,
|
||||
default=0,
|
||||
validators=[django.core.validators.MinValueValidator(0)],
|
||||
verbose_name="Höhenmeter in Meter",
|
||||
),
|
||||
),
|
||||
(
|
||||
"anforderung_strecke",
|
||||
models.IntegerField(
|
||||
blank=True,
|
||||
default=0,
|
||||
validators=[django.core.validators.MinValueValidator(0)],
|
||||
verbose_name="Strecke in Kilometer",
|
||||
),
|
||||
),
|
||||
(
|
||||
"category",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("WAN", "Wandern"),
|
||||
("BW", "Bergwandern"),
|
||||
("KST", "Klettersteig"),
|
||||
("KL", "Klettern"),
|
||||
("SKI", "Piste, Loipe"),
|
||||
("SCH", "Schneeschuhgehen"),
|
||||
("ST", "Skitour"),
|
||||
("STH", "Skihochtour"),
|
||||
("HT", "Hochtour"),
|
||||
("MTB", "Montainbike"),
|
||||
("AUS", "Ausbildung"),
|
||||
("SON", "Sonstiges z.B. Treffen"),
|
||||
],
|
||||
default="SON",
|
||||
max_length=100,
|
||||
verbose_name="Kategorie",
|
||||
),
|
||||
),
|
||||
(
|
||||
"condition",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("gering", "gering"),
|
||||
("mittel", "mittel"),
|
||||
("groß", "groß"),
|
||||
("sehr groß", "sehr groß"),
|
||||
],
|
||||
default="mittel",
|
||||
max_length=100,
|
||||
verbose_name="Kondition",
|
||||
),
|
||||
),
|
||||
("equipment", models.TextField(blank=True, verbose_name="Ausrüstung")),
|
||||
(
|
||||
"eventart",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("Einzeltermin", "Einzeltermin"),
|
||||
("Mehrtagesevent", "Mehrtagesevent"),
|
||||
("Regelmäßiges Event/Training", "Regelmäßiges Event/Training"),
|
||||
("Tagesevent", "Tagesevent"),
|
||||
("Wochenendevent", "Wochenendevent"),
|
||||
],
|
||||
default="Einzeltermin",
|
||||
max_length=100,
|
||||
verbose_name="Eventart",
|
||||
),
|
||||
),
|
||||
(
|
||||
"klassifizierung",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("Gemeinschaftstour", "Gemeinschaftstour"),
|
||||
("Ausbildung", "Ausbildung"),
|
||||
],
|
||||
default="Gemeinschaftstour",
|
||||
max_length=100,
|
||||
verbose_name="Klassifizierung",
|
||||
),
|
||||
),
|
||||
(
|
||||
"max_participants",
|
||||
models.IntegerField(
|
||||
default=10,
|
||||
validators=[django.core.validators.MinValueValidator(1)],
|
||||
verbose_name="Max. Teilnehmerzahl",
|
||||
),
|
||||
),
|
||||
(
|
||||
"saison",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("ganzjährig", "ganzjährig"),
|
||||
("Indoor", "Indoor"),
|
||||
("Sommer", "Sommer"),
|
||||
("Winter", "Winter"),
|
||||
],
|
||||
default="ganzjährig",
|
||||
max_length=100,
|
||||
verbose_name="Saison",
|
||||
),
|
||||
),
|
||||
(
|
||||
"subtitle",
|
||||
models.CharField(blank=True, max_length=100, verbose_name="Untertitel"),
|
||||
),
|
||||
(
|
||||
"technik",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("leicht", "leicht"),
|
||||
("mittel", "mittel"),
|
||||
("schwer", "schwer"),
|
||||
("sehr schwer", "sehr schwer"),
|
||||
],
|
||||
default="mittel",
|
||||
max_length=100,
|
||||
verbose_name="Technik",
|
||||
),
|
||||
),
|
||||
("voraussetzungen", models.TextField(blank=True, verbose_name="Voraussetzungen")),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'Termine',
|
||||
'verbose_name': 'Termin',
|
||||
"verbose_name_plural": "Termine",
|
||||
"verbose_name": "Termin",
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
@ -1,121 +1,128 @@
|
||||
from django.db import models
|
||||
from django.core.validators import MinValueValidator
|
||||
from django.db import models
|
||||
|
||||
GRUPPE = [
|
||||
('ASG', 'Alpinsportgruppe'),
|
||||
('OGB', 'Ortsgruppe Bietigheim'),
|
||||
('OGV', 'Ortsgruppe Vaihingen'),
|
||||
('JUG', 'Jugend'),
|
||||
('FAM', 'Familie'),
|
||||
('Ü30', 'Ü30'),
|
||||
('MTB', 'Mountainbike'),
|
||||
('RA', 'RegioAktiv'),
|
||||
('SEK', 'Sektion'),
|
||||
("ASG", "Alpinsportgruppe"),
|
||||
("OGB", "Ortsgruppe Bietigheim"),
|
||||
("OGV", "Ortsgruppe Vaihingen"),
|
||||
("JUG", "Jugend"),
|
||||
("FAM", "Familie"),
|
||||
("Ü30", "Ü30"),
|
||||
("MTB", "Mountainbike"),
|
||||
("RA", "RegioAktiv"),
|
||||
("SEK", "Sektion"),
|
||||
]
|
||||
KATEGORIE = [
|
||||
('WAN', 'Wandern'),
|
||||
('BW', 'Bergwandern'),
|
||||
('KST', 'Klettersteig'),
|
||||
('KL', 'Klettern'),
|
||||
('SKI', 'Piste, Loipe'),
|
||||
('SCH', 'Schneeschuhgehen'),
|
||||
('ST', 'Skitour'),
|
||||
('STH', 'Skihochtour'),
|
||||
('HT', 'Hochtour'),
|
||||
('MTB', 'Montainbike'),
|
||||
('AUS', 'Ausbildung'),
|
||||
('SON', 'Sonstiges z.B. Treffen')
|
||||
("WAN", "Wandern"),
|
||||
("BW", "Bergwandern"),
|
||||
("KST", "Klettersteig"),
|
||||
("KL", "Klettern"),
|
||||
("SKI", "Piste, Loipe"),
|
||||
("SCH", "Schneeschuhgehen"),
|
||||
("ST", "Skitour"),
|
||||
("STH", "Skihochtour"),
|
||||
("HT", "Hochtour"),
|
||||
("MTB", "Montainbike"),
|
||||
("AUS", "Ausbildung"),
|
||||
("SON", "Sonstiges z.B. Treffen"),
|
||||
]
|
||||
KONDITION = [
|
||||
('gering', 'gering'),
|
||||
('mittel', 'mittel'),
|
||||
('groß', 'groß'),
|
||||
('sehr groß', 'sehr groß'),
|
||||
("gering", "gering"),
|
||||
("mittel", "mittel"),
|
||||
("groß", "groß"),
|
||||
("sehr groß", "sehr groß"),
|
||||
]
|
||||
TECHNIK = [
|
||||
('leicht', 'leicht'),
|
||||
('mittel', 'mittel'),
|
||||
('schwer', 'schwer'),
|
||||
('sehr schwer', 'sehr schwer'),
|
||||
("leicht", "leicht"),
|
||||
("mittel", "mittel"),
|
||||
("schwer", "schwer"),
|
||||
("sehr schwer", "sehr schwer"),
|
||||
]
|
||||
SAISON = [
|
||||
('ganzjährig','ganzjährig'),
|
||||
('Indoor', 'Indoor'),
|
||||
('Sommer', 'Sommer'),
|
||||
('Winter', 'Winter'),
|
||||
("ganzjährig", "ganzjährig"),
|
||||
("Indoor", "Indoor"),
|
||||
("Sommer", "Sommer"),
|
||||
("Winter", "Winter"),
|
||||
]
|
||||
EVENTART = [
|
||||
('Einzeltermin', 'Einzeltermin',),
|
||||
('Mehrtagesevent', 'Mehrtagesevent',),
|
||||
('Regelmäßiges Event/Training', 'Regelmäßiges Event/Training',),
|
||||
('Tagesevent', 'Tagesevent',),
|
||||
('Wochenendevent', 'Wochenendevent',),
|
||||
(
|
||||
"Einzeltermin",
|
||||
"Einzeltermin",
|
||||
),
|
||||
(
|
||||
"Mehrtagesevent",
|
||||
"Mehrtagesevent",
|
||||
),
|
||||
(
|
||||
"Regelmäßiges Event/Training",
|
||||
"Regelmäßiges Event/Training",
|
||||
),
|
||||
(
|
||||
"Tagesevent",
|
||||
"Tagesevent",
|
||||
),
|
||||
(
|
||||
"Wochenendevent",
|
||||
"Wochenendevent",
|
||||
),
|
||||
]
|
||||
KLASSIFIZIERUNG = [
|
||||
('Gemeinschaftstour', 'Gemeinschaftstour'),
|
||||
('Ausbildung', 'Ausbildung'),
|
||||
("Gemeinschaftstour", "Gemeinschaftstour"),
|
||||
("Ausbildung", "Ausbildung"),
|
||||
]
|
||||
|
||||
|
||||
# Create your models here.
|
||||
class Termin(models.Model):
|
||||
title = models.CharField('Titel', max_length=100)
|
||||
subtitle = models.CharField('Untertitel', max_length=100, blank=True)
|
||||
start_date = models.DateField('Von')
|
||||
end_date = models.DateField('Bis')
|
||||
group = models.CharField('Gruppe',
|
||||
choices=GRUPPE,
|
||||
max_length=100)
|
||||
responsible = models.CharField('Organisator', max_length=100, blank=False)
|
||||
phone = models.CharField(max_length=20, verbose_name='Telefonnumer', blank=True)
|
||||
email = models.EmailField(max_length=100, verbose_name='Email', blank=False)
|
||||
category = models.CharField('Kategorie', blank=False, choices=KATEGORIE, max_length=100,
|
||||
default='SON')
|
||||
condition = models.CharField('Kondition', blank=False, choices=KONDITION, max_length=100,
|
||||
default='mittel')
|
||||
technik = models.CharField('Technik', blank=False, choices=TECHNIK, max_length=100,
|
||||
default='mittel')
|
||||
saison = models.CharField('Saison', blank=False, choices=SAISON, max_length=100,
|
||||
default='ganzjährig')
|
||||
eventart = models.CharField('Eventart', blank=False, choices=EVENTART, max_length=100,
|
||||
default='Einzeltermin')
|
||||
klassifizierung = models.CharField('Klassifizierung', blank=False, choices=KLASSIFIZIERUNG,
|
||||
max_length=100,
|
||||
default='Gemeinschaftstour')
|
||||
equipment = models.TextField('Ausrüstung',
|
||||
blank=True)
|
||||
voraussetzungen = models.TextField('Voraussetzungen',
|
||||
blank=True)
|
||||
description = models.TextField('Beschreibung',
|
||||
blank=True)
|
||||
max_participants = models.IntegerField('Max. Teilnehmerzahl',
|
||||
blank=False,
|
||||
validators=[
|
||||
MinValueValidator(1)
|
||||
],
|
||||
default=10)
|
||||
anforderung_hoehe = models.IntegerField('Höhenmeter in Meter',
|
||||
blank=True,
|
||||
validators=[
|
||||
MinValueValidator(0)
|
||||
],
|
||||
default=0)
|
||||
anforderung_strecke = models.IntegerField('Strecke in Kilometer',
|
||||
blank=True,
|
||||
validators=[
|
||||
MinValueValidator(0)
|
||||
],
|
||||
default=0)
|
||||
anforderung_dauer = models.IntegerField('Etappendauer in Stunden',
|
||||
blank=True,
|
||||
validators=[
|
||||
MinValueValidator(0)
|
||||
],
|
||||
default=0)
|
||||
title = models.CharField("Titel", max_length=100)
|
||||
subtitle = models.CharField("Untertitel", max_length=100, blank=True)
|
||||
start_date = models.DateField("Von")
|
||||
end_date = models.DateField("Bis")
|
||||
group = models.CharField("Gruppe", choices=GRUPPE, max_length=100)
|
||||
responsible = models.CharField("Organisator", max_length=100, blank=False)
|
||||
phone = models.CharField(max_length=20, verbose_name="Telefonnumer", blank=True)
|
||||
email = models.EmailField(max_length=100, verbose_name="Email", blank=False)
|
||||
category = models.CharField(
|
||||
"Kategorie", blank=False, choices=KATEGORIE, max_length=100, default="SON"
|
||||
)
|
||||
condition = models.CharField(
|
||||
"Kondition", blank=False, choices=KONDITION, max_length=100, default="mittel"
|
||||
)
|
||||
technik = models.CharField(
|
||||
"Technik", blank=False, choices=TECHNIK, max_length=100, default="mittel"
|
||||
)
|
||||
saison = models.CharField(
|
||||
"Saison", blank=False, choices=SAISON, max_length=100, default="ganzjährig"
|
||||
)
|
||||
eventart = models.CharField(
|
||||
"Eventart", blank=False, choices=EVENTART, max_length=100, default="Einzeltermin"
|
||||
)
|
||||
klassifizierung = models.CharField(
|
||||
"Klassifizierung",
|
||||
blank=False,
|
||||
choices=KLASSIFIZIERUNG,
|
||||
max_length=100,
|
||||
default="Gemeinschaftstour",
|
||||
)
|
||||
equipment = models.TextField("Ausrüstung", blank=True)
|
||||
voraussetzungen = models.TextField("Voraussetzungen", blank=True)
|
||||
description = models.TextField("Beschreibung", blank=True)
|
||||
max_participants = models.IntegerField(
|
||||
"Max. Teilnehmerzahl", blank=False, validators=[MinValueValidator(1)], default=10
|
||||
)
|
||||
anforderung_hoehe = models.IntegerField(
|
||||
"Höhenmeter in Meter", blank=True, validators=[MinValueValidator(0)], default=0
|
||||
)
|
||||
anforderung_strecke = models.IntegerField(
|
||||
"Strecke in Kilometer", blank=True, validators=[MinValueValidator(0)], default=0
|
||||
)
|
||||
anforderung_dauer = models.IntegerField(
|
||||
"Etappendauer in Stunden", blank=True, validators=[MinValueValidator(0)], default=0
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return "{} {}".format(self.title, str(self.group))
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'Termin'
|
||||
verbose_name_plural = 'Termine'
|
||||
verbose_name = "Termin"
|
||||
verbose_name_plural = "Termine"
|
||||
|
||||
@ -1,100 +1,89 @@
|
||||
from django.shortcuts import render
|
||||
from django import forms
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.contrib.admin import widgets
|
||||
from django.core.validators import MinValueValidator
|
||||
from .models import Termin, GRUPPE, KATEGORIE, KONDITION, TECHNIK, SAISON, EVENTART, KLASSIFIZIERUNG
|
||||
from django.shortcuts import render
|
||||
|
||||
datepicker = forms.TextInput(attrs={'class': 'datepicker'})
|
||||
from .models import EVENTART
|
||||
from .models import GRUPPE
|
||||
from .models import KATEGORIE
|
||||
from .models import KLASSIFIZIERUNG
|
||||
from .models import KONDITION
|
||||
from .models import SAISON
|
||||
from .models import TECHNIK
|
||||
from .models import Termin
|
||||
|
||||
datepicker = forms.TextInput(attrs={"class": "datepicker"})
|
||||
|
||||
class TerminForm(forms.Form):
|
||||
|
||||
|
||||
title = forms.CharField(label='Titel')
|
||||
subtitle = forms.CharField(label='Untertitel')
|
||||
start_date = forms.DateField(label='Von',
|
||||
widget=datepicker)
|
||||
end_date = forms.DateField(label='Bis',
|
||||
widget=datepicker)
|
||||
group = forms.ChoiceField(label='Gruppe',
|
||||
required=True,
|
||||
choices=GRUPPE)
|
||||
category = forms.ChoiceField(label='Kategorie', required=True, choices=KATEGORIE)
|
||||
condition = forms.ChoiceField(label='Kondition', required=True, choices=KONDITION)
|
||||
technik = forms.ChoiceField(label='Technik', required=True, choices=TECHNIK)
|
||||
saison = forms.ChoiceField(label='Saison', required=True, choices=SAISON)
|
||||
eventart = forms.ChoiceField(label='Eventart', required=True, choices=EVENTART)
|
||||
klassifizierung = forms.ChoiceField(label='Klassifizierung', required=True, choices=KLASSIFIZIERUNG)
|
||||
anforderung_hoehe = forms.IntegerField(label='Höhenmeter in Metern',
|
||||
required=True,
|
||||
validators=[
|
||||
MinValueValidator(0)
|
||||
])
|
||||
anforderung_strecke = forms.IntegerField(label='Strecke in Kilometern',
|
||||
required=True,
|
||||
validators=[
|
||||
MinValueValidator(0)
|
||||
])
|
||||
anforderung_dauer = forms.IntegerField(label='Etappendauer in Stunden',
|
||||
required=True,
|
||||
validators=[
|
||||
MinValueValidator(0)
|
||||
])
|
||||
description = forms.CharField(label='Beschreibung',
|
||||
widget=forms.Textarea,
|
||||
required=False)
|
||||
equipment = forms.CharField(label='Ausrüstung',
|
||||
widget=forms.Textarea,
|
||||
required=False)
|
||||
voraussetzungen = forms.CharField(label='Voraussetzungen',
|
||||
widget=forms.Textarea,
|
||||
required=False)
|
||||
max_participants = forms.IntegerField(label='Max. Teilnehmerzahl',
|
||||
required=True,
|
||||
validators=[
|
||||
MinValueValidator(1)
|
||||
])
|
||||
responsible = forms.CharField(label='Organisator', max_length=100,
|
||||
required=False)
|
||||
phone = forms.CharField(max_length=20, label='Telefonnumer',
|
||||
required=False)
|
||||
email = forms.EmailField(max_length=100, label='Email',
|
||||
required=False)
|
||||
class TerminForm(forms.Form):
|
||||
title = forms.CharField(label="Titel")
|
||||
subtitle = forms.CharField(label="Untertitel")
|
||||
start_date = forms.DateField(label="Von", widget=datepicker)
|
||||
end_date = forms.DateField(label="Bis", widget=datepicker)
|
||||
group = forms.ChoiceField(label="Gruppe", required=True, choices=GRUPPE)
|
||||
category = forms.ChoiceField(label="Kategorie", required=True, choices=KATEGORIE)
|
||||
condition = forms.ChoiceField(label="Kondition", required=True, choices=KONDITION)
|
||||
technik = forms.ChoiceField(label="Technik", required=True, choices=TECHNIK)
|
||||
saison = forms.ChoiceField(label="Saison", required=True, choices=SAISON)
|
||||
eventart = forms.ChoiceField(label="Eventart", required=True, choices=EVENTART)
|
||||
klassifizierung = forms.ChoiceField(
|
||||
label="Klassifizierung", required=True, choices=KLASSIFIZIERUNG
|
||||
)
|
||||
anforderung_hoehe = forms.IntegerField(
|
||||
label="Höhenmeter in Metern", required=True, validators=[MinValueValidator(0)]
|
||||
)
|
||||
anforderung_strecke = forms.IntegerField(
|
||||
label="Strecke in Kilometern", required=True, validators=[MinValueValidator(0)]
|
||||
)
|
||||
anforderung_dauer = forms.IntegerField(
|
||||
label="Etappendauer in Stunden", required=True, validators=[MinValueValidator(0)]
|
||||
)
|
||||
description = forms.CharField(label="Beschreibung", widget=forms.Textarea, required=False)
|
||||
equipment = forms.CharField(label="Ausrüstung", widget=forms.Textarea, required=False)
|
||||
voraussetzungen = forms.CharField(
|
||||
label="Voraussetzungen", widget=forms.Textarea, required=False
|
||||
)
|
||||
max_participants = forms.IntegerField(
|
||||
label="Max. Teilnehmerzahl", required=True, validators=[MinValueValidator(1)]
|
||||
)
|
||||
responsible = forms.CharField(label="Organisator", max_length=100, required=False)
|
||||
phone = forms.CharField(max_length=20, label="Telefonnumer", required=False)
|
||||
email = forms.EmailField(max_length=100, label="Email", required=False)
|
||||
|
||||
|
||||
# Create your views here.
|
||||
def index(request, *args):
|
||||
if request.method == 'POST':
|
||||
if request.method == "POST":
|
||||
form = TerminForm(request.POST)
|
||||
if form.is_valid():
|
||||
termin = Termin(title=form.cleaned_data["title"],
|
||||
subtitle=form.cleaned_data["subtitle"],
|
||||
start_date=form.cleaned_data["start_date"],
|
||||
end_date=form.cleaned_data["end_date"],
|
||||
group=form.cleaned_data["group"],
|
||||
responsible=form.cleaned_data["responsible"],
|
||||
phone=form.cleaned_data["phone"],
|
||||
email=form.cleaned_data["email"],
|
||||
category=form.cleaned_data["category"],
|
||||
condition=form.cleaned_data["condition"],
|
||||
technik=form.cleaned_data["technik"],
|
||||
saison=form.cleaned_data["saison"],
|
||||
eventart=form.cleaned_data["eventart"],
|
||||
klassifizierung=form.cleaned_data["klassifizierung"],
|
||||
equipment=form.cleaned_data["equipment"],
|
||||
voraussetzungen=form.cleaned_data["voraussetzungen"],
|
||||
max_participants=form.cleaned_data["max_participants"],
|
||||
anforderung_hoehe=form.cleaned_data["anforderung_hoehe"],
|
||||
anforderung_strecke=form.cleaned_data["anforderung_strecke"],
|
||||
anforderung_dauer=form.cleaned_data["anforderung_dauer"],
|
||||
description=form.cleaned_data["description"])
|
||||
termin = Termin(
|
||||
title=form.cleaned_data["title"],
|
||||
subtitle=form.cleaned_data["subtitle"],
|
||||
start_date=form.cleaned_data["start_date"],
|
||||
end_date=form.cleaned_data["end_date"],
|
||||
group=form.cleaned_data["group"],
|
||||
responsible=form.cleaned_data["responsible"],
|
||||
phone=form.cleaned_data["phone"],
|
||||
email=form.cleaned_data["email"],
|
||||
category=form.cleaned_data["category"],
|
||||
condition=form.cleaned_data["condition"],
|
||||
technik=form.cleaned_data["technik"],
|
||||
saison=form.cleaned_data["saison"],
|
||||
eventart=form.cleaned_data["eventart"],
|
||||
klassifizierung=form.cleaned_data["klassifizierung"],
|
||||
equipment=form.cleaned_data["equipment"],
|
||||
voraussetzungen=form.cleaned_data["voraussetzungen"],
|
||||
max_participants=form.cleaned_data["max_participants"],
|
||||
anforderung_hoehe=form.cleaned_data["anforderung_hoehe"],
|
||||
anforderung_strecke=form.cleaned_data["anforderung_strecke"],
|
||||
anforderung_dauer=form.cleaned_data["anforderung_dauer"],
|
||||
description=form.cleaned_data["description"],
|
||||
)
|
||||
termin.save()
|
||||
return published(request)
|
||||
else:
|
||||
form = TerminForm()
|
||||
return render(request, 'ludwigsburgalpin/termine.html', {'form': form.as_table()})
|
||||
return render(request, "ludwigsburgalpin/termine.html", {"form": form.as_table()})
|
||||
|
||||
|
||||
def published(request):
|
||||
return render(request, 'ludwigsburgalpin/published.html')
|
||||
return render(request, "ludwigsburgalpin/published.html")
|
||||
|
||||
@ -1,79 +1,165 @@
|
||||
# Generated by Django 4.0.1 on 2023-03-29 20:38
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import utils
|
||||
from django.db import migrations
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
replaces = [('mailer', '0001_initial'), ('mailer', '0002_auto_20190615_1225'), ('mailer', '0003_emailaddress'), ('mailer', '0004_auto_20200924_1744'), ('mailer', '0005_auto_20200924_2139'), ('mailer', '0006_auto_20210924_1155')]
|
||||
replaces = [
|
||||
("mailer", "0001_initial"),
|
||||
("mailer", "0002_auto_20190615_1225"),
|
||||
("mailer", "0003_emailaddress"),
|
||||
("mailer", "0004_auto_20200924_1744"),
|
||||
("mailer", "0005_auto_20200924_2139"),
|
||||
("mailer", "0006_auto_20210924_1155"),
|
||||
]
|
||||
|
||||
dependencies = [
|
||||
('members', '0006_auto_20190914_2341'),
|
||||
('members', '0008_auto_20210924_1155'),
|
||||
('members', '0001_initial'),
|
||||
('members', '0007_auto_20200924_1512'),
|
||||
('members', '0005_auto_20190615_1224'),
|
||||
("members", "0006_auto_20190914_2341"),
|
||||
("members", "0008_auto_20210924_1155"),
|
||||
("members", "0001_initial"),
|
||||
("members", "0007_auto_20200924_1512"),
|
||||
("members", "0005_auto_20190615_1224"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Message',
|
||||
name="Message",
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('subject', models.CharField(max_length=50, verbose_name='subject')),
|
||||
('content', models.TextField(verbose_name='content')),
|
||||
('sent', models.BooleanField(default=False, verbose_name='sent')),
|
||||
('to_groups', models.ManyToManyField(blank=True, to='members.Group', verbose_name='to group')),
|
||||
('to_members', models.ManyToManyField(blank=True, to='members.Member', verbose_name='to member')),
|
||||
('reply_to', models.ManyToManyField(blank=True, related_name='reply_to', to='members.Member', verbose_name='reply to participant')),
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
|
||||
),
|
||||
),
|
||||
("subject", models.CharField(max_length=50, verbose_name="subject")),
|
||||
("content", models.TextField(verbose_name="content")),
|
||||
("sent", models.BooleanField(default=False, verbose_name="sent")),
|
||||
(
|
||||
"to_groups",
|
||||
models.ManyToManyField(blank=True, to="members.Group", verbose_name="to group"),
|
||||
),
|
||||
(
|
||||
"to_members",
|
||||
models.ManyToManyField(
|
||||
blank=True, to="members.Member", verbose_name="to member"
|
||||
),
|
||||
),
|
||||
(
|
||||
"reply_to",
|
||||
models.ManyToManyField(
|
||||
blank=True,
|
||||
related_name="reply_to",
|
||||
to="members.Member",
|
||||
verbose_name="reply to participant",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'messages',
|
||||
'permissions': (('submit_mails', 'Can submit mails'),),
|
||||
'verbose_name': 'message',
|
||||
"verbose_name_plural": "messages",
|
||||
"permissions": (("submit_mails", "Can submit mails"),),
|
||||
"verbose_name": "message",
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Attachment',
|
||||
name="Attachment",
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('f', utils.RestrictedFileField(blank=True, upload_to='attachments', verbose_name='file')),
|
||||
('msg', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mailer.message')),
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
|
||||
),
|
||||
),
|
||||
(
|
||||
"f",
|
||||
utils.RestrictedFileField(
|
||||
blank=True, upload_to="attachments", verbose_name="file"
|
||||
),
|
||||
),
|
||||
(
|
||||
"msg",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE, to="mailer.message"
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'attachments',
|
||||
'verbose_name': 'attachment',
|
||||
"verbose_name_plural": "attachments",
|
||||
"verbose_name": "attachment",
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='EmailAddress',
|
||||
name="EmailAddress",
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=50, validators=[django.core.validators.RegexValidator('^[0-9a-zA-Z]*$', 'Only alphanumeric characters are allowed')], verbose_name='name')),
|
||||
('to_members', models.ManyToManyField(blank=True, to='members.Member', verbose_name='Forward to participants')),
|
||||
('to_groups', models.ManyToManyField(blank=True, to='members.Group', verbose_name='Forward to group')),
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
|
||||
),
|
||||
),
|
||||
(
|
||||
"name",
|
||||
models.CharField(
|
||||
max_length=50,
|
||||
validators=[
|
||||
django.core.validators.RegexValidator(
|
||||
"^[0-9a-zA-Z]*$", "Only alphanumeric characters are allowed"
|
||||
)
|
||||
],
|
||||
verbose_name="name",
|
||||
),
|
||||
),
|
||||
(
|
||||
"to_members",
|
||||
models.ManyToManyField(
|
||||
blank=True, to="members.Member", verbose_name="Forward to participants"
|
||||
),
|
||||
),
|
||||
(
|
||||
"to_groups",
|
||||
models.ManyToManyField(
|
||||
blank=True, to="members.Group", verbose_name="Forward to group"
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'email addresses',
|
||||
'verbose_name': 'email address',
|
||||
"verbose_name_plural": "email addresses",
|
||||
"verbose_name": "email address",
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='message',
|
||||
name='reply_to_email_address',
|
||||
field=models.ManyToManyField(blank=True, related_name='reply_to_email_addr', to='mailer.EmailAddress', verbose_name='reply to custom email address'),
|
||||
model_name="message",
|
||||
name="reply_to_email_address",
|
||||
field=models.ManyToManyField(
|
||||
blank=True,
|
||||
related_name="reply_to_email_addr",
|
||||
to="mailer.EmailAddress",
|
||||
verbose_name="reply to custom email address",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='message',
|
||||
name='to_freizeit',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='members.freizeit', verbose_name='to freizeit'),
|
||||
model_name="message",
|
||||
name="to_freizeit",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="members.freizeit",
|
||||
verbose_name="to freizeit",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='message',
|
||||
name='to_notelist',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='members.membernotelist', verbose_name='to notes list'),
|
||||
model_name="message",
|
||||
name="to_notelist",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="members.membernotelist",
|
||||
verbose_name="to notes list",
|
||||
),
|
||||
),
|
||||
]
|
||||
|
||||
@ -1,20 +1,27 @@
|
||||
# Generated by Django 4.0.1 on 2023-04-02 12:06
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('members', '0006_rename_permissions'),
|
||||
('mailer', '0001_initial_squashed_0006_auto_20210924_1155'),
|
||||
("members", "0006_rename_permissions"),
|
||||
("mailer", "0001_initial_squashed_0006_auto_20210924_1155"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='message',
|
||||
name='created_by',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='created_messages', to='members.member', verbose_name='Created by'),
|
||||
model_name="message",
|
||||
name="created_by",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="created_messages",
|
||||
to="members.member",
|
||||
verbose_name="Created by",
|
||||
),
|
||||
),
|
||||
]
|
||||
|
||||
@ -1,19 +1,18 @@
|
||||
# Generated by Django 4.0.1 on 2024-11-17 23:31
|
||||
|
||||
from django.db import migrations
|
||||
import utils
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('mailer', '0003_alter_message_options'),
|
||||
("mailer", "0003_alter_message_options"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='attachment',
|
||||
name='f',
|
||||
field=utils.RestrictedFileField(upload_to='attachments', verbose_name='file'),
|
||||
model_name="attachment",
|
||||
name="f",
|
||||
field=utils.RestrictedFileField(upload_to="attachments", verbose_name="file"),
|
||||
),
|
||||
]
|
||||
|
||||
@ -1,19 +1,27 @@
|
||||
# Generated by Django 4.0.1 on 2024-11-23 14:03
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
from django.db import migrations
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('mailer', '0004_alter_attachment_f'),
|
||||
("mailer", "0004_alter_attachment_f"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='emailaddress',
|
||||
name='name',
|
||||
field=models.CharField(max_length=50, validators=[django.core.validators.RegexValidator('^[0-9a-zA-Z._-]*$', 'Only alphanumeric characters, ., - and _ are allowed')], verbose_name='name'),
|
||||
model_name="emailaddress",
|
||||
name="name",
|
||||
field=models.CharField(
|
||||
max_length=50,
|
||||
validators=[
|
||||
django.core.validators.RegexValidator(
|
||||
"^[0-9a-zA-Z._-]*$", "Only alphanumeric characters, ., - and _ are allowed"
|
||||
)
|
||||
],
|
||||
verbose_name="name",
|
||||
),
|
||||
),
|
||||
]
|
||||
|
||||
@ -1,19 +1,25 @@
|
||||
# Generated by Django 4.0.1 on 2024-12-01 15:54
|
||||
|
||||
from django.db import migrations, models
|
||||
from django.db import migrations
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('members', '0029_alter_member_gender_alter_memberwaitinglist_gender'),
|
||||
('mailer', '0005_alter_emailaddress_name'),
|
||||
("members", "0029_alter_member_gender_alter_memberwaitinglist_gender"),
|
||||
("mailer", "0005_alter_emailaddress_name"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='emailaddress',
|
||||
name='allowed_senders',
|
||||
field=models.ManyToManyField(blank=True, help_text='Only forward e-mails of members of selected groups. Leave empty to allow all senders.', related_name='allowed_sender_on_emailaddresses', to='members.Group', verbose_name='Allowed sender'),
|
||||
model_name="emailaddress",
|
||||
name="allowed_senders",
|
||||
field=models.ManyToManyField(
|
||||
blank=True,
|
||||
help_text="Only forward e-mails of members of selected groups. Leave empty to allow all senders.",
|
||||
related_name="allowed_sender_on_emailaddresses",
|
||||
to="members.Group",
|
||||
verbose_name="Allowed sender",
|
||||
),
|
||||
),
|
||||
]
|
||||
|
||||
@ -1,18 +1,22 @@
|
||||
# Generated by Django 4.0.1 on 2024-12-01 17:45
|
||||
|
||||
from django.db import migrations, models
|
||||
from django.db import migrations
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('mailer', '0006_emailaddress_allowed_senders'),
|
||||
("mailer", "0006_emailaddress_allowed_senders"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='emailaddress',
|
||||
name='internal_only',
|
||||
field=models.BooleanField(default=False, help_text='Only allow forwarding to this e-mail address from the internal domain.', verbose_name='Restrict to internal email addresses'),
|
||||
model_name="emailaddress",
|
||||
name="internal_only",
|
||||
field=models.BooleanField(
|
||||
default=False,
|
||||
help_text="Only allow forwarding to this e-mail address from the internal domain.",
|
||||
verbose_name="Restrict to internal email addresses",
|
||||
),
|
||||
),
|
||||
]
|
||||
|
||||
@ -1,19 +1,28 @@
|
||||
# Generated by Django 4.0.1 on 2024-12-03 23:19
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
from django.db import migrations
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('mailer', '0007_emailaddress_internal_only'),
|
||||
("mailer", "0007_emailaddress_internal_only"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='emailaddress',
|
||||
name='name',
|
||||
field=models.CharField(max_length=50, unique=True, validators=[django.core.validators.RegexValidator('^[0-9a-zA-Z._-]*$', 'Only alphanumeric characters, ., - and _ are allowed')], verbose_name='name'),
|
||||
model_name="emailaddress",
|
||||
name="name",
|
||||
field=models.CharField(
|
||||
max_length=50,
|
||||
unique=True,
|
||||
validators=[
|
||||
django.core.validators.RegexValidator(
|
||||
"^[0-9a-zA-Z._-]*$", "Only alphanumeric characters, ., - and _ are allowed"
|
||||
)
|
||||
],
|
||||
verbose_name="name",
|
||||
),
|
||||
),
|
||||
]
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
from .models import *
|
||||
# ruff: noqa F403
|
||||
|
||||
from .admin import *
|
||||
from .views import *
|
||||
from .rules import *
|
||||
from .mailutils import *
|
||||
from .models import *
|
||||
from .rules import *
|
||||
from .views import *
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue