From 9ebf2ba0a5d00a46527c73a6b2fa011fc0d87bfa Mon Sep 17 00:00:00 2001 From: andis Date: Sun, 10 Jan 2021 07:13:28 +0000 Subject: [PATCH 01/15] build dev 2020 DockerImages --- deployment/dev_nginx/Dockerfile | 2 + deployment/dev_nginx/build_and_push | 3 ++ deployment/dev_nginx/nginxdev.conf | 67 +++++++++++++++++++++++++++ deployment/dev_theia/Dockerfile | 5 ++ deployment/dev_theia/build_and_push | 3 ++ deployment/dev_theia/requirements.txt | 16 +++++++ 6 files changed, 96 insertions(+) create mode 100644 deployment/dev_nginx/Dockerfile create mode 100755 deployment/dev_nginx/build_and_push create mode 100644 deployment/dev_nginx/nginxdev.conf create mode 100644 deployment/dev_theia/Dockerfile create mode 100755 deployment/dev_theia/build_and_push create mode 100644 deployment/dev_theia/requirements.txt diff --git a/deployment/dev_nginx/Dockerfile b/deployment/dev_nginx/Dockerfile new file mode 100644 index 00000000..a157b5c9 --- /dev/null +++ b/deployment/dev_nginx/Dockerfile @@ -0,0 +1,2 @@ +from nginx:alpine +copy nginxdev.conf /etc/nginx/conf.d/default.conf \ No newline at end of file diff --git a/deployment/dev_nginx/build_and_push b/deployment/dev_nginx/build_and_push new file mode 100755 index 00000000..fff38493 --- /dev/null +++ b/deployment/dev_nginx/build_and_push @@ -0,0 +1,3 @@ +cp ../nginxdev.conf . +docker build . -t docker.triton2.fet.at/nginxdev-fet2020:latest +docker image push docker.triton2.fet.at/nginxdev-fet2020:latest \ No newline at end of file diff --git a/deployment/dev_nginx/nginxdev.conf b/deployment/dev_nginx/nginxdev.conf new file mode 100644 index 00000000..35267064 --- /dev/null +++ b/deployment/dev_nginx/nginxdev.conf @@ -0,0 +1,67 @@ +server { + listen 8080; + error_log /var/log/nginx/error.log notice; + rewrite_log on; + resolver 127.0.0.11 valid=30s; + set $theia theia; + set $flaskfetfotos "flaskfetfotos:8080"; + set $etherpad "etherpad:9001"; + location /fotos { + proxy_ssl_server_name on; + proxy_ssl_verify off; + + proxy_pass http://$flaskfetfotos; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + # proxy_set_header REMOTE-USER $http_REMOTE_USER; +# proxy_set_header X-Forwarded-User $http_REMOTE_USER; +# proxy_set_header x-forwarded-user $http_REMOTE_USER; + proxy_set_header Connection "upgrade"; + + + } + + location /etherpad { + + rewrite /etherpad/(.*) /$1 break; + rewrite ^/etherpad$ /etherpad/ permanent; + + proxy_pass http://$etherpad; + proxy_redirect / /etherpad/; + proxy_set_header Host $host; + proxy_buffering off; + + } + location /dev { + rewrite_log on; + rewrite /dev/(.*) /$1 break; + rewrite ^/dev$ /dev/ permanent; + proxy_set_header Host $host; + proxy_set_header Proxy ""; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarde-Proto $scheme; + + + proxy_buffering off; + proxy_pass http://$theia:3000; + } + + location / { + proxy_set_header Host $host; + proxy_set_header Proxy ""; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarde-Proto $scheme; + + + proxy_buffering off; + + proxy_pass http://$theia:8000; + + } +} diff --git a/deployment/dev_theia/Dockerfile b/deployment/dev_theia/Dockerfile new file mode 100644 index 00000000..fa58a392 --- /dev/null +++ b/deployment/dev_theia/Dockerfile @@ -0,0 +1,5 @@ +from theiaide/theia-python:latest +run apt-get update && apt-get -y install libgs-dev +COPY ./requirements.txt . +run pip3 install --upgrade pip && pip3 install -r requirements.txt && pip3 install pytest pylint bandit flake8 black pytest-django six pytest-mock +ENTRYPOINT node /home/theia/src-gen/backend/main.js /home/project/.theia-workspace --hostname=0.0.0.0 \ No newline at end of file diff --git a/deployment/dev_theia/build_and_push b/deployment/dev_theia/build_and_push new file mode 100755 index 00000000..e79a0260 --- /dev/null +++ b/deployment/dev_theia/build_and_push @@ -0,0 +1,3 @@ +cp ../../fet2020/requirements.txt . +docker build . -t docker.triton2.fet.at/theia-fet2020:latest +docker image push docker.triton2.fet.at/theia-fet2020:latest \ No newline at end of file diff --git a/deployment/dev_theia/requirements.txt b/deployment/dev_theia/requirements.txt new file mode 100644 index 00000000..c3e5fcb5 --- /dev/null +++ b/deployment/dev_theia/requirements.txt @@ -0,0 +1,16 @@ +django==3.1.4 +django-ckeditor==6.0.0 +django-crontab==0.7.1 +django-environ==0.4.5 +django-filter==2.4.0 +django-static-jquery-ui==1.12.1.1 +django-softhyphen==1.1.0 +django-taggit==1.3.0 +djangorestframework==3.12.2 +configparser==5.0.1 +docutils==0.16 +easy-thumbnails==2.7.1 +etherpad-lite==0.5 +ghostscript==0.6 +ldap3==2.8.1 +mysqlclient==2.0.1 From 01b16a28f163b5c26f2cc34b02d65183fa0dc653 Mon Sep 17 00:00:00 2001 From: andis Date: Sun, 10 Jan 2021 09:09:15 +0000 Subject: [PATCH 02/15] improve docker dev --- docker-compose.andis.yml | 51 +++++++------------------------------- docker-compose.dev.yml | 53 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 42 deletions(-) create mode 100644 docker-compose.dev.yml diff --git a/docker-compose.andis.yml b/docker-compose.andis.yml index 5654a8ea..eaa6cf8f 100644 --- a/docker-compose.andis.yml +++ b/docker-compose.andis.yml @@ -1,4 +1,4 @@ -version: "3" +version: "2" services: flaskfetfotos: image: flask-fet-fotos @@ -7,27 +7,16 @@ services: FLASK_APP: main.py pages_root: /app/data volumes: - - /mnt/fotos/www:/app/data - mysql: - image: jbergstroem/mariadb-alpine - environment: - SKIP_INNODB: "yes" - MYSQL_DATABASE: fet2020db - MYSQL_USER: user - MYSQL_PASSWORD: hgu - MYSQL_COLLATION: utf8_general_ci - MYSQL_CHARSET: utf8 - volumes: - - mysql-volume:/var/lib/mysql + - foto-data:/app/data etherpadsql: - image: jbergstroem/mariadb-alpine + image: mariadb environment: - SKIP_INNODB: "no" MYSQL_DATABASE: etherpaddb MYSQL_USER: user MYSQL_PASSWORD: hgu MYSQL_COLLATION: utf8_general_ci MYSQL_CHARSET: utf8 + MYSQL_ALLOW_EMPTY_PASSWORD: "yes" volumes: - ep-mysql-volume:/var/lib/mysql etherpad: @@ -40,38 +29,14 @@ services: DB_USER: user DB_PASS: hgu DB_CHARSET: utf8 - #ADMIN_PASSWORD: "AndiS" - #REQUIRE_AUTHENTICATION: "false" TRUST_PROXY: "true" - REQUIRE_SESSION: "true" - #LOGLEVEL: "DEBUG" + REQUIRE_SESSION: "true" depends_on: - etherpadsql volumes: - ./etherpad/APIKEY.txt:/opt/etherpad-lite/APIKEY.txt -# restart: always -# fet2020: -# image: fet2020django -# build: . -# environment: -# HOST_NAME: andis.2020.fet.at -# DEBUG: "False" -# SECRET_KEY: arguiq3ebhnjo -# MYSQL_USER: user -# MYSQL_PASSWORD: hgu -# MYSQL_PORT: 3306 -# depends_on: -# - mysql -# ports: -# - "8106:8080" -# volumes: -# - ./fet2020:/app -# - ./assets:/app/assets -# - ./etherpad:/app/etherpad -# - ./deployment/nginx.conf:/etc/nginx/conf.d/fet2020.conf -# restart: always theia: - image: theiaide/theia-python:latest + image: docker.triton2.fet.at/theia-fet2020:latest volumes: - .:/home/project - ./etherpad/APIKEY.txt:/srv/etherpad/APIKEY.txt @@ -83,4 +48,6 @@ services: - "8106:8080" volumes: ep-mysql-volume: - mysql-volume: + driver: local + foto-data: + driver: local \ No newline at end of file diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml new file mode 100644 index 00000000..ce1313a0 --- /dev/null +++ b/docker-compose.dev.yml @@ -0,0 +1,53 @@ +version: "2" +services: + flaskfetfotos: + image: docker.triton2.fet.at/flask-fet-fotos:latest + environment: + FLASK_DEBUG: 0 + FLASK_APP: main.py + pages_root: /app/data + etherpadsql: + image: mariadb + environment: + MYSQL_DATABASE: etherpaddb + MYSQL_USER: user + MYSQL_PASSWORD: hgu + MYSQL_COLLATION: utf8_general_ci + MYSQL_CHARSET: utf8 + volumes: + - ep-mysql-volume-andis:/var/lib/mysql + etherpad: + image: etherpad/etherpad + environment: + DB_TYPE: mysql + DB_HOST: etherpadsql + DB_PORT: 3306 + DB_NAME: etherpaddb + DB_USER: user + DB_PASS: hgu + DB_CHARSET: utf8 + TRUST_PROXY: "true" + REQUIRE_SESSION: "true" + depends_on: + - etherpadsql + volumes: + - /srv/etherpad/APIKEY.txt:/opt/etherpad-lite/APIKEY.txt + theia: + image: docker.triton2.fet.at/theia-fet2020:latest + volumes: + - /srv/andis_fet2020:/home/project + - /srv/etherpad/APIKEY.txt:/srv/etherpad/APIKEY.txt + - theia_usr:/usr/local + environment: + HOST_NAME: andis.triton2.fet.at + nginx: + image: docker.triton2.fet.at/nginxdev-fet2020:latest + ports: + - "8106:8080" +volumes: + ep-mysql-volume-andis: + driver: local + mysql-volume-andis: + driver: local + theia_usr: + driver: local From 307ee351185648390598e377accff2a1e83b8c99 Mon Sep 17 00:00:00 2001 From: andis Date: Sun, 10 Jan 2021 09:12:29 +0000 Subject: [PATCH 03/15] docker dev data --- docker-compose.dev.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index ce1313a0..1b6b7466 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -35,7 +35,7 @@ services: theia: image: docker.triton2.fet.at/theia-fet2020:latest volumes: - - /srv/andis_fet2020:/home/project + - dev_data:/home/project - /srv/etherpad/APIKEY.txt:/srv/etherpad/APIKEY.txt - theia_usr:/usr/local environment: @@ -51,3 +51,5 @@ volumes: driver: local theia_usr: driver: local + dev_data: + driver: local \ No newline at end of file From 08dd2754ad4b5ab4e8c8b10a73c1ad29b114f5c3 Mon Sep 17 00:00:00 2001 From: Patrick Date: Wed, 13 Jan 2021 12:48:58 +0000 Subject: [PATCH 04/15] The text 'fachschaft info' can be changed in a post --- fet2020/members/views.py | 8 ++++++++ fet2020/templates/members/index.html | 4 +++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/fet2020/members/views.py b/fet2020/members/views.py index bff13896..fff08eff 100644 --- a/fet2020/members/views.py +++ b/fet2020/members/views.py @@ -7,6 +7,8 @@ from django_filters.rest_framework import DjangoFilterBackend from .models import Member, JobMember, JobGroup, Job from .serializers import MemberSerializer, JobSerializer, JobGroupSerializer, JobMemberSerializer +from posts.models import Post + from rest_framework import viewsets #from rest_framework import permissions @@ -45,10 +47,13 @@ def index(request): pinned_job_groups, unpinned_job_groups = __get_job_groups() members = deque(Member.all_members.all()) + fs_info = Post.objects.filter(slug='fachschaft-info').first() + context = { "pinned_job_groups": pinned_job_groups, "unpinned_job_groups": unpinned_job_groups, "members": members, + "fs_info": fs_info, } return render(request, 'members/index.html', context) @@ -84,10 +89,13 @@ def members_view(request, filter=None): logger.info("Wrong member role '{}'".format(filter)) raise Http404("no member role") + fs_info = Post.objects.filter(slug='fachschaft-info').first() + context = { "pinned_job_groups": pinned_job_groups, "unpinned_job_groups": unpinned_job_groups, "members": members, + "fs_info": fs_info, } return render(request, 'members/index.html', context) diff --git a/fet2020/templates/members/index.html b/fet2020/templates/members/index.html index 5826e49a..e29c4803 100644 --- a/fet2020/templates/members/index.html +++ b/fet2020/templates/members/index.html @@ -62,7 +62,9 @@ {% if members %}
- Die Fachschaft Elektrotechnik (kurz: FET), ist die offizielle Vertretung aller Studierenden auf der Fakultät für Elektrotechnik und Informationstechnik. Ehrenamtliche engagierte Studierende unterstützen dich in Anliegen und Fragen zum und rund ums Studium. Wir vertreten eure Interessen in den offiziellen Gremien der Universität und arbeiten an Studienplänen mit. Außerdem bieten wir ein Rahmenprogramm zum Studium in Form von Veranstaltungen und Festln. Wir freuen uns über Feedback und Anregungen, insbesondere von jenen, die gleich Nägel mit Köpfen machen und unser Team verstärken wollen oder ihre Themen und Meinungen in eine unserer Sitzungen einbringen möchten. + {% if fs_info %} + {{ fs_info.body|safe }} + {% endif %}
From 7454ed5b53c70c6d3b366c5cd89d8a2f5d30f01d Mon Sep 17 00:00:00 2001 From: Patrick Date: Wed, 13 Jan 2021 13:25:03 +0000 Subject: [PATCH 05/15] relocate viewset methods --- fet2020/fet2020/urls.py | 4 +-- fet2020/members/views.py | 55 ------------------------------------- fet2020/members/viewsets.py | 55 +++++++++++++++++++++++++++++++++++++ fet2020/posts/views.py | 21 ++------------ fet2020/posts/viewsets.py | 21 ++++++++++++++ 5 files changed, 80 insertions(+), 76 deletions(-) create mode 100644 fet2020/members/viewsets.py create mode 100644 fet2020/posts/viewsets.py diff --git a/fet2020/fet2020/urls.py b/fet2020/fet2020/urls.py index 81de07ee..b7701ef2 100644 --- a/fet2020/fet2020/urls.py +++ b/fet2020/fet2020/urls.py @@ -4,9 +4,9 @@ from django.conf.urls.static import static from django.conf import settings from django.views.generic import RedirectView from . import views -from posts.views import PostViewSet +from posts.viewsets import PostViewSet from members.urls import member_urlpatterns, jobs_urlpatterns -from members.views import MemberViewSet, JobViewSet, JobGroupViewSet, JobMemberViewSet +from members.viewsets import MemberViewSet, JobViewSet, JobGroupViewSet, JobMemberViewSet from rest_framework import routers router = routers.DefaultRouter() diff --git a/fet2020/members/views.py b/fet2020/members/views.py index fff08eff..5381cca7 100644 --- a/fet2020/members/views.py +++ b/fet2020/members/views.py @@ -2,16 +2,10 @@ from django.http import Http404 from django.shortcuts import render from collections import deque -from django_filters.rest_framework import DjangoFilterBackend from .models import Member, JobMember, JobGroup, Job -from .serializers import MemberSerializer, JobSerializer, JobGroupSerializer, JobMemberSerializer - from posts.models import Post -from rest_framework import viewsets -#from rest_framework import permissions - import logging logger = logging.getLogger(__name__) @@ -119,52 +113,3 @@ def profile_view(request, member_id=None): } return render(request, 'members/member.html', context) - - -class MemberViewSet(viewsets.ModelViewSet): - """ - API endpoint that allows users to be viewed or edited. - """ - queryset = Member.all_members.order_by('nickname') - serializer_class = MemberSerializer - - #permission_classes = [permissions.IsAuthenticated] - filter_backends = [DjangoFilterBackend] - filterset_fields = ['nickname','mailaccount'] -# lookup_field = 'name' - - def pre_save(self, obj): - obj.image = self.request.FILES.get('image') - - -class JobGroupViewSet(viewsets.ModelViewSet): - """ - API endpoint that allows users to be viewed or edited. - """ - queryset = JobGroup.all_jobgroups.all() - serializer_class = JobGroupSerializer - - filter_backends = [DjangoFilterBackend] - filterset_fields = ['name','slug'] - #lookup_field = 'name' -# lookup_field = 'name' - -class JobViewSet(viewsets.ModelViewSet): - """ - API endpoint that allows users to be viewed or edited. - """ - queryset = Job.objects.all() - serializer_class = JobSerializer - filter_backends = [DjangoFilterBackend] - filterset_fields = ['name','slug'] - #lookup_field = 'slug' - -class JobMemberViewSet(viewsets.ModelViewSet): - """ - API endpoint that allows users to be viewed or edited. - """ - queryset = JobMember.objects.all() - serializer_class = JobMemberSerializer - filter_backends = [DjangoFilterBackend] - filterset_fields = ['member','job','job_role','job_start'] - #lookup_field = 'nickname' \ No newline at end of file diff --git a/fet2020/members/viewsets.py b/fet2020/members/viewsets.py new file mode 100644 index 00000000..27c1683f --- /dev/null +++ b/fet2020/members/viewsets.py @@ -0,0 +1,55 @@ +from django_filters.rest_framework import DjangoFilterBackend +from rest_framework import viewsets + +from .models import Member, JobMember, JobGroup, Job +from .serializers import MemberSerializer, JobSerializer, JobGroupSerializer, JobMemberSerializer + + +class MemberViewSet(viewsets.ModelViewSet): + """ + API endpoint that allows users to be viewed or edited. + """ + queryset = Member.all_members.order_by('nickname') + serializer_class = MemberSerializer + + #permission_classes = [permissions.IsAuthenticated] + filter_backends = [DjangoFilterBackend] + filterset_fields = ['nickname','mailaccount'] + #lookup_field = 'name' + + def pre_save(self, obj): + obj.image = self.request.FILES.get('image') + + +class JobGroupViewSet(viewsets.ModelViewSet): + """ + API endpoint that allows users to be viewed or edited. + """ + queryset = JobGroup.all_jobgroups.all() + serializer_class = JobGroupSerializer + + filter_backends = [DjangoFilterBackend] + filterset_fields = ['name','slug'] + #lookup_field = 'name' + + +class JobViewSet(viewsets.ModelViewSet): + """ + API endpoint that allows users to be viewed or edited. + """ + queryset = Job.objects.all() + serializer_class = JobSerializer + filter_backends = [DjangoFilterBackend] + filterset_fields = ['name','slug'] + #lookup_field = 'slug' + + +class JobMemberViewSet(viewsets.ModelViewSet): + """ + API endpoint that allows users to be viewed or edited. + """ + queryset = JobMember.objects.all() + serializer_class = JobMemberSerializer + filter_backends = [DjangoFilterBackend] + filterset_fields = ['member','job','job_role','job_start'] + #lookup_field = 'nickname' diff --git a/fet2020/posts/views.py b/fet2020/posts/views.py index 2481bf09..5b6c4f27 100644 --- a/fet2020/posts/views.py +++ b/fet2020/posts/views.py @@ -1,13 +1,11 @@ from collections import deque import logging -from rest_framework import viewsets from taggit.models import Tag from django.shortcuts import render from django.http import HttpResponse, JsonResponse, HttpResponseServerError from django.utils.text import slugify from django.utils import timezone -from django_filters.rest_framework import DjangoFilterBackend from documents.api import get_pad_link from documents.etherpadlib import add_ep_cookie @@ -15,7 +13,8 @@ from members.models import Member, JobMember from .models import Post, FetMeeting -from .serializers import PostSerializer + + logger = logging.getLogger(__name__) @@ -196,19 +195,3 @@ def get_next_dict(post=None): break return d - - -class PostViewSet(viewsets.ModelViewSet): - """ - API endpoint that allows users to be viewed or edited. - """ - - queryset = Post.objects.all().order_by("-public_date") - serializer_class = PostSerializer - # permission_classes = [permissions.IsAuthenticated] - filter_backends = [DjangoFilterBackend] - filterset_fields = ["legacy_id", "slug", "legacy_rubrik_id"] - lookup_field = "slug" - - def pre_save(self, obj): - obj.image = self.request.FILES.get("image") diff --git a/fet2020/posts/viewsets.py b/fet2020/posts/viewsets.py new file mode 100644 index 00000000..90a87ea2 --- /dev/null +++ b/fet2020/posts/viewsets.py @@ -0,0 +1,21 @@ +from django_filters.rest_framework import DjangoFilterBackend +from rest_framework import viewsets + +from .models import Post, FetMeeting +from .serializers import PostSerializer + + +class PostViewSet(viewsets.ModelViewSet): + """ + API endpoint that allows users to be viewed or edited. + """ + + queryset = Post.objects.all().order_by("-public_date") + serializer_class = PostSerializer + # permission_classes = [permissions.IsAuthenticated] + filter_backends = [DjangoFilterBackend] + filterset_fields = ["legacy_id", "slug", "legacy_rubrik_id"] + lookup_field = "slug" + + def pre_save(self, obj): + obj.image = self.request.FILES.get("image") From 7b650a1c7fd867a994d2bd2aea108e68bc2441b7 Mon Sep 17 00:00:00 2001 From: Patrick Date: Wed, 13 Jan 2021 13:34:26 +0000 Subject: [PATCH 06/15] update requirements --- fet2020/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fet2020/requirements.txt b/fet2020/requirements.txt index c3e5fcb5..b00d74f9 100644 --- a/fet2020/requirements.txt +++ b/fet2020/requirements.txt @@ -1,4 +1,4 @@ -django==3.1.4 +django==3.1.5 django-ckeditor==6.0.0 django-crontab==0.7.1 django-environ==0.4.5 From 9ac9cd7b4f9c11518073747d8ba436d4108b426f Mon Sep 17 00:00:00 2001 From: Patrick Date: Thu, 14 Jan 2021 11:32:20 +0000 Subject: [PATCH 07/15] fix spelling --- fet2020/templates/home.html | 2 +- fet2020/templates/posts/fet_calendar.ics | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fet2020/templates/home.html b/fet2020/templates/home.html index 9661e9d3..951b2834 100644 --- a/fet2020/templates/home.html +++ b/fet2020/templates/home.html @@ -58,7 +58,7 @@ {% for post in events %} {% include 'posts/partials/_date_box.html' %} {% endfor %} - ICS Kalendar + FET-Ka­len­der abonnieren: ICS Ka­len­der diff --git a/fet2020/templates/posts/fet_calendar.ics b/fet2020/templates/posts/fet_calendar.ics index 4c4f71cf..792b19c2 100644 --- a/fet2020/templates/posts/fet_calendar.ics +++ b/fet2020/templates/posts/fet_calendar.ics @@ -25,7 +25,7 @@ UID:{{event.id}} ORGANIZER;CN="Fachschaft Elektrotechnik":MAILTO:service@fet.at LOCATION:Vienna SUMMARY:{{ event.title }} -DESCRIPTION: {{ request.scheme }}://{{ request.get_host }}{{ event.url }} {{ even.title }} +DESCRIPTION:{{ request.scheme }}://{{ request.get_host }}{{ event.url }} {{ even.title }} CLASS:PUBLIC DTSTART;TZID=Europe/Vienna:{{ event.event_start|date:'Ymd' }}T{{ event.event_start|time:'His' }} DTEND;TZID=Europe/Vienna:{{ event.event_end|date:'Ymd' }}T{{ event.event_end|time:'His' }} From 2e2bf603b8ce063e638e0552d5c76dc8838c04cb Mon Sep 17 00:00:00 2001 From: Patrick Date: Thu, 14 Jan 2021 11:55:57 +0000 Subject: [PATCH 08/15] add redirect to current page after login --- fet2020/authentications/views.py | 6 +++++- fet2020/templates/layout.html | 10 +++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/fet2020/authentications/views.py b/fet2020/authentications/views.py index bbf8b0a3..2c9cc80e 100644 --- a/fet2020/authentications/views.py +++ b/fet2020/authentications/views.py @@ -25,7 +25,11 @@ def loginPage(request): user = User.objects.create_user(auth_user.lower()) login(request, user) - return redirect('home') + + try: + return redirect(request.GET.get('next')) + except: + return redirect('home') else: messages.info(request, 'username or password is incorrect') diff --git a/fet2020/templates/layout.html b/fet2020/templates/layout.html index c82f2b55..57f941b5 100644 --- a/fet2020/templates/layout.html +++ b/fet2020/templates/layout.html @@ -50,19 +50,19 @@ footer {
From bdd36c08f8610c2849f6bf44c46246883c081bc3 Mon Sep 17 00:00:00 2001 From: Patrick Date: Thu, 14 Jan 2021 16:22:06 +0000 Subject: [PATCH 09/15] cleanups --- fet2020/fet2020/middleware.py | 22 ---------------------- fet2020/fet2020/settings.py | 2 -- 2 files changed, 24 deletions(-) diff --git a/fet2020/fet2020/middleware.py b/fet2020/fet2020/middleware.py index 4a638721..e69de29b 100644 --- a/fet2020/fet2020/middleware.py +++ b/fet2020/fet2020/middleware.py @@ -1,22 +0,0 @@ -# from django.contrib.auth.models import User -from django.contrib.auth.middleware import RemoteUserMiddleware -# import django -# import logging -# logger=logging.getLogger("django.request") - - -class FETHeaderMiddleware(RemoteUserMiddleware): - header = "Remote-User" - - def process_request(self, request): - request.META[self.header] = request.META.get( - self.header, - request.headers.get(self.header, None) - ) - # logger = logging.getLogger(__name__) - super().process_request(request) - # logger.info('User: ' + str(request.user)) - if request.user.is_authenticated: - request.user.is_admin = True - request.user.is_superuser = True - request.user.is_staff = True diff --git a/fet2020/fet2020/settings.py b/fet2020/fet2020/settings.py index 4b834e78..3dc57c3b 100644 --- a/fet2020/fet2020/settings.py +++ b/fet2020/fet2020/settings.py @@ -89,7 +89,6 @@ MIDDLEWARE = [ 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'fet2020.middleware.FETHeaderMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] @@ -141,7 +140,6 @@ else: AUTHENTICATION_BACKENDS = [ - # 'django.contrib.auth.backends.RemoteUserBackend', 'django.contrib.auth.backends.ModelBackend', ] From b702fcb33dd3b405e79e4cb14c7f169eab7cd271 Mon Sep 17 00:00:00 2001 From: Andreas Stephanides Date: Fri, 15 Jan 2021 14:10:06 +0000 Subject: [PATCH 10/15] clean dev volumes --- docker-compose.dev.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 1b6b7466..160e2dd4 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -15,7 +15,7 @@ services: MYSQL_COLLATION: utf8_general_ci MYSQL_CHARSET: utf8 volumes: - - ep-mysql-volume-andis:/var/lib/mysql + - ep-mysql:/var/lib/mysql etherpad: image: etherpad/etherpad environment: @@ -45,9 +45,7 @@ services: ports: - "8106:8080" volumes: - ep-mysql-volume-andis: - driver: local - mysql-volume-andis: + ep-mysql: driver: local theia_usr: driver: local From f6b9e2f741c23a5de1bd40fa14961e527a47dabd Mon Sep 17 00:00:00 2001 From: patrick Date: Fri, 15 Jan 2021 15:42:30 +0000 Subject: [PATCH 11/15] linting --- fet2020/authentications/apps.py | 2 +- fet2020/authentications/authentications.py | 10 +- fet2020/authentications/decorators.py | 4 +- fet2020/authentications/forms.py | 2 +- fet2020/authentications/urls.py | 4 +- fet2020/authentications/views.py | 16 +- fet2020/blackboard/admin.py | 2 +- fet2020/blackboard/apps.py | 2 +- fet2020/blackboard/forms.py | 18 +- fet2020/blackboard/models.py | 35 ++-- fet2020/blackboard/urls.py | 2 +- fet2020/blackboard/views.py | 6 +- fet2020/documents/api.py | 19 +- fet2020/documents/apps.py | 3 +- fet2020/documents/etherpadlib.py | 34 +--- fet2020/fet2020/asgi.py | 2 +- fet2020/fet2020/settings.py | 206 ++++++++++----------- fet2020/fet2020/urls.py | 45 +++-- fet2020/fet2020/views.py | 15 +- fet2020/fet2020/wsgi.py | 2 +- fet2020/members/admin.py | 128 ++++++++----- fet2020/members/apps.py | 2 +- fet2020/members/forms.py | 64 ++++--- fet2020/members/models.py | 77 ++++---- fet2020/members/serializers.py | 69 +++---- fet2020/members/urls.py | 8 +- fet2020/members/views.py | 17 +- fet2020/members/viewsets.py | 33 ++-- fet2020/posts/admin.py | 42 +++-- fet2020/posts/apps.py | 2 +- fet2020/posts/forms.py | 141 ++++++++------ fet2020/posts/mails.py | 23 ++- fet2020/posts/managers.py | 63 +++++-- fet2020/posts/models.py | 81 ++++---- fet2020/posts/serializers.py | 47 ++--- fet2020/posts/urls.py | 12 +- fet2020/posts/views.py | 20 +- fet2020/tasks/admin.py | 40 ++-- fet2020/tasks/apps.py | 2 +- fet2020/tasks/forms.py | 58 +++--- fet2020/tasks/models.py | 18 +- fet2020/tasks/urls.py | 2 +- fet2020/tasks/views.py | 43 +++-- 43 files changed, 793 insertions(+), 628 deletions(-) diff --git a/fet2020/authentications/apps.py b/fet2020/authentications/apps.py index cb10b004..38a778e3 100644 --- a/fet2020/authentications/apps.py +++ b/fet2020/authentications/apps.py @@ -2,4 +2,4 @@ from django.apps import AppConfig class AuthenticationsConfig(AppConfig): - name = 'authentications' + name = "authentications" diff --git a/fet2020/authentications/authentications.py b/fet2020/authentications/authentications.py index 8d469d6a..16e6cce5 100644 --- a/fet2020/authentications/authentications.py +++ b/fet2020/authentications/authentications.py @@ -11,25 +11,25 @@ def authentication(username, password): return None # username format - new_username = 'uid={username},ou=user,dc=fet,dc=htu,dc=tuwien,dc=ac,dc=at' + new_username = "uid={username},ou=user,dc=fet,dc=htu,dc=tuwien,dc=ac,dc=at" userdn = new_username.format(username=username) - server_uri = 'ldap://gagarin.fet.htu.tuwien.ac.at' + server_uri = "ldap://gagarin.fet.htu.tuwien.ac.at" server = ldap3.Server(server_uri, port=389, use_ssl=True) has_user = False try: conn = ldap3.Connection(server, user=userdn, password=password, auto_bind=True) - conn.search('dc=fet,dc=htu,dc=tuwien,dc=ac,dc=at', '(objectclass=person)') + conn.search("dc=fet,dc=htu,dc=tuwien,dc=ac,dc=at", "(objectclass=person)") for user in sorted(conn.entries): if ("DN: uid=" + str(username.lower())) in str(user): has_user = True except LDAPBindError as e: - logger.info('Username does not exist. Error: {}'.format(e)) + logger.info("Username does not exist. Error: {}".format(e)) username = None except Exception as e: - logger.info('Connection to server lost. Error: {}'.format(e)) + logger.info("Connection to server lost. Error: {}".format(e)) username = None if not has_user: diff --git a/fet2020/authentications/decorators.py b/fet2020/authentications/decorators.py index 8059b93e..670430aa 100644 --- a/fet2020/authentications/decorators.py +++ b/fet2020/authentications/decorators.py @@ -4,7 +4,7 @@ from django.shortcuts import redirect def unauthenticated_user(view_func): def wrapper_func(request, *args, **kwargs): if request.user.is_authenticated: - return redirect('home') + return redirect("home") else: return view_func(request, *args, **kwargs) @@ -16,7 +16,7 @@ def authenticated_user(view_func): if request.user.is_authenticated: return view_func(request, *args, **kwargs) else: - return redirect('login') + return redirect("login") return wrapper_func diff --git a/fet2020/authentications/forms.py b/fet2020/authentications/forms.py index 204803e6..40a53f7c 100644 --- a/fet2020/authentications/forms.py +++ b/fet2020/authentications/forms.py @@ -3,4 +3,4 @@ from django import forms class LoginForm(forms.Form): username = forms.CharField() - password = forms.CharField(label='Passwort', widget=forms.PasswordInput()) + password = forms.CharField(label="Passwort", widget=forms.PasswordInput()) diff --git a/fet2020/authentications/urls.py b/fet2020/authentications/urls.py index 7c084c15..24d78d0f 100644 --- a/fet2020/authentications/urls.py +++ b/fet2020/authentications/urls.py @@ -3,6 +3,6 @@ from . import views urlpatterns = [ - path('login/', views.loginPage, name="login"), - path('logout/', views.logoutUser, name="logout"), + path("login/", views.loginPage, name="login"), + path("logout/", views.logoutUser, name="logout"), ] diff --git a/fet2020/authentications/views.py b/fet2020/authentications/views.py index 2c9cc80e..61050c91 100644 --- a/fet2020/authentications/views.py +++ b/fet2020/authentications/views.py @@ -12,9 +12,9 @@ from .forms import LoginForm @unauthenticated_user def loginPage(request): - if request.method == 'POST': - username = request.POST.get('username') - password = request.POST.get('password') + if request.method == "POST": + username = request.POST.get("username") + password = request.POST.get("password") auth_user = authentication(username, password) @@ -27,25 +27,25 @@ def loginPage(request): login(request, user) try: - return redirect(request.GET.get('next')) + return redirect(request.GET.get("next")) except: - return redirect('home') + return redirect("home") else: - messages.info(request, 'username or password is incorrect') + messages.info(request, "username or password is incorrect") form = LoginForm() context = { "form": form, } - return render(request, 'authentications/login.html', context) + return render(request, "authentications/login.html", context) @authenticated_user def logoutUser(request): logout(request) - response = redirect('home') + response = redirect("home") response = del_ep_cookie(request, response) return response diff --git a/fet2020/blackboard/admin.py b/fet2020/blackboard/admin.py index a16ed892..47b951dc 100644 --- a/fet2020/blackboard/admin.py +++ b/fet2020/blackboard/admin.py @@ -8,7 +8,7 @@ class JobPostingAdmin(admin.ModelAdmin): form = JobPostingForm model = JobPosting - list_display = ['companyName', 'jobName', 'salary', 'publishDate'] + list_display = ["companyName", "jobName", "salary", "publishDate"] admin.site.register(JobPosting, JobPostingAdmin) diff --git a/fet2020/blackboard/apps.py b/fet2020/blackboard/apps.py index a1b4f21a..6f7c4fdb 100644 --- a/fet2020/blackboard/apps.py +++ b/fet2020/blackboard/apps.py @@ -2,4 +2,4 @@ from django.apps import AppConfig class BlackboardConfig(AppConfig): - name = 'blackboard' + name = "blackboard" diff --git a/fet2020/blackboard/forms.py b/fet2020/blackboard/forms.py index 1e4abea6..94db3375 100644 --- a/fet2020/blackboard/forms.py +++ b/fet2020/blackboard/forms.py @@ -7,19 +7,17 @@ from .models import JobPosting class JobPostingForm(forms.ModelForm): class Meta: model = JobPosting - fields = ['companyName', 'jobName', 'salary', 'pdfLocation', 'publishDate'] + fields = ["companyName", "jobName", "salary", "pdfLocation", "publishDate"] labels = { - 'companyName': _("Firmenname"), - 'jobName': _("Berufsbezeichnung"), - 'salary': _("Gehalt"), - 'pdfLocation': _("Stellenausschreibung"), - 'publishDate': _("Veröffentlichung"), + "companyName": _("Firmenname"), + "jobName": _("Berufsbezeichnung"), + "salary": _("Gehalt"), + "pdfLocation": _("Stellenausschreibung"), + "publishDate": _("Veröffentlichung"), } help_texts = { - 'pdfLocation': _( - "Verwendbare Formate: PDF" - ), - 'salary': _("in Euro angeben"), + "pdfLocation": _("Verwendbare Formate: PDF"), + "salary": _("in Euro angeben"), } diff --git a/fet2020/blackboard/models.py b/fet2020/blackboard/models.py index d1b2a4f3..db100b2d 100644 --- a/fet2020/blackboard/models.py +++ b/fet2020/blackboard/models.py @@ -11,16 +11,23 @@ from os.path import splitext, basename import ghostscript import logging -logger = logging.getLogger('blackboard') + +logger = logging.getLogger("blackboard") class JobPosting(models.Model): companyName = models.CharField(verbose_name="Firmenname", max_length=128) jobName = models.CharField(verbose_name="Berufsbezeichnung", max_length=128) - salary = models.PositiveSmallIntegerField(verbose_name="Gehalt", ) - pdfLocation = models.FileField(verbose_name="Stellenausschreibung", upload_to='uploads/blackboard/pdf/') + salary = models.PositiveSmallIntegerField( + verbose_name="Gehalt", + ) + pdfLocation = models.FileField( + verbose_name="Stellenausschreibung", upload_to="uploads/blackboard/pdf/" + ) pdf_thumb_location = models.CharField(max_length=128) - publishDate = models.DateField(verbose_name="Veröffentlichung", default=timezone.now) + publishDate = models.DateField( + verbose_name="Veröffentlichung", default=timezone.now + ) # Managers all_jobPosting = models.Manager() @@ -40,7 +47,7 @@ class JobPosting(models.Model): "-dDEVICEWIDTHPOINTS=600", "-dDEVICEHEIGHTPOINTS=800", "-sOutputFile=" + jpeg_output_path, - pdf_input_path + pdf_input_path, ] encoding = locale.getpreferredencoding() @@ -54,14 +61,18 @@ class JobPosting(models.Model): if not os.path.exists(settings.MEDIA_ROOT + "uploads/blackboard/thumb/"): os.makedirs(settings.MEDIA_ROOT + "uploads/blackboard/thumb/") - pdf_thumb_location_full = settings.MEDIA_ROOT \ - + "uploads/blackboard/thumb/" \ - + splitext(basename(self.pdfLocation.name))[0] \ + pdf_thumb_location_full = ( + settings.MEDIA_ROOT + + "uploads/blackboard/thumb/" + + splitext(basename(self.pdfLocation.name))[0] + ".jpg" + ) - self.pdf_thumb_location = "/files/uploads/blackboard/thumb/" \ - + splitext(basename(self.pdfLocation.name))[0] \ + self.pdf_thumb_location = ( + "/files/uploads/blackboard/thumb/" + + splitext(basename(self.pdfLocation.name))[0] + ".jpg" + ) self.pdf2jpeg(self.pdfLocation.path, pdf_thumb_location_full) logger.info("SavenThumbAs: " + self.pdf_thumb_location) @@ -70,7 +81,7 @@ class JobPosting(models.Model): def clean(self): count = 0 for i in self.pdfLocation.name: - if i == '.': + if i == ".": count = count + 1 if count > 1: # if more than one dot in filename - raise ValidationError(_('Keine Dateien mit >1 Punkten im Namen erlaubt.')) + raise ValidationError(_("Keine Dateien mit >1 Punkten im Namen erlaubt.")) diff --git a/fet2020/blackboard/urls.py b/fet2020/blackboard/urls.py index 89addfe8..9ec77413 100644 --- a/fet2020/blackboard/urls.py +++ b/fet2020/blackboard/urls.py @@ -4,5 +4,5 @@ from . import views urlpatterns = [ - path('', views.index, name='blackboard'), + path("", views.index, name="blackboard"), ] diff --git a/fet2020/blackboard/views.py b/fet2020/blackboard/views.py index 093728ef..72165e9c 100644 --- a/fet2020/blackboard/views.py +++ b/fet2020/blackboard/views.py @@ -10,8 +10,8 @@ from posts.models import Post def index(request): job_postings_cutoff = timezone.now().date() - timedelta(30) # 30days from now job_postings = JobPosting.all_jobPosting.filter(publishDate__gt=job_postings_cutoff) - bb_info = Post.objects.filter(slug='blackboard').first() - bb_empty = Post.objects.filter(slug='blackboard-empty').first() + bb_info = Post.objects.filter(slug="blackboard").first() + bb_empty = Post.objects.filter(slug="blackboard-empty").first() context = { "job_postings": job_postings, @@ -19,4 +19,4 @@ def index(request): "bb_empty": bb_empty, } - return render(request, 'blackboard/index.html', context) + return render(request, "blackboard/index.html", context) diff --git a/fet2020/documents/api.py b/fet2020/documents/api.py index be16ce35..cbb22b89 100644 --- a/fet2020/documents/api.py +++ b/fet2020/documents/api.py @@ -6,6 +6,7 @@ import urllib.parse from etherpad_lite import EtherpadLiteClient, EtherpadException import logging + logger = logging.getLogger(__name__) SERVER_URL = settings.ETHERPAD_CLIENT["exturl"] @@ -20,9 +21,11 @@ def get_ep_client(): apikey = f.read() apikey = apikey.rstrip() epc = EtherpadLiteClient( - base_params={'apikey': apikey, }, + base_params={ + "apikey": apikey, + }, base_url=urllib.parse.urljoin(settings.ETHERPAD_CLIENT["url"], "api"), - api_version='1.2.14', + api_version="1.2.14", ) group = epc.createGroupIfNotExistsFor(groupMapper="fet") except Exception as e: @@ -62,7 +65,9 @@ def createPadifNotExists(padID): # Pad doesn't exist if not __checkPadExists(padID=padID): try: - epc.createGroupPad(groupID=group["groupID"], padName=padID, text="helloworld") + epc.createGroupPad( + groupID=group["groupID"], padName=padID, text="helloworld" + ) except EtherpadException as e: logger.info("Can't create Pad '{}'. EtherpadException: {}".format(padID, e)) return None @@ -81,7 +86,9 @@ def getPadHTML(padID): try: text = epc.getHTML(padID=group["groupID"] + "$" + padID)["html"] except EtherpadException as e: - logger.info("Can't get HTML from padID '{}'. EtherpadException: {}".format(padID, e)) + logger.info( + "Can't get HTML from padID '{}'. EtherpadException: {}".format(padID, e) + ) return None except Exception as e: raise e @@ -107,4 +114,6 @@ def get_pad_link(padID): if not epc or not group: return "#" - return urllib.parse.urljoin(settings.ETHERPAD_CLIENT["exturl"], 'p/' + group["groupID"] + '$' + str(padID)) + return urllib.parse.urljoin( + settings.ETHERPAD_CLIENT["exturl"], "p/" + group["groupID"] + "$" + str(padID) + ) diff --git a/fet2020/documents/apps.py b/fet2020/documents/apps.py index 1450e243..dfabc095 100644 --- a/fet2020/documents/apps.py +++ b/fet2020/documents/apps.py @@ -1,6 +1,7 @@ from django.apps import AppConfig + # from django.contrib.admin.apps import AdminConfig class DocumentsConfig(AppConfig): - name = 'documents' + name = "documents" diff --git a/fet2020/documents/etherpadlib.py b/fet2020/documents/etherpadlib.py index 9014d8b6..7d772616 100644 --- a/fet2020/documents/etherpadlib.py +++ b/fet2020/documents/etherpadlib.py @@ -11,22 +11,21 @@ def __get_ep_sessionid(request): return None, None author = epc.createAuthorIfNotExistsFor( - name=str(request.user), - authorMapper=str(request.user) - )['authorID'] + name=str(request.user), authorMapper=str(request.user) + )["authorID"] expires = datetime.utcnow() + timedelta(hours=3) try: result = epc.createSession( - groupID=str(group['groupID']), + groupID=str(group["groupID"]), authorID=str(author), - validUntil=str(int(expires.timestamp())) + validUntil=str(int(expires.timestamp())), ) except Exception as e: raise e return None, None - return result['sessionID'], expires + return result["sessionID"], expires def add_ep_cookie(request, response): @@ -34,32 +33,19 @@ def add_ep_cookie(request, response): if ep_sessid: response.set_cookie( - "sessionID", - ep_sessid, - expires=expires, - domain=".2020.fet.at", - path="/" - ) - response.set_cookie( - "sessionID", - ep_sessid, - expires=expires, - path="/etherpad" + "sessionID", ep_sessid, expires=expires, domain=".2020.fet.at", path="/" ) + response.set_cookie("sessionID", ep_sessid, expires=expires, path="/etherpad") return response def del_ep_cookie(request, response): - if 'sessionID' in request.COOKIES: - ep_sessionID = request.COOKIES['sessionID'] + if "sessionID" in request.COOKIES: + ep_sessionID = request.COOKIES["sessionID"] epc, group = get_ep_client() epc.deleteSession(sessionID=ep_sessionID) - response.delete_cookie( - "sessionID", - domain=".2020.fet.at", - path="/" - ) + response.delete_cookie("sessionID", domain=".2020.fet.at", path="/") return response diff --git a/fet2020/fet2020/asgi.py b/fet2020/fet2020/asgi.py index be2e0c86..3dbaa8d9 100644 --- a/fet2020/fet2020/asgi.py +++ b/fet2020/fet2020/asgi.py @@ -2,6 +2,6 @@ import os from django.core.asgi import get_asgi_application -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'fet2020.settings') +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "fet2020.settings") application = get_asgi_application() diff --git a/fet2020/fet2020/settings.py b/fet2020/fet2020/settings.py index 3dc57c3b..5a752a22 100644 --- a/fet2020/fet2020/settings.py +++ b/fet2020/fet2020/settings.py @@ -11,23 +11,23 @@ env = environ.Env( MYSQL_USER=(str), MYSQL_PASSWORD=(str), HOST_NAME=(str, "localhost"), - ETHERPAD_PORT=(str,"9001"), - ETHERPAD_HOST=(str,"etherpad2.2020.fet.at") + ETHERPAD_PORT=(str, "9001"), + ETHERPAD_HOST=(str, "etherpad2.2020.fet.at"), ) # Prints and logs are written to console # TODO: Change before release LOGGING = { - 'version': 1, - 'disable_existing_loggers': False, - 'handlers': { - 'console': { - 'class': 'logging.StreamHandler', + "version": 1, + "disable_existing_loggers": False, + "handlers": { + "console": { + "class": "logging.StreamHandler", }, }, - 'root': { - 'handlers': ['console'], - 'level': 'DEBUG', + "root": { + "handlers": ["console"], + "level": "DEBUG", }, } @@ -41,106 +41,106 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/ # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = env('DEBUG') +DEBUG = env("DEBUG") if DEBUG: # SECURITY WARNING: keep the secret key used in production secret! - SECRET_KEY = 'r37-i7l)vrduzz2-gira+z#u!p!di9#f+%s*5-bb($hg)55@ns' + SECRET_KEY = "r37-i7l)vrduzz2-gira+z#u!p!di9#f+%s*5-bb($hg)55@ns" else: - SECRET_KEY = env('SECRET_KEY') + SECRET_KEY = env("SECRET_KEY") -ALLOWED_HOSTS = ["127.0.0.1", env('HOST_NAME')] +ALLOWED_HOSTS = ["127.0.0.1", env("HOST_NAME")] -HOST_NAME = env('HOST_NAME') +HOST_NAME = env("HOST_NAME") DATA_UPLOAD_MAX_MEMORY_SIZE = 1024 * 1024 * 1024 # Application definition -CKEDITOR_UPLOAD_PATH = 'upload' +CKEDITOR_UPLOAD_PATH = "upload" INSTALLED_APPS = [ - 'django.contrib.admin', - 'django.contrib.admindocs', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'taggit', - 'ckeditor', - 'ckeditor_uploader', - 'easy_thumbnails', - 'rest_framework', - 'softhyphen', - 'django_crontab', - 'django_filters', - 'django_static_jquery_ui', - 'posts.apps.PostsConfig', - 'members.apps.MembersConfig', - 'documents.apps.DocumentsConfig', - 'blackboard.apps.BlackboardConfig', - 'tasks.apps.TasksConfig', + "django.contrib.admin", + "django.contrib.admindocs", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "taggit", + "ckeditor", + "ckeditor_uploader", + "easy_thumbnails", + "rest_framework", + "softhyphen", + "django_crontab", + "django_filters", + "django_static_jquery_ui", + "posts.apps.PostsConfig", + "members.apps.MembersConfig", + "documents.apps.DocumentsConfig", + "blackboard.apps.BlackboardConfig", + "tasks.apps.TasksConfig", ] MIDDLEWARE = [ - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.locale.LocaleMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.locale.LocaleMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", ] -ROOT_URLCONF = 'fet2020.urls' +ROOT_URLCONF = "fet2020.urls" TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [ - os.path.join(BASE_DIR, 'templates'), + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [ + os.path.join(BASE_DIR, "templates"), ], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', - 'django.template.context_processors.i18n', + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + "django.template.context_processors.i18n", ], }, }, ] -WSGI_APPLICATION = 'fet2020.wsgi.application' +WSGI_APPLICATION = "fet2020.wsgi.application" # Database # https://docs.djangoproject.com/en/3.0/ref/settings/#databases if DEBUG: DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": os.path.join(BASE_DIR, "db.sqlite3"), } } else: DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.mysql', - 'NAME': env('MYSQL_DATABASE'), - 'USER': env('MYSQL_USER'), - 'PASSWORD': env('MYSQL_PASSWORD'), - 'HOST': env('MYSQL_HOST'), - 'PORT': env('MYSQL_PORT') + "default": { + "ENGINE": "django.db.backends.mysql", + "NAME": env("MYSQL_DATABASE"), + "USER": env("MYSQL_USER"), + "PASSWORD": env("MYSQL_PASSWORD"), + "HOST": env("MYSQL_HOST"), + "PORT": env("MYSQL_PORT"), } } AUTHENTICATION_BACKENDS = [ - 'django.contrib.auth.backends.ModelBackend', + "django.contrib.auth.backends.ModelBackend", ] # Password validation @@ -148,16 +148,16 @@ AUTHENTICATION_BACKENDS = [ AUTH_PASSWORD_VALIDATORS = [ { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", }, ] @@ -165,9 +165,9 @@ AUTH_PASSWORD_VALIDATORS = [ # Internationalization # https://docs.djangoproject.com/en/3.0/topics/i18n/ -LANGUAGE_CODE = 'de-at' +LANGUAGE_CODE = "de-at" -TIME_ZONE = 'CET' +TIME_ZONE = "CET" USE_I18N = True @@ -179,28 +179,26 @@ USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.0/howto/static-files/ -STATIC_URL = '/assets/' +STATIC_URL = "/assets/" -STATICFILES_DIRS = [ - os.path.join(BASE_DIR, "static") -] -STATIC_ROOT = 'assets/' -MEDIA_ROOT = os.path.join(BASE_DIR, 'files/') -MEDIA_URL = '/files/' +STATICFILES_DIRS = [os.path.join(BASE_DIR, "static")] +STATIC_ROOT = "assets/" +MEDIA_ROOT = os.path.join(BASE_DIR, "files/") +MEDIA_URL = "/files/" TAGGIT_FORCE_LOWERCASE = True CKEDITOR_CONFIGS = { - 'default': { - 'stylesSet': [ + "default": { + "stylesSet": [ { - "name": 'Überschrift 2', - "element": 'h2', + "name": "Überschrift 2", + "element": "h2", "attributes": {}, }, { - "name": 'Code', - "element": 'code', + "name": "Code", + "element": "code", "attributes": {"class": "code-block"}, }, ], @@ -209,41 +207,41 @@ CKEDITOR_CONFIGS = { # THUMBNAIL THUMBNAIL_ALIASES = { - '': { - 'avatar': {'size': (50, 50), 'crop': True}, - 'thumb': {'size': (150, 150), 'crop': True}, + "": { + "avatar": {"size": (50, 50), "crop": True}, + "thumb": {"size": (150, 150), "crop": True}, }, } # ETHERPAD CLIENT if DEBUG: ETHERPAD_CLIENT = { - 'url': "http://etherpad:"+env('ETHERPAD_PORT'), - 'exturl': env('ETHERPAD_HOST'), - 'apikey': "/srv/etherpad/APIKEY.txt" + "url": "http://etherpad:" + env("ETHERPAD_PORT"), + "exturl": env("ETHERPAD_HOST"), + "apikey": "/srv/etherpad/APIKEY.txt", } else: ETHERPAD_CLIENT = { - 'url': "http://etherpad:"+env('ETHERPAD_PORT'), - 'exturl': urljoin('https://' + env('HOST_NAME'),"etherpad/"), - 'apikey': "/app/etherpad/APIKEY.txt" + "url": "http://etherpad:" + env("ETHERPAD_PORT"), + "exturl": urljoin("https://" + env("HOST_NAME"), "etherpad/"), + "apikey": "/app/etherpad/APIKEY.txt", } # REST FRAMEWORK -REST_FRAMEWORK={ - 'DEFAULT_PERMISSION_CLASSES_CLASSES':[ - 'rest_framework.permissions.AllowAny', +REST_FRAMEWORK = { + "DEFAULT_PERMISSION_CLASSES_CLASSES": [ + "rest_framework.permissions.AllowAny", ], - 'DEFAULT_AUTHENTICATION_CLASSES':() + "DEFAULT_AUTHENTICATION_CLASSES": (), } # DJANGO MAIL -EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' -EMAIL_HOST = 'buran.htu.tuwien.ac.at' +EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend" +EMAIL_HOST = "buran.htu.tuwien.ac.at" EMAIL_PORT = 587 EMAIL_USE_TLS = True # CRON JOBS CRONJOBS = [ - ('0 16 * * *', 'posts.cronjobs.check_to_send_agenda_mail'), + ("0 16 * * *", "posts.cronjobs.check_to_send_agenda_mail"), ] diff --git a/fet2020/fet2020/urls.py b/fet2020/fet2020/urls.py index b7701ef2..8e1c6653 100644 --- a/fet2020/fet2020/urls.py +++ b/fet2020/fet2020/urls.py @@ -6,29 +6,34 @@ from django.views.generic import RedirectView from . import views from posts.viewsets import PostViewSet from members.urls import member_urlpatterns, jobs_urlpatterns -from members.viewsets import MemberViewSet, JobViewSet, JobGroupViewSet, JobMemberViewSet +from members.viewsets import ( + MemberViewSet, + JobViewSet, + JobGroupViewSet, + JobMemberViewSet, +) from rest_framework import routers router = routers.DefaultRouter() -router.register(r'posts', PostViewSet) -router.register(r'members', MemberViewSet) -router.register(r'jobgroups', JobGroupViewSet) -router.register(r'jobs', JobViewSet) -router.register(r'jobmembers', JobMemberViewSet) +router.register(r"posts", PostViewSet) +router.register(r"members", MemberViewSet) +router.register(r"jobgroups", JobGroupViewSet) +router.register(r"jobs", JobViewSet) +router.register(r"jobmembers", JobMemberViewSet) urlpatterns = [ - path('posts/', include('posts.urls')), - path('admin/doc/', include('django.contrib.admindocs.urls')), - path('admin/login/', RedirectView.as_view(pattern_name='login')), - path('admin/', admin.site.urls), - path('auth/', include('authentications.urls')), - path('', views.index, name='home'), - path('index.html', views.index, name='home'), - path('ckeditor/', include('ckeditor_uploader.urls')), - path('api/', include(router.urls)), - path('members/', include('members.urls'), name='members'), - path('jobs/', include(jobs_urlpatterns), name='jobs'), - path('member/', include(member_urlpatterns), name='member'), - path('blackboard/', include('blackboard.urls'), name='blackboard'), - path('tasks/', include('tasks.urls'), name='tasks'), + path("posts/", include("posts.urls")), + path("admin/doc/", include("django.contrib.admindocs.urls")), + path("admin/login/", RedirectView.as_view(pattern_name="login")), + path("admin/", admin.site.urls), + path("auth/", include("authentications.urls")), + path("", views.index, name="home"), + path("index.html", views.index, name="home"), + path("ckeditor/", include("ckeditor_uploader.urls")), + path("api/", include(router.urls)), + path("members/", include("members.urls"), name="members"), + path("jobs/", include(jobs_urlpatterns), name="jobs"), + path("member/", include(member_urlpatterns), name="member"), + path("blackboard/", include("blackboard.urls"), name="blackboard"), + path("tasks/", include("tasks.urls"), name="tasks"), ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/fet2020/fet2020/views.py b/fet2020/fet2020/views.py index 3d2e5bdf..8ced407c 100644 --- a/fet2020/fet2020/views.py +++ b/fet2020/fet2020/views.py @@ -1,4 +1,5 @@ from django.shortcuts import render + # from django.http import HttpResponse from collections import deque from posts.models import Post, FetMeeting, Event @@ -34,12 +35,12 @@ def index(request): featured_meeting = FetMeeting.objects.get_meetings() context = { - 'posts': deque(list(posts)[:5]), - 'events': Event.all_events.get_five_events(), - 'featured_post': featured_post, - 'featured_event': featured_event, - 'featured_meeting': featured_meeting, - 'tags_list': " ".join(t) + "posts": deque(list(posts)[:5]), + "events": Event.all_events.get_five_events(), + "featured_post": featured_post, + "featured_event": featured_event, + "featured_meeting": featured_meeting, + "tags_list": " ".join(t), } - return render(request, 'home.html', context) + return render(request, "home.html", context) diff --git a/fet2020/fet2020/wsgi.py b/fet2020/fet2020/wsgi.py index 5d996e36..afca229e 100644 --- a/fet2020/fet2020/wsgi.py +++ b/fet2020/fet2020/wsgi.py @@ -2,6 +2,6 @@ import os from django.core.wsgi import get_wsgi_application -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'fet2020.settings') +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "fet2020.settings") application = get_wsgi_application() diff --git a/fet2020/members/admin.py b/fet2020/members/admin.py index 2e94f8f9..c6a9c196 100644 --- a/fet2020/members/admin.py +++ b/fet2020/members/admin.py @@ -6,13 +6,13 @@ from .forms import MemberForm, JobForm, JobGroupForm class MemberRoleFilter(admin.SimpleListFilter): - title = _('Rolle') - parameter_name = 'role' + title = _("Rolle") + parameter_name = "role" def lookups(self, request, model_admin): return ( - ('A', _('Aktiv')), - ('P', _('Pension')), + ("A", _("Aktiv")), + ("P", _("Pension")), ) def queryset(self, request, queryset): @@ -55,40 +55,53 @@ class MemberAdmin(admin.ModelAdmin): form = MemberForm model = Member fieldsets = ( - (None, { - 'fields': ( - ('firstname', 'surname',), - 'nickname', - 'username', - 'mailaccount', - 'role', - 'description', - 'image', - 'birthday', - 'phone', - 'address', - ) - }), + ( + None, + { + "fields": ( + ( + "firstname", + "surname", + ), + "nickname", + "username", + "mailaccount", + "role", + "description", + "image", + "birthday", + "phone", + "address", + ) + }, + ), ) inlines = (JobOverviewInline,) - list_display = ['nickname', 'firstname', 'surname', 'mailaccount', 'role'] - ordering = ['firstname', ] - search_fields = ['firstname', 'surname', 'nickname', 'mailaccount'] + list_display = ["nickname", "firstname", "surname", "mailaccount", "role"] + ordering = [ + "firstname", + ] + search_fields = ["firstname", "surname", "nickname", "mailaccount"] list_filter = [MemberRoleFilter] - def add_view(self, request, form_url='', extra_context=None): + def add_view(self, request, form_url="", extra_context=None): extra_context = extra_context or {} - extra_context['help_text'] = "Fette Schriften sind Pflichtfelder." + extra_context["help_text"] = "Fette Schriften sind Pflichtfelder." return super().add_view( - request, form_url, extra_context=extra_context, + request, + form_url, + extra_context=extra_context, ) - def change_view(self, request, object_id, form_url='', extra_context=None): + def change_view(self, request, object_id, form_url="", extra_context=None): extra_context = extra_context or {} - extra_context['help_text'] = "Fette Schriften sind Pflichtfelder." + extra_context["help_text"] = "Fette Schriften sind Pflichtfelder." return super().change_view( - request, object_id, form_url, extra_context=extra_context, + request, + object_id, + form_url, + extra_context=extra_context, ) def save_model(self, request, obj, form, change): @@ -101,22 +114,33 @@ class JobAdmin(admin.ModelAdmin): model = Job inlines = (ActiveMemberInline, InactiveMemberInline) - list_display = ['name', ] - ordering = ['name', ] - search_fields = ['name', ] + list_display = [ + "name", + ] + ordering = [ + "name", + ] + search_fields = [ + "name", + ] - def add_view(self, request, form_url='', extra_context=None): + def add_view(self, request, form_url="", extra_context=None): extra_context = extra_context or {} - extra_context['help_text'] = "Fette Schriften sind Pflichtfelder." + extra_context["help_text"] = "Fette Schriften sind Pflichtfelder." return super().add_view( - request, form_url, extra_context=extra_context, + request, + form_url, + extra_context=extra_context, ) - def change_view(self, request, object_id, form_url='', extra_context=None): + def change_view(self, request, object_id, form_url="", extra_context=None): extra_context = extra_context or {} - extra_context['help_text'] = "Fette Schriften sind Pflichfelder." + extra_context["help_text"] = "Fette Schriften sind Pflichfelder." return super().change_view( - request, object_id, form_url, extra_context=extra_context, + request, + object_id, + form_url, + extra_context=extra_context, ) def save_model(self, request, obj, form, change): @@ -127,24 +151,36 @@ class JobAdmin(admin.ModelAdmin): class JobGroupAdmin(admin.ModelAdmin): form = JobGroupForm model = JobGroup - inlines = (JobInline, ) + inlines = (JobInline,) - list_display = ['name', 'is_pinned', ] - ordering = ['name', ] - search_fields = ['name', ] + list_display = [ + "name", + "is_pinned", + ] + ordering = [ + "name", + ] + search_fields = [ + "name", + ] - def add_view(self, request, form_url='', extra_context=None): + def add_view(self, request, form_url="", extra_context=None): extra_context = extra_context or {} - extra_context['help_text'] = "Fette Schriften sind Pflichtfelder." + extra_context["help_text"] = "Fette Schriften sind Pflichtfelder." return super().add_view( - request, form_url, extra_context=extra_context, + request, + form_url, + extra_context=extra_context, ) - def change_view(self, request, object_id, form_url='', extra_context=None): + def change_view(self, request, object_id, form_url="", extra_context=None): extra_context = extra_context or {} - extra_context['help_text'] = "Fette Schriften sind Pflichfelder." + extra_context["help_text"] = "Fette Schriften sind Pflichfelder." return super().change_view( - request, object_id, form_url, extra_context=extra_context, + request, + object_id, + form_url, + extra_context=extra_context, ) def save_model(self, request, obj, form, change): diff --git a/fet2020/members/apps.py b/fet2020/members/apps.py index f773ade1..85a13061 100644 --- a/fet2020/members/apps.py +++ b/fet2020/members/apps.py @@ -2,4 +2,4 @@ from django.apps import AppConfig class MembersConfig(AppConfig): - name = 'members' + name = "members" diff --git a/fet2020/members/forms.py b/fet2020/members/forms.py index 0304b5eb..0e4c16b7 100644 --- a/fet2020/members/forms.py +++ b/fet2020/members/forms.py @@ -10,56 +10,68 @@ class MemberForm(forms.ModelForm): class Meta: model = Member fields = [ - 'firstname', 'surname', 'nickname', 'username', 'mailaccount', 'role', 'description', - 'image', 'birthday', 'phone', 'address', + "firstname", + "surname", + "nickname", + "username", + "mailaccount", + "role", + "description", + "image", + "birthday", + "phone", + "address", ] - widgets = { - 'description': CKEditorUploadingWidget(config_name='default') - } + widgets = {"description": CKEditorUploadingWidget(config_name="default")} labels = { - 'description': _("Beschreibung zu der Person"), - 'image': _("Porträt"), - 'birthday': _("Geburtstag"), - 'phone': _("Telefonnummer"), - 'address': _("Wohnadresse"), + "description": _("Beschreibung zu der Person"), + "image": _("Porträt"), + "birthday": _("Geburtstag"), + "phone": _("Telefonnummer"), + "address": _("Wohnadresse"), } help_texts = { - 'image': _( - "Mindestgröße: 150*150 px, Verwendbare Formate: ..." - ), - 'mailaccount': _( - "Die Mailadresse mit '@fet.at' angeben." - ), + "image": _("Mindestgröße: 150*150 px, Verwendbare Formate: ..."), + "mailaccount": _("Die Mailadresse mit '@fet.at' angeben."), } class JobForm(forms.ModelForm): class Meta: model = Job - fields = ['name', 'shortterm', 'slug', 'job_group',] + fields = [ + "name", + "shortterm", + "slug", + "job_group", + ] labels = { - 'shortterm': _("Kürzel der Tätigkeit"), - 'job_group': _("Tätigkeitsbereich"), + "shortterm": _("Kürzel der Tätigkeit"), + "job_group": _("Tätigkeitsbereich"), } class JobGroupForm(forms.ModelForm): class Meta: model = JobGroup - fields = ['name', 'shortterm', 'slug', 'description', 'is_pinned',] + fields = [ + "name", + "shortterm", + "slug", + "description", + "is_pinned", + ] - widgets = { - 'description': CKEditorUploadingWidget(config_name='default') - } + widgets = {"description": CKEditorUploadingWidget(config_name="default")} labels = { - 'shortterm': _("Kürzel des Tätigkeitsbereichs"), - 'description': _("Beschreibung des Tätigkeitsbereichs"), - 'is_pinned': _( + "shortterm": _("Kürzel des Tätigkeitsbereichs"), + "description": _("Beschreibung des Tätigkeitsbereichs"), + "is_pinned": _( "Dieser Tätigkeitsbereich soll im Fachschaftsbereich angeheftet werden, damit es sofort ersichtlich ist." ), } diff --git a/fet2020/members/models.py b/fet2020/members/models.py index 50da58b4..91559a3b 100644 --- a/fet2020/members/models.py +++ b/fet2020/members/models.py @@ -10,15 +10,20 @@ from easy_thumbnails.fields import ThumbnailerImageField class ActiveJobMemberManager(models.Manager): - ''' + """ return a list of active member, and members who are still working - ''' + """ + def get_all_by_slug(self, slug): - return self.get_queryset().filter(job__job_group__slug=slug).order_by('job__slug', 'job_role', 'member__firstname') + return ( + self.get_queryset() + .filter(job__job_group__slug=slug) + .order_by("job__slug", "job_role", "member__firstname") + ) def get_queryset(self): date_today = timezone.now().date() - qs = super().get_queryset().order_by('member__firstname') + qs = super().get_queryset().order_by("member__firstname") return qs.filter( Q(member__role=Member.MemberRole.ACTIVE) @@ -27,15 +32,20 @@ class ActiveJobMemberManager(models.Manager): class InactiveJobMemberManager(models.Manager): - ''' + """ return a list of inactive member - ''' + """ + def get_all_by_slug(self, slug): - return self.get_queryset().filter(job__job_group__slug=slug).order_by('job__slug', 'job_role', 'member__firstname') + return ( + self.get_queryset() + .filter(job__job_group__slug=slug) + .order_by("job__slug", "job_role", "member__firstname") + ) def get_queryset(self): date_today = timezone.now().date() - qs = super().get_queryset().order_by('member__firstname') + qs = super().get_queryset().order_by("member__firstname") return qs.filter( Q(member__role=Member.MemberRole.PENSION) @@ -45,7 +55,7 @@ class InactiveJobMemberManager(models.Manager): class JobMemberManager(models.Manager): def get_members(self, role): - qs = self.get_queryset().order_by('member__firstname') + qs = self.get_queryset().order_by("member__firstname") return qs.filter(Q(member__role=role)) @@ -82,19 +92,19 @@ class JobGroupManager(models.Manager): class MemberManager(models.Manager): def get_queryset(self): - return super().get_queryset().order_by('firstname') + return super().get_queryset().order_by("firstname") class Member(models.Model): firstname = models.CharField("Vorname", max_length=128) surname = models.CharField("Nachname", max_length=128) - nickname = models.CharField("Spitzname", max_length=128) + nickname = models.CharField("Spitzname", max_length=128) username = models.CharField("Benutzername", blank=True, max_length=128) mailaccount = models.CharField("Mailadresse", unique=True, max_length=128) class MemberRole(models.TextChoices): - ACTIVE = 'A', _('Active') - PENSION = 'P', _('Pension') + ACTIVE = "A", _("Active") + PENSION = "P", _("Pension") role = models.CharField( "Rolle", @@ -104,14 +114,16 @@ class Member(models.Model): ) description = models.TextField(null=True, blank=True) - image = ThumbnailerImageField(upload_to='uploads/members/image/') + image = ThumbnailerImageField(upload_to="uploads/members/image/") birthday = models.DateField(null=True, blank=True) - phone_error_msg = _(( - "Phone number must be entered in the format: +999999999'. Up to 15 digits allowed." - )) - phone_regex = RegexValidator(regex=r'^\+?1?\d{9,15}$', message=phone_error_msg) + phone_error_msg = _( + ( + "Phone number must be entered in the format: +999999999'. Up to 15 digits allowed." + ) + ) + phone_regex = RegexValidator(regex=r"^\+?1?\d{9,15}$", message=phone_error_msg) phone = models.CharField(validators=[phone_regex], max_length=17, blank=True) address = models.TextField(null=True, blank=True) @@ -134,15 +146,12 @@ class Member(models.Model): if self.image.height < 150 or self.image.width < 150: raise ValidationError( _("Das Bild ist zu klein. (Höhe: {}, Breite: {})").format( - self.image.height, - self.image.width + self.image.height, self.image.width ) ) if not "@fet.at" in self.mailaccount: - raise ValidationError( - _("In der Mailadresse fehlt die Domäne.") - ) + raise ValidationError(_("In der Mailadresse fehlt die Domäne.")) def __str__(self): return self.firstname + " " + self.surname @@ -198,7 +207,7 @@ class Job(models.Model): def save(self, *args, **kwargs): if not self.slug: self.slug = slugify(self.shortterm) - #if type(self.job_group) = str: + # if type(self.job_group) = str: # self.job_group=JobGroup.objects.filter(slug=self.job) super().save(*args, **kwargs) @@ -218,18 +227,20 @@ class JobMember(models.Model): verbose_name="Tätigkeit", ) - job_start = models.DateField('Job Start') - job_end = models.DateField('Job Ende', null=True, blank=True) + job_start = models.DateField("Job Start") + job_end = models.DateField("Job Ende", null=True, blank=True) class JobRole(models.TextChoices): - PRESIDENT = ('10', _('VorsitzendeR')) - VICE_PRESIDENT = ('20', _('stv VorsitzendeR')) - SECOND_VICE_PRESIDENT = ('30', _('2. stv VorsitzendeR')) - PERSON_RESPONSIBLE = ('40', _('VerantwortlicheR')) - MEMBER = ('50', _('Mitglied')) - SUBSTITUTE_MEMBER = ('60', _('Ersatzmitglied')) + PRESIDENT = ("10", _("VorsitzendeR")) + VICE_PRESIDENT = ("20", _("stv VorsitzendeR")) + SECOND_VICE_PRESIDENT = ("30", _("2. stv VorsitzendeR")) + PERSON_RESPONSIBLE = ("40", _("VerantwortlicheR")) + MEMBER = ("50", _("Mitglied")) + SUBSTITUTE_MEMBER = ("60", _("Ersatzmitglied")) - job_role = models.CharField(max_length=2, choices=JobRole.choices, default=JobRole.MEMBER) + job_role = models.CharField( + max_length=2, choices=JobRole.choices, default=JobRole.MEMBER + ) objects = models.Manager() members = JobMemberManager() diff --git a/fet2020/members/serializers.py b/fet2020/members/serializers.py index 204f306b..3a624b70 100644 --- a/fet2020/members/serializers.py +++ b/fet2020/members/serializers.py @@ -4,65 +4,50 @@ from rest_framework import serializers class MemberSerializer(serializers.HyperlinkedModelSerializer): - class Meta: model = Member - fields = ['id', - 'firstname', - 'surname', - 'nickname', - 'mailaccount', - 'role', - 'description', - 'image', - 'birthday', + fields = [ + "id", + "firstname", + "surname", + "nickname", + "mailaccount", + "role", + "description", + "image", + "birthday", ] + class JobGroupSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = JobGroup - fields = [ - 'id', - 'name', - 'shortterm', - 'slug' - ] + fields = ["id", "name", "shortterm", "slug"] + class JobSerializer(serializers.HyperlinkedModelSerializer): - #job_group = JobGroupSerializer() + # job_group = JobGroupSerializer() job_group = serializers.SlugRelatedField( - slug_field='slug',queryset = JobGroup.objects - ) + slug_field="slug", queryset=JobGroup.objects + ) + class Meta: model = Job - fields = [ - 'id', - 'name', - 'shortterm', - 'job_group', - 'slug' - ] + fields = ["id", "name", "shortterm", "job_group", "slug"] class JobMemberSerializer(serializers.HyperlinkedModelSerializer): - #member = MemberSerializer() - #job = JobSerializer() - job = serializers.SlugRelatedField( - slug_field='slug',queryset = Job.objects - ) - member= serializers.SlugRelatedField( - slug_field='mailaccount',queryset = Member.objects - ) + # member = MemberSerializer() + # job = JobSerializer() + job = serializers.SlugRelatedField(slug_field="slug", queryset=Job.objects) + member = serializers.SlugRelatedField( + slug_field="mailaccount", queryset=Member.objects + ) + class Meta: model = JobMember - fields = [ - 'id', - 'job_start', - 'job_end', - 'member', - 'job', - 'job_role' - ] + fields = ["id", "job_start", "job_end", "member", "job", "job_role"] + # def create(self, validated_data): # member_data = validated_data.pop('member') diff --git a/fet2020/members/urls.py b/fet2020/members/urls.py index 93c10b7a..00d47eb4 100644 --- a/fet2020/members/urls.py +++ b/fet2020/members/urls.py @@ -4,14 +4,14 @@ from . import views urlpatterns = [ - path('', views.index, name='members'), - path('', views.members_view), + path("", views.index, name="members"), + path("", views.members_view), ] member_urlpatterns = [ - path('', views.profile_view, name='member'), + path("", views.profile_view, name="member"), ] jobs_urlpatterns = [ - path('', views.jobs_view, name='jobs'), + path("", views.jobs_view, name="jobs"), ] diff --git a/fet2020/members/views.py b/fet2020/members/views.py index 5381cca7..1e2c4dbd 100644 --- a/fet2020/members/views.py +++ b/fet2020/members/views.py @@ -7,6 +7,7 @@ from .models import Member, JobMember, JobGroup, Job from posts.models import Post import logging + logger = logging.getLogger(__name__) @@ -41,7 +42,7 @@ def index(request): pinned_job_groups, unpinned_job_groups = __get_job_groups() members = deque(Member.all_members.all()) - fs_info = Post.objects.filter(slug='fachschaft-info').first() + fs_info = Post.objects.filter(slug="fachschaft-info").first() context = { "pinned_job_groups": pinned_job_groups, @@ -50,14 +51,16 @@ def index(request): "fs_info": fs_info, } - return render(request, 'members/index.html', context) + return render(request, "members/index.html", context) def jobs_view(request, slug=None): pinned_job_groups, unpinned_job_groups = __get_job_groups() try: - description = JobGroup.all_jobgroups.filter(slug=slug).values().first()['description'] + description = ( + JobGroup.all_jobgroups.filter(slug=slug).values().first()["description"] + ) except Exception as e: logger.info("Wrong job '{}'".format(slug)) raise Http404("wrong job") @@ -71,7 +74,7 @@ def jobs_view(request, slug=None): "job_members": job_members, } - return render(request, 'members/index.html', context) + return render(request, "members/index.html", context) def members_view(request, filter=None): @@ -83,7 +86,7 @@ def members_view(request, filter=None): logger.info("Wrong member role '{}'".format(filter)) raise Http404("no member role") - fs_info = Post.objects.filter(slug='fachschaft-info').first() + fs_info = Post.objects.filter(slug="fachschaft-info").first() context = { "pinned_job_groups": pinned_job_groups, @@ -92,7 +95,7 @@ def members_view(request, filter=None): "fs_info": fs_info, } - return render(request, 'members/index.html', context) + return render(request, "members/index.html", context) def profile_view(request, member_id=None): @@ -112,4 +115,4 @@ def profile_view(request, member_id=None): "jobs": jobs, } - return render(request, 'members/member.html', context) + return render(request, "members/member.html", context) diff --git a/fet2020/members/viewsets.py b/fet2020/members/viewsets.py index 27c1683f..92a0cf69 100644 --- a/fet2020/members/viewsets.py +++ b/fet2020/members/viewsets.py @@ -2,54 +2,63 @@ from django_filters.rest_framework import DjangoFilterBackend from rest_framework import viewsets from .models import Member, JobMember, JobGroup, Job -from .serializers import MemberSerializer, JobSerializer, JobGroupSerializer, JobMemberSerializer +from .serializers import ( + MemberSerializer, + JobSerializer, + JobGroupSerializer, + JobMemberSerializer, +) class MemberViewSet(viewsets.ModelViewSet): """ API endpoint that allows users to be viewed or edited. """ - queryset = Member.all_members.order_by('nickname') + + queryset = Member.all_members.order_by("nickname") serializer_class = MemberSerializer - #permission_classes = [permissions.IsAuthenticated] + # permission_classes = [permissions.IsAuthenticated] filter_backends = [DjangoFilterBackend] - filterset_fields = ['nickname','mailaccount'] - #lookup_field = 'name' + filterset_fields = ["nickname", "mailaccount"] + # lookup_field = 'name' def pre_save(self, obj): - obj.image = self.request.FILES.get('image') + obj.image = self.request.FILES.get("image") class JobGroupViewSet(viewsets.ModelViewSet): """ API endpoint that allows users to be viewed or edited. """ + queryset = JobGroup.all_jobgroups.all() serializer_class = JobGroupSerializer filter_backends = [DjangoFilterBackend] - filterset_fields = ['name','slug'] - #lookup_field = 'name' + filterset_fields = ["name", "slug"] + # lookup_field = 'name' class JobViewSet(viewsets.ModelViewSet): """ API endpoint that allows users to be viewed or edited. """ + queryset = Job.objects.all() serializer_class = JobSerializer filter_backends = [DjangoFilterBackend] - filterset_fields = ['name','slug'] - #lookup_field = 'slug' + filterset_fields = ["name", "slug"] + # lookup_field = 'slug' class JobMemberViewSet(viewsets.ModelViewSet): """ API endpoint that allows users to be viewed or edited. """ + queryset = JobMember.objects.all() serializer_class = JobMemberSerializer filter_backends = [DjangoFilterBackend] - filterset_fields = ['member','job','job_role','job_start'] - #lookup_field = 'nickname' + filterset_fields = ["member", "job", "job_role", "job_start"] + # lookup_field = 'nickname' diff --git a/fet2020/posts/admin.py b/fet2020/posts/admin.py index 60560e76..1a5b9f7f 100644 --- a/fet2020/posts/admin.py +++ b/fet2020/posts/admin.py @@ -13,7 +13,7 @@ admin.site.unregister(taggit.models.Tag) def make_fetmeeting(self, request, queryset): - qs = self.get_queryset(request).filter(id=request.POST['_selected_action']).first() + qs = self.get_queryset(request).filter(id=request.POST["_selected_action"]).first() failed = False agenda_key = None @@ -24,7 +24,7 @@ def make_fetmeeting(self, request, queryset): except Exception as e: self.message_user( request, - _('Das Agenda konnte nicht erstellt werden. Error: %s') % str(e), + _("Das Agenda konnte nicht erstellt werden. Error: %s") % str(e), messages.ERROR, ) failed = True @@ -34,14 +34,14 @@ def make_fetmeeting(self, request, queryset): except Exception as e: self.message_user( request, - _('Das Protokoll konnte nicht erstellt werden. Error: %s') % str(e), + _("Das Protokoll konnte nicht erstellt werden. Error: %s") % str(e), messages.ERROR, ) failed = True if not failed: queryset.update( - post_type='F', + post_type="F", has_agenda=True, has_protocol=True, agenda_key=agenda_key, @@ -49,7 +49,8 @@ def make_fetmeeting(self, request, queryset): ) self.message_user( request, - _('Das Event %s wurde erfolgreich in eine FET Sitzung konvertiert.') % (qs.title), + _("Das Event %s wurde erfolgreich in eine FET Sitzung konvertiert.") + % (qs.title), messages.SUCCESS, ) @@ -60,22 +61,27 @@ make_fetmeeting.short_description = "In eine Fachschaftssitzung konvertieren" class PostAdmin(admin.ModelAdmin): form = PostForm model = Post - list_filter = ['is_pinned', 'is_hidden'] - list_display = ['title', 'slug', 'public_date', 'is_pinned', 'is_hidden'] - ordering = ['is_hidden', '-public_date'] + list_filter = ["is_pinned", "is_hidden"] + list_display = ["title", "slug", "public_date", "is_pinned", "is_hidden"] + ordering = ["is_hidden", "-public_date"] - def add_view(self, request, form_url='', extra_context=None): + def add_view(self, request, form_url="", extra_context=None): extra_context = extra_context or {} - extra_context['help_text'] = "Fette Schriften sind Pflichtfelder." + extra_context["help_text"] = "Fette Schriften sind Pflichtfelder." return super().add_view( - request, form_url, extra_context=extra_context, + request, + form_url, + extra_context=extra_context, ) - def change_view(self, request, object_id, form_url='', extra_context=None): + def change_view(self, request, object_id, form_url="", extra_context=None): extra_context = extra_context or {} - extra_context['help_text'] = "Fette Schriften sind Pflichtfelder." + extra_context["help_text"] = "Fette Schriften sind Pflichtfelder." return super().change_view( - request, object_id, form_url, extra_context=extra_context, + request, + object_id, + form_url, + extra_context=extra_context, ) def save_model(self, request, obj, form, change): @@ -98,9 +104,9 @@ class PostAdmin(admin.ModelAdmin): class EventAdmin(PostAdmin): form = EventForm model = Event - list_filter = ['is_pinned'] - list_display = ['title', 'slug', 'event_start', 'public_date', 'is_pinned'] - ordering = ['-event_start'] + list_filter = ["is_pinned"] + list_display = ["title", "slug", "event_start", "public_date", "is_pinned"] + ordering = ["-event_start"] actions = [make_fetmeeting] @@ -113,7 +119,7 @@ class FetMeetingAdmin(EventAdmin): form = FetMeetingForm model = FetMeeting list_filter = [] - list_display = ['title', 'slug', 'event_start', 'public_date'] + list_display = ["title", "slug", "event_start", "public_date"] actions = [] diff --git a/fet2020/posts/apps.py b/fet2020/posts/apps.py index 2c2b982e..d39b3e18 100644 --- a/fet2020/posts/apps.py +++ b/fet2020/posts/apps.py @@ -2,4 +2,4 @@ from django.apps import AppConfig class PostsConfig(AppConfig): - name = 'posts' + name = "posts" diff --git a/fet2020/posts/forms.py b/fet2020/posts/forms.py index 00756c7f..ed87c9d3 100644 --- a/fet2020/posts/forms.py +++ b/fet2020/posts/forms.py @@ -10,14 +10,23 @@ from .models import Post, Event, News, FetMeeting class PostForm(forms.ModelForm): class Meta: model = Post - fields = ['title', 'subtitle', 'tags', 'image', 'body', 'slug', 'author', 'public_date'] + fields = [ + "title", + "subtitle", + "tags", + "image", + "body", + "slug", + "author", + "public_date", + ] - widgets = {'body': CKEditorUploadingWidget(config_name='default')} + widgets = {"body": CKEditorUploadingWidget(config_name="default")} class Media: js = ( - 'js/auto_slug.js', # automatic slag completion via ajax - 'js/tag_completion.js', # to get a list for tag autocompletion via ajax + "js/auto_slug.js", # automatic slag completion via ajax + "js/tag_completion.js", # to get a list for tag autocompletion via ajax ) @@ -25,106 +34,124 @@ class NewsForm(PostForm): class Meta: model = News fields = [ - 'title', 'subtitle', 'tags', 'image', 'body', 'slug', 'author', 'public_date', - 'is_pinned', 'is_hidden', + "title", + "subtitle", + "tags", + "image", + "body", + "slug", + "author", + "public_date", + "is_pinned", + "is_hidden", ] labels = { - 'title': _("Titel"), - 'subtitle': _("Untertitel"), - 'image': _("Hintergrundbild"), - 'body': _("Text"), - 'author': _("Autor"), - 'public_date': _("Veröffentlichung"), - 'is_pinned': _("Post anheften"), - 'is_hidden': _("Post verstecken"), + "title": _("Titel"), + "subtitle": _("Untertitel"), + "image": _("Hintergrundbild"), + "body": _("Text"), + "author": _("Autor"), + "public_date": _("Veröffentlichung"), + "is_pinned": _("Post anheften"), + "is_hidden": _("Post verstecken"), } help_texts = { - 'tags': _( + "tags": _( "Die Hashtags ohne '#' eintragen, und mit Komma kann man mehrere Tags anfügen." ), - 'image': _( - "Verwendbare Formate: ..." - ), - 'is_pinned': _( + "image": _("Verwendbare Formate: ..."), + "is_pinned": _( "Dieser Post soll an die Startseite als erster Post angeheftet werden." ), - 'is_hidden': _( + "is_hidden": _( "Dieser Post soll im News Feed nicht auftauchen, z.B. Impressum." ), } - widgets = {'body': CKEditorUploadingWidget(config_name='default')} + widgets = {"body": CKEditorUploadingWidget(config_name="default")} def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # to get the self.fields set - self.fields['author'].queryset = self.fields['author'].queryset.order_by('username') + self.fields["author"].queryset = self.fields["author"].queryset.order_by( + "username" + ) class EventForm(PostForm): class Meta: model = Event fields = [ - 'title', 'subtitle', 'tags', 'image', 'body', 'event_start', 'event_end', - 'event_place', 'slug', 'author', 'public_date', 'is_pinned', + "title", + "subtitle", + "tags", + "image", + "body", + "event_start", + "event_end", + "event_place", + "slug", + "author", + "public_date", + "is_pinned", ] labels = { - 'title': _("Titel"), - 'subtitle': _("Untertitel"), - 'image': _("Hintergrundbild"), - 'body': _("Text"), - 'event_start': _("Start des Events"), - 'event_end': _("Ende des Events"), - 'event_place': _("Ort des Events"), - 'author': _("Autor"), - 'public_date': _("Veröffentlichung"), - 'is_pinned': _("Event anheften"), + "title": _("Titel"), + "subtitle": _("Untertitel"), + "image": _("Hintergrundbild"), + "body": _("Text"), + "event_start": _("Start des Events"), + "event_end": _("Ende des Events"), + "event_place": _("Ort des Events"), + "author": _("Autor"), + "public_date": _("Veröffentlichung"), + "is_pinned": _("Event anheften"), } help_texts = { - 'tags': _( + "tags": _( "Die Hashtags ohne '#' eintragen, und mit Komma kann man mehrere Tags anfügen." ), - 'image': _( - "Verwendbare Formate: " - ), - 'is_pinned': _( + "image": _("Verwendbare Formate: "), + "is_pinned": _( "Dieses Event soll an die Startseite als erster Post angeheftet werden." ), } - widgets = {'body': CKEditorUploadingWidget(config_name='default')} + widgets = {"body": CKEditorUploadingWidget(config_name="default")} def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # to get the self.fields set - self.fields['author'].queryset = self.fields['author'].queryset.order_by('username') + self.fields["author"].queryset = self.fields["author"].queryset.order_by( + "username" + ) - self.fields['event_start'].required = True - self.fields['event_end'].required = False + self.fields["event_start"].required = True + self.fields["event_end"].required = False - if 'event_place' in self.fields: - self.fields['event_place'].required = True + if "event_place" in self.fields: + self.fields["event_place"].required = True class FetMeetingForm(PostForm): # agenda_html = forms.CharField(widget = forms.TextInput()) class Meta: model = FetMeeting - fields = ['event_start', 'event_end', 'tags']#, 'has_agenda', 'has_protocol'] + fields = ["event_start", "event_end", "tags"] # , 'has_agenda', 'has_protocol'] labels = { - 'event_start': _("Start der Sitzung"), - 'event_end': _("Ende der Sitzung")#, -# 'has_agenda': _("Agenda"), -# 'has_protocol': _("Protokoll"), + "event_start": _("Start der Sitzung"), + "event_end": _("Ende der Sitzung") # , + # 'has_agenda': _("Agenda"), + # 'has_protocol': _("Protokoll"), } help_texts = { - 'tags': _( + "tags": _( "Die Hashtags ohne '#' eintragen, und mit Komma kann man mehrere Tags anfügen." - )#, + ) # , #'has_agenda': _("Agenda zur Sitzung hinzufügen."), #'has_protocol': _("Protokoll zur Sitzung hinzufügen."), } @@ -132,13 +159,13 @@ class FetMeetingForm(PostForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # to get the self.fields set - self.fields['event_start'].required = True - self.fields['event_end'].required = False + self.fields["event_start"].required = True + self.fields["event_end"].required = False - #self.fields['has_agenda'].initial = True - #self.fields['has_protocol'].initial = True + # self.fields['has_agenda'].initial = True + # self.fields['has_protocol'].initial = True tags = [] tags.append(Tag()) tags[0].name = "fachschaft" - self.fields['tags'].initial = tags + self.fields["tags"].initial = tags diff --git a/fet2020/posts/mails.py b/fet2020/posts/mails.py index 8b6ef842..a9967cd1 100644 --- a/fet2020/posts/mails.py +++ b/fet2020/posts/mails.py @@ -3,15 +3,22 @@ from django.core.mail import send_mail def send_agenda_mail(date, time, slug): - msg = "Liebe Alle,\n\n" \ - "wir haben am " + str(date) + " um " + str(time) + " wieder Sitzung.\n" \ - "du hast noch bis morgen Zeit, weitere Themen auf die Agenda zu schreiben: " \ - + settings.HOST_NAME + '/posts/' + str(slug) + ".\n\n" \ + msg = ( + "Liebe Alle,\n\n" + "wir haben am " + str(date) + " um " + str(time) + " wieder Sitzung.\n" + "du hast noch bis morgen Zeit, weitere Themen auf die Agenda zu schreiben: " + + settings.HOST_NAME + + "/posts/" + + str(slug) + + ".\n\n" "LG deine FET" + ) send_mail( - subject = 'Test - Agenda der FET Sitzung von ' + str(date), - message = msg, - from_email = 'patrick@fet.at', - recipient_list = ['all@fet.at', ], + subject="Test - Agenda der FET Sitzung von " + str(date), + message=msg, + from_email="patrick@fet.at", + recipient_list=[ + "all@fet.at", + ], ) diff --git a/fet2020/posts/managers.py b/fet2020/posts/managers.py index a8577d4d..cbdaddb7 100644 --- a/fet2020/posts/managers.py +++ b/fet2020/posts/managers.py @@ -5,23 +5,32 @@ from django.utils import timezone class PostManager(models.Manager): def get_queryset(self): - return super().get_queryset().order_by('-public_date') + return super().get_queryset().order_by("-public_date") def get_visible_articles(self): return self.get_queryset().filter(is_hidden=False) def all_post_with_date(self): - return self.get_queryset().filter(Q(event_start__isnull=False) & Q(event_end__isnull=False)).order_by('-event_start') + return ( + self.get_queryset() + .filter(Q(event_start__isnull=False) & Q(event_end__isnull=False)) + .order_by("-event_start") + ) + + class ArticleManager(models.Manager): """ Provide a query set only for "Article" regular fet meetings should not be contained in the news stream """ + def get_queryset(self): - return super().get_queryset().filter( - Q(post_type='E') - | Q(post_type='N') - ).order_by('-public_date') + return ( + super() + .get_queryset() + .filter(Q(post_type="E") | Q(post_type="N")) + .order_by("-public_date") + ) def get_visible_articles(self): return self.get_queryset().filter(is_hidden=False) @@ -34,8 +43,9 @@ class NewsManager(models.Manager): """ Provide a query set only for "News" """ + def get_queryset(self): - return super().get_queryset().filter(post_type='N').order_by('-public_date') + return super().get_queryset().filter(post_type="N").order_by("-public_date") def get_visible_articles(self): return self.get_queryset().filter(is_hidden=False) @@ -45,12 +55,17 @@ class AllEventManager(models.Manager): """ Provide a query set for all events ("Event" and "Fet Meeting") """ + def get_queryset(self): - return super().get_queryset().filter(Q(post_type='E') | Q(post_type='F')) + return super().get_queryset().filter(Q(post_type="E") | Q(post_type="F")) def get_five_events(self): date_today = timezone.now() - return self.get_queryset().filter(event_start__gt=date_today).order_by('event_start')[:5] + return ( + self.get_queryset() + .filter(event_start__gt=date_today) + .order_by("event_start")[:5] + ) class EventManager(models.Manager): @@ -58,32 +73,50 @@ class EventManager(models.Manager): Provide a query set only for "Events" regular fet meetings should not be contained in the news stream """ + def get_queryset(self): - return super().get_queryset().filter(post_type='E') + return super().get_queryset().filter(post_type="E") def get_future_events(self): date_today = timezone.now() - return self.get_queryset().filter(event_start__gt=date_today).order_by('event_start') + return ( + self.get_queryset() + .filter(event_start__gt=date_today) + .order_by("event_start") + ) def get_past_events(self): date_today = timezone.now() - return self.get_queryset().filter(event_start__lt=date_today).order_by('-event_start') + return ( + self.get_queryset() + .filter(event_start__lt=date_today) + .order_by("-event_start") + ) class FetMeetingManager(models.Manager): """ Provide a query set only for "Fet Meeting" """ + def get_queryset(self): - return super().get_queryset().filter(post_type='F') + return super().get_queryset().filter(post_type="F") def _get_future_events(self): date_today = timezone.now() - return self.get_queryset().filter(event_start__gt=date_today).order_by('event_start') + return ( + self.get_queryset() + .filter(event_start__gt=date_today) + .order_by("event_start") + ) def _get_past_events(self): date_today = timezone.now() - return self.get_queryset().filter(event_start__lt=date_today).order_by('-event_start') + return ( + self.get_queryset() + .filter(event_start__lt=date_today) + .order_by("-event_start") + ) def get_meetings(self): meetings = [] diff --git a/fet2020/posts/models.py b/fet2020/posts/models.py index 9d7f49eb..daf40877 100644 --- a/fet2020/posts/models.py +++ b/fet2020/posts/models.py @@ -133,6 +133,7 @@ class Post(models.Model): ) html = None return html + @property def protocol_html(self): "Protocol HTML from Etherpad Pad" @@ -196,7 +197,7 @@ class Post(models.Model): def get_agenda_key(self): """Create a Etherpad Id for the Pad associated to this post. - Creates the pad if it doesn't exist""" + Creates the pad if it doesn't exist""" if not self.slug: return None return create_pad_for_post(self.slug, typ="agenda") @@ -255,9 +256,10 @@ class Post(models.Model): def clean(self): if self.event_end and self.event_end < self.event_start: raise ValidationError(_("Das Ende des Events liegt vor dem Beginn.")) - if self.event_start and self.post_type not in ['E','F']: + if self.event_start and self.post_type not in ["E", "F"]: raise ValidationError("Für diesen Post Typ ist kein Event Start zulässig") super().clean() + def save(self, *args, **kwargs): # save the post with some defaults if not self.public_date: @@ -307,9 +309,9 @@ class Event(Post): verbose_name = "Event" verbose_name_plural = "Events" - def __init__(self,*args,**kwargs): - super().__init__(*args,**kwargs) - self.post_type='E' + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.post_type = "E" def clean(self): if not self.event_start: @@ -334,10 +336,10 @@ class FetMeeting(Event): verbose_name = "Fet Sitzung" verbose_name_plural = "Fet Sitzungen" - def __init__(self,*args,**kwargs): - super().__init__(*args,**kwargs) - self.post_type='F' - + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.post_type = "F" + def __get_slug(self): slug = slugify(self.event_start.date()) + "-" + slugify("Fachschaftssitzung") @@ -349,48 +351,47 @@ class FetMeeting(Event): return slug -# def __get_agenda_key(self): -# if not self.slug: -# return None## -# -# try: -# agenda_key = createPadifNotExists(self.slug + "-agenda") -# except Exception as error: -# raise ValidationError( -# _("Die Agenda konnte nicht erstellt werden. Error: %(error)s"), -# params={"error": str(error)}, -# ) from error -# -# return agenda_key + # def __get_agenda_key(self): + # if not self.slug: + # return None## + # + # try: + # agenda_key = createPadifNotExists(self.slug + "-agenda") + # except Exception as error: + # raise ValidationError( + # _("Die Agenda konnte nicht erstellt werden. Error: %(error)s"), + # params={"error": str(error)}, + # ) from error + # + # return agenda_key + + # def __get_protocol_key(self): + # if not self.slug: + # return None# + # + # try: + # protocol_key = createPadifNotExists(self.slug + "-protocol") + # except URLError as error: + # raise ValidationError( + # _("Das Protokoll konnte nicht erstellt werden. Error: %(error)s"), + # params={"error": str(error)}, + # ) from error# + # + # return protocol_key -# def __get_protocol_key(self): -# if not self.slug: -# return None# -# -# try: -# protocol_key = createPadifNotExists(self.slug + "-protocol") -# except URLError as error: -# raise ValidationError( -# _("Das Protokoll konnte nicht erstellt werden. Error: %(error)s"), -# params={"error": str(error)}, -# ) from error# -# -# return protocol_key - - def clean(self): super().clean() if not self.slug: self.slug = self.__get_slug() - + def save(self, *args, **kwargs): self.title = "Fachschaftssitzung" if not self.slug: self.slug = self.__get_slug() - + self.has_agenda = True self.has_protocol = True - + self.agenda_key = self.get_agenda_key() self.protocol_key = self.get_protocol_key() diff --git a/fet2020/posts/serializers.py b/fet2020/posts/serializers.py index 4c09e4b7..57f0b874 100644 --- a/fet2020/posts/serializers.py +++ b/fet2020/posts/serializers.py @@ -5,33 +5,34 @@ from rest_framework import serializers class PostSerializer(serializers.HyperlinkedModelSerializer): agenda_html = serializers.CharField(required=False) - tag_string = serializers.CharField(required=False,read_only=True) - imageurl = serializers.CharField(required=False,read_only=True) + tag_string = serializers.CharField(required=False, read_only=True) + imageurl = serializers.CharField(required=False, read_only=True) + class Meta: model = Post fields = [ - 'slug', - 'title', - 'subtitle', - 'body', - 'url', - 'post_type', - 'public_date', - 'legacy_id', - 'image', - 'event_start', - 'event_end', - 'is_hidden', - 'agenda_html', - 'protocol_html', - 'has_agenda', - 'has_protocol', - 'tag_string', - 'imageurl' + "slug", + "title", + "subtitle", + "body", + "url", + "post_type", + "public_date", + "legacy_id", + "image", + "event_start", + "event_end", + "is_hidden", + "agenda_html", + "protocol_html", + "has_agenda", + "has_protocol", + "tag_string", + "imageurl" # 'author', ] - extra_kwargs={ - 'agenda_html': {"required": False}, - 'protocol_html': {"required": False} + extra_kwargs = { + "agenda_html": {"required": False}, + "protocol_html": {"required": False}, } diff --git a/fet2020/posts/urls.py b/fet2020/posts/urls.py index d0204e37..003a7516 100644 --- a/fet2020/posts/urls.py +++ b/fet2020/posts/urls.py @@ -3,10 +3,10 @@ from . import views urlpatterns = [ - path('func/tag_complete', views.tag_complete), - path('func/slug_calc', views.slug_calc), - path('t/', views.tags, name='posts.tags'), - path('', views.index, name='posts.index'), - path('fet_calendar.ics', views.calendar, name='posts.calendar'), - path('', views.show, name='posts.show'), + path("func/tag_complete", views.tag_complete), + path("func/slug_calc", views.slug_calc), + path("t/", views.tags, name="posts.tags"), + path("", views.index, name="posts.index"), + path("fet_calendar.ics", views.calendar, name="posts.calendar"), + path("", views.show, name="posts.show"), ] diff --git a/fet2020/posts/views.py b/fet2020/posts/views.py index 5b6c4f27..5c4a570e 100644 --- a/fet2020/posts/views.py +++ b/fet2020/posts/views.py @@ -27,7 +27,7 @@ def index(request): "Index von aktuellen Posts" posts = deque(Post.objects.get_visible_articles().order_by("-public_date")) - taglist = map(lambda post : post.tags, posts) + taglist = map(lambda post: post.tags, posts) return render(request, "posts/index.html", {"posts": posts, "tags_list": taglist}) @@ -35,7 +35,7 @@ def index(request): def calendar(request): "Kalender Ansicht ICS zur Verknüpfung mit Outlook" events = deque(Post.objects.all_post_with_date().all()) - + return render( request, "posts/fet_calendar.ics", @@ -48,7 +48,6 @@ def tags(request, tag=""): posts = deque(Post.objects.get_visible_articles().filter(tags__name=tag)) featured_post = Post.objects.get_visible_articles().filter(slug=tag).first() - job_members = JobMember.active_member.get_all_by_slug(slug=tag) author_image = None @@ -86,25 +85,21 @@ def show(request, id=None): ep_agenda_link = "#" ep_protocol_link = "#" - if p.has_agenda:# and p.agenda_key: + if p.has_agenda: # and p.agenda_key: try: ep_agenda_link = get_pad_link(p.agenda_key) except Exception as e: logger.error( - "Can't get the agenda link from '%s'. Error: %s", - p.agenda_key, - e + "Can't get the agenda link from '%s'. Error: %s", p.agenda_key, e ) ep_agenda_link = "#" - if p.has_protocol:# and p.protocol_key: + if p.has_protocol: # and p.protocol_key: try: ep_protocol_link = get_pad_link(p.protocol_key) except Exception as e: logger.error( - "Can't get the protocol link from '%s. Error: %s", - p.protocol_key, e - + "Can't get the protocol link from '%s. Error: %s", p.protocol_key, e ) ep_protocol_link = "#" @@ -125,8 +120,7 @@ def show(request, id=None): try: response = add_ep_cookie(request, response) except Exception as e: - logger.info( - "Etherpad Server doesn't work. Error: %s", e) + logger.info("Etherpad Server doesn't work. Error: %s", e) return response diff --git a/fet2020/tasks/admin.py b/fet2020/tasks/admin.py index 83c3a1d0..54e0f3dd 100644 --- a/fet2020/tasks/admin.py +++ b/fet2020/tasks/admin.py @@ -8,23 +8,33 @@ class TaskAdmin(admin.ModelAdmin): form = TaskAdminForm model = Task fieldsets = ( - (None, { - 'fields': ( - 'title', - 'task_list', - 'assigned_to', - 'due_date', - 'completed', - 'completed_date', - 'note', - 'priority', - ) - }), + ( + None, + { + "fields": ( + "title", + "task_list", + "assigned_to", + "due_date", + "completed", + "completed_date", + "note", + "priority", + ) + }, + ), ) - list_display = ['title', 'task_list', 'assigned_to', 'due_date', 'completed', 'priority'] - list_filter = ('task_list', ) - search_fields = ('title', ) + list_display = [ + "title", + "task_list", + "assigned_to", + "due_date", + "completed", + "priority", + ] + list_filter = ("task_list",) + search_fields = ("title",) def save_model(self, request, obj, form, change): obj.created_by = request.user diff --git a/fet2020/tasks/apps.py b/fet2020/tasks/apps.py index 20547224..5aadae04 100644 --- a/fet2020/tasks/apps.py +++ b/fet2020/tasks/apps.py @@ -2,4 +2,4 @@ from django.apps import AppConfig class TasksConfig(AppConfig): - name = 'tasks' + name = "tasks" diff --git a/fet2020/tasks/forms.py b/fet2020/tasks/forms.py index 5f83602b..df92cca3 100644 --- a/fet2020/tasks/forms.py +++ b/fet2020/tasks/forms.py @@ -7,29 +7,31 @@ from .models import Task, TaskList class DateInput(forms.DateInput): - input_type = 'date' + input_type = "date" class TaskAdminForm(forms.ModelForm): class Meta: model = Task - fields = '__all__' + fields = "__all__" labels = { - 'title': _('Titel'), - 'task_list': _('Aufgabenbereich'), - 'due_date': _('Fälligkeit'), - 'completed': _('Abgeschlossen'), - 'completed_date': _('Datum der Fertigstellung'), - 'assigned_to': _('Zuweisen an'), - 'note': _('Notizen'), - 'priority': _('Priorität'), + "title": _("Titel"), + "task_list": _("Aufgabenbereich"), + "due_date": _("Fälligkeit"), + "completed": _("Abgeschlossen"), + "completed_date": _("Datum der Fertigstellung"), + "assigned_to": _("Zuweisen an"), + "note": _("Notizen"), + "priority": _("Priorität"), } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # to get the self.fields set - self.fields['assigned_to'].empty_label = "Alle" - self.fields['assigned_to'].queryset = self.fields['assigned_to'].queryset.order_by('username') + self.fields["assigned_to"].empty_label = "Alle" + self.fields["assigned_to"].queryset = self.fields[ + "assigned_to" + ].queryset.order_by("username") class TaskForm(forms.ModelForm): @@ -37,39 +39,41 @@ class TaskForm(forms.ModelForm): model = Task fields = [ - 'title', - 'task_list', - 'due_date', - 'assigned_to', + "title", + "task_list", + "due_date", + "assigned_to", ] labels = { - 'title': _('Titel des Tasks'), - 'task_list': _('Task-Gruppe'), - 'due_date': _('Fälligkeitsdatum'), - 'assigned_to': _('Zuweisen an'), + "title": _("Titel des Tasks"), + "task_list": _("Task-Gruppe"), + "due_date": _("Fälligkeitsdatum"), + "assigned_to": _("Zuweisen an"), } widgets = { - 'due_date': DateInput( - format=('%d-%m-%Y'), + "due_date": DateInput( + format=("%d-%m-%Y"), ) } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # to get the self.fields set - self.fields['assigned_to'].empty_label = "Alle" - self.fields['assigned_to'].queryset = self.fields['assigned_to'].queryset.order_by('username') + self.fields["assigned_to"].empty_label = "Alle" + self.fields["assigned_to"].queryset = self.fields[ + "assigned_to" + ].queryset.order_by("username") class TaskListForm(forms.ModelForm): users = forms.ModelMultipleChoiceField( label="Benutzer", help_text="Es können nur die Benutzer ausgewählt werden, die sich auf der Homepage angemeldet haben.", - queryset=User.objects.all().order_by('username'), - widget=FilteredSelectMultiple("User", is_stacked=False) + queryset=User.objects.all().order_by("username"), + widget=FilteredSelectMultiple("User", is_stacked=False), ) class Meta: model = TaskList - fields = '__all__' + fields = "__all__" diff --git a/fet2020/tasks/models.py b/fet2020/tasks/models.py index 932decb8..49c31261 100644 --- a/fet2020/tasks/models.py +++ b/fet2020/tasks/models.py @@ -7,7 +7,7 @@ from django.utils import timezone class TaskQuerySet(models.QuerySet): def get_ordered(self): - return self.order_by('task_list') + return self.order_by("task_list") class TaskManager(models.Manager): @@ -16,7 +16,11 @@ class TaskManager(models.Manager): qs = self.get_queryset().get_ordered().filter(assigned_to__id=user) if all_tasks: - qs_tmp = self.get_queryset().get_ordered().filter(Q(assigned_to=None) & Q(task_list__users__id__exact=user)) + qs_tmp = ( + self.get_queryset() + .get_ordered() + .filter(Q(assigned_to=None) & Q(task_list__users__id__exact=user)) + ) qs = (qs | qs_tmp).distinct() if not completed: @@ -24,7 +28,7 @@ class TaskManager(models.Manager): if task_list: qs = qs.filter(task_list=task_list) - + return qs def get_queryset(self): @@ -49,7 +53,9 @@ class TaskList(models.Model): class Task(models.Model): title = models.CharField(verbose_name="Titel", max_length=140) - task_list = models.ForeignKey(TaskList, verbose_name="Aufgabenbereich", on_delete=models.CASCADE, null=True) + task_list = models.ForeignKey( + TaskList, verbose_name="Aufgabenbereich", on_delete=models.CASCADE, null=True + ) created_date = models.DateTimeField(auto_now_add=True) due_date = models.DateField(verbose_name="Fälligkeit", blank=True, null=True) @@ -72,7 +78,9 @@ class Task(models.Model): ) note = models.TextField(verbose_name="Notizen", blank=True, null=True) - priority = models.PositiveIntegerField(verbose_name="Priorität", blank=True, null=True) + priority = models.PositiveIntegerField( + verbose_name="Priorität", blank=True, null=True + ) objects = models.Manager() taskmanager = TaskManager() diff --git a/fet2020/tasks/urls.py b/fet2020/tasks/urls.py index f1eab942..6ea2af7d 100644 --- a/fet2020/tasks/urls.py +++ b/fet2020/tasks/urls.py @@ -4,5 +4,5 @@ from . import views urlpatterns = [ - path('', views.index, name='tasks'), + path("", views.index, name="tasks"), ] diff --git a/fet2020/tasks/views.py b/fet2020/tasks/views.py index 5b68db00..466da333 100644 --- a/fet2020/tasks/views.py +++ b/fet2020/tasks/views.py @@ -17,8 +17,8 @@ def index(request): show_tasklist = None show_all_tasks = True - if request.method == 'POST': - if 'btn_input' in request.POST: + if request.method == "POST": + if "btn_input" in request.POST: form = TaskForm(request.POST) if form.is_valid(): @@ -29,13 +29,18 @@ def index(request): task.created_by = request.user task.save() else: - messages.info(request, "User '{}' ist nicht in der Liste von Task-Gruppe '{}'.".format(task.assigned_to, task.task_list.name)) + messages.info( + request, + "User '{}' ist nicht in der Liste von Task-Gruppe '{}'.".format( + task.assigned_to, task.task_list.name + ), + ) else: task.created_by = request.user task.save() - elif 'btn_checkbox' in request.POST: - for task_id in request.POST.getlist('checkbox'): + elif "btn_checkbox" in request.POST: + for task_id in request.POST.getlist("checkbox"): task = Task.objects.get(id=task_id) if not task.completed: @@ -43,27 +48,31 @@ def index(request): task.completed_date = timezone.now().date() task.save() - elif 'btn_user' in request.POST: - if request.POST['action'] == 'show_incompleted': + elif "btn_user" in request.POST: + if request.POST["action"] == "show_incompleted": current_action = False else: current_action = True - if request.POST['tasklist'] != 'all': - show_tasklist = TaskList.objects.filter(id=request.POST['tasklist']).first() + if request.POST["tasklist"] != "all": + show_tasklist = TaskList.objects.filter( + id=request.POST["tasklist"] + ).first() - if request.POST['tasks'] == 'all': + if request.POST["tasks"] == "all": show_all_tasks = True else: show_all_tasks = False form = TaskForm() - tasks = deque(Task.taskmanager.get_tasks( - user=current_user, - completed=current_action, - task_list=show_tasklist, - all_tasks=show_all_tasks - )) + tasks = deque( + Task.taskmanager.get_tasks( + user=current_user, + completed=current_action, + task_list=show_tasklist, + all_tasks=show_all_tasks, + ) + ) tasklists = deque(TaskList.objects.all()) context = { @@ -74,4 +83,4 @@ def index(request): "current_action": current_action, } - return render(request, 'tasks/index.html', context) + return render(request, "tasks/index.html", context) From 2c90e50dbc944f16684938022e942aff8d6da394 Mon Sep 17 00:00:00 2001 From: Patrick Date: Fri, 15 Jan 2021 16:18:20 +0000 Subject: [PATCH 12/15] fix admin --- fet2020/fet2020/middleware.py | 22 ++++++++++++++++++++++ fet2020/fet2020/settings.py | 1 + 2 files changed, 23 insertions(+) diff --git a/fet2020/fet2020/middleware.py b/fet2020/fet2020/middleware.py index e69de29b..4a638721 100644 --- a/fet2020/fet2020/middleware.py +++ b/fet2020/fet2020/middleware.py @@ -0,0 +1,22 @@ +# from django.contrib.auth.models import User +from django.contrib.auth.middleware import RemoteUserMiddleware +# import django +# import logging +# logger=logging.getLogger("django.request") + + +class FETHeaderMiddleware(RemoteUserMiddleware): + header = "Remote-User" + + def process_request(self, request): + request.META[self.header] = request.META.get( + self.header, + request.headers.get(self.header, None) + ) + # logger = logging.getLogger(__name__) + super().process_request(request) + # logger.info('User: ' + str(request.user)) + if request.user.is_authenticated: + request.user.is_admin = True + request.user.is_superuser = True + request.user.is_staff = True diff --git a/fet2020/fet2020/settings.py b/fet2020/fet2020/settings.py index 5a752a22..1bea2592 100644 --- a/fet2020/fet2020/settings.py +++ b/fet2020/fet2020/settings.py @@ -89,6 +89,7 @@ MIDDLEWARE = [ "django.middleware.common.CommonMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", + "fet2020.middleware.FETHeaderMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", ] From 450f40e1a81db91df2dc8b0d03ec7e58c034643b Mon Sep 17 00:00:00 2001 From: patrick Date: Sun, 17 Jan 2021 13:10:46 +0000 Subject: [PATCH 13/15] add translation for de_AT --- fet2020/fet2020/settings.py | 2 + fet2020/locale/de/LC_MESSAGES/django.mo | Bin 0 -> 539 bytes fet2020/locale/de/LC_MESSAGES/django.po | 346 ++++++++++++++++++++++++ 3 files changed, 348 insertions(+) create mode 100644 fet2020/locale/de/LC_MESSAGES/django.mo create mode 100644 fet2020/locale/de/LC_MESSAGES/django.po diff --git a/fet2020/fet2020/settings.py b/fet2020/fet2020/settings.py index 1bea2592..64f83383 100644 --- a/fet2020/fet2020/settings.py +++ b/fet2020/fet2020/settings.py @@ -176,6 +176,8 @@ USE_L10N = True USE_TZ = True +LOCALE_PATHS = [os.path.join(BASE_DIR, 'locale')] + # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.0/howto/static-files/ diff --git a/fet2020/locale/de/LC_MESSAGES/django.mo b/fet2020/locale/de/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..fe74f0fcf4a6a9650a41eccb1a6c21b1365f1e5c GIT binary patch literal 539 zcmY+9!A=4(5QeK_G<)#i!IOu2(~!Yk5~C^MfU+pW6+%`My_f>yx@5OYy2Z#F=+T33 zz&m*G=zI7qPJy6K^5yS8{X1>Hw+ru#YMt06>cj?-5Vl?j>tBg&;%%W*(lz3PsIM^g zNosR!bv|p8)cP&b0_hGZ#g=8y+B@wYZ86r8YAp4H$zD(6Q;DaUGLHr7mY7V;A3sYC zrD7eO4Y6;aIe;6~d7LT1AJCNDvg>qllxYJ&9>oJV9Y;BYncz;R9m1JLX($YJX;5&A zd*FKD9doZNj*g2i6$PP-Pq7`k$ldz2E(C3;*Z4(S1kK`I`^tANWo{tUQss#>nHId^ zhtyQjSVjmT%2e=k)Tvab~N8Rqh>B Q9M<}pDusHcrGJk70PtywXaE2J literal 0 HcmV?d00001 diff --git a/fet2020/locale/de/LC_MESSAGES/django.po b/fet2020/locale/de/LC_MESSAGES/django.po new file mode 100644 index 00000000..9d83965b --- /dev/null +++ b/fet2020/locale/de/LC_MESSAGES/django.po @@ -0,0 +1,346 @@ +# Translation for Austrian German 'de_AT'. You have to use 'de' because Django doesn't support 'de_AT'. +msgid "" +msgstr "" +"Project-Id-Version: fet2020\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-01-17 12:57+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FET\n" +"Language-Team: German\n" +"Language: de_AT\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: blackboard/forms.py:13 +msgid "Firmenname" +msgstr "" + +#: blackboard/forms.py:14 +msgid "Berufsbezeichnung" +msgstr "" + +#: blackboard/forms.py:15 +msgid "Gehalt" +msgstr "" + +#: blackboard/forms.py:16 +msgid "Stellenausschreibung" +msgstr "" + +#: blackboard/forms.py:17 posts/forms.py:55 posts/forms.py:109 +msgid "Veröffentlichung" +msgstr "" + +#: blackboard/forms.py:21 +msgid "Verwendbare Formate: PDF" +msgstr "" + +#: blackboard/forms.py:22 +msgid "in Euro angeben" +msgstr "" + +#: blackboard/models.py:87 +msgid "Keine Dateien mit >1 Punkten im Namen erlaubt." +msgstr "" + +#: members/admin.py:9 +msgid "Rolle" +msgstr "" + +#: members/admin.py:14 +msgid "Aktiv" +msgstr "" + +#: members/admin.py:15 members/models.py:107 +msgid "Pension" +msgstr "" + +#: members/forms.py:29 +msgid "Beschreibung zu der Person" +msgstr "" + +#: members/forms.py:30 +msgid "Porträt" +msgstr "" + +#: members/forms.py:31 +msgid "Geburtstag" +msgstr "" + +#: members/forms.py:32 +msgid "Telefonnummer" +msgstr "" + +#: members/forms.py:33 +msgid "Wohnadresse" +msgstr "" + +#: members/forms.py:37 +msgid "Mindestgröße: 150*150 px, Verwendbare Formate: ..." +msgstr "" + +#: members/forms.py:38 +msgid "Die Mailadresse mit '@fet.at' angeben." +msgstr "" + +#: members/forms.py:53 +msgid "Kürzel der Tätigkeit" +msgstr "" + +#: members/forms.py:54 +msgid "Tätigkeitsbereich" +msgstr "" + +#: members/forms.py:72 +msgid "Kürzel des Tätigkeitsbereichs" +msgstr "" + +#: members/forms.py:73 +msgid "Beschreibung des Tätigkeitsbereichs" +msgstr "" + +#: members/forms.py:75 +msgid "" +"Dieser Tätigkeitsbereich soll im Fachschaftsbereich angeheftet werden, damit " +"es sofort ersichtlich ist." +msgstr "" + +#: members/models.py:106 +msgid "Active" +msgstr "" + +#: members/models.py:144 +msgid "Es fehlt das Profilbild." +msgstr "" + +#: members/models.py:148 +msgid "Das Bild ist zu klein. (Höhe: {}, Breite: {})" +msgstr "" + +#: members/models.py:154 +msgid "In der Mailadresse fehlt die Domäne." +msgstr "" + +#: members/models.py:234 +msgid "VorsitzendeR" +msgstr "" + +#: members/models.py:235 +msgid "stv VorsitzendeR" +msgstr "" + +#: members/models.py:236 +msgid "2. stv VorsitzendeR" +msgstr "" + +#: members/models.py:237 +msgid "VerantwortlicheR" +msgstr "" + +#: members/models.py:238 +msgid "Mitglied" +msgstr "" + +#: members/models.py:239 +msgid "Ersatzmitglied" +msgstr "" + +#: posts/admin.py:27 +#, python-format +msgid "Das Agenda konnte nicht erstellt werden. Error: %s" +msgstr "" + +#: posts/admin.py:37 +#, python-format +msgid "Das Protokoll konnte nicht erstellt werden. Error: %s" +msgstr "" + +#: posts/admin.py:52 +#, python-format +msgid "Das Event %s wurde erfolgreich in eine FET Sitzung konvertiert." +msgstr "" + +#: posts/forms.py:50 posts/forms.py:101 tasks/forms.py:19 +msgid "Titel" +msgstr "" + +#: posts/forms.py:51 posts/forms.py:102 +msgid "Untertitel" +msgstr "" + +#: posts/forms.py:52 posts/forms.py:103 +msgid "Hintergrundbild" +msgstr "" + +#: posts/forms.py:53 posts/forms.py:104 +msgid "Text" +msgstr "" + +#: posts/forms.py:54 posts/forms.py:108 +msgid "Autor" +msgstr "" + +#: posts/forms.py:56 +msgid "Post anheften" +msgstr "" + +#: posts/forms.py:57 +msgid "Post verstecken" +msgstr "" + +#: posts/forms.py:62 posts/forms.py:115 posts/forms.py:153 +msgid "" +"Die Hashtags ohne '#' eintragen, und mit Komma kann man mehrere Tags anfügen." +msgstr "" + +#: posts/forms.py:64 +msgid "Verwendbare Formate: ..." +msgstr "" + +#: posts/forms.py:66 +msgid "Dieser Post soll an die Startseite als erster Post angeheftet werden." +msgstr "" + +#: posts/forms.py:69 +msgid "Dieser Post soll im News Feed nicht auftauchen, z.B. Impressum." +msgstr "" + +#: posts/forms.py:105 +msgid "Start des Events" +msgstr "" + +#: posts/forms.py:106 +msgid "Ende des Events" +msgstr "" + +#: posts/forms.py:107 +msgid "Ort des Events" +msgstr "" + +#: posts/forms.py:110 +msgid "Event anheften" +msgstr "" + +#: posts/forms.py:117 +msgid "Verwendbare Formate: " +msgstr "" + +#: posts/forms.py:119 +msgid "Dieses Event soll an die Startseite als erster Post angeheftet werden." +msgstr "" + +#: posts/forms.py:145 +msgid "Start der Sitzung" +msgstr "" + +#: posts/forms.py:146 +msgid "Ende der Sitzung" +msgstr "" + +#: posts/models.py:86 +msgid "News" +msgstr "" + +#: posts/models.py:86 +msgid "Event" +msgstr "" + +#: posts/models.py:86 +msgid "FetMeeting" +msgstr "" + +#: posts/models.py:258 +msgid "Das Ende des Events liegt vor dem Beginn." +msgstr "" + +#: posts/models.py:318 +msgid "Das Datum des Events fehlt." +msgstr "" + +#: posts/models.py:349 +msgid "Es existiert bereits eine Sitzung mit demselben Datum." +msgstr "" + +#: tasks/forms.py:20 +msgid "Aufgabenbereich" +msgstr "" + +#: tasks/forms.py:21 +msgid "Fälligkeit" +msgstr "" + +#: tasks/forms.py:22 +msgid "Abgeschlossen" +msgstr "" + +#: tasks/forms.py:23 +msgid "Datum der Fertigstellung" +msgstr "" + +#: tasks/forms.py:24 tasks/forms.py:52 +msgid "Zuweisen an" +msgstr "" + +#: tasks/forms.py:25 +msgid "Notizen" +msgstr "" + +#: tasks/forms.py:26 +msgid "Priorität" +msgstr "" + +#: tasks/forms.py:49 +msgid "Titel des Tasks" +msgstr "" + +#: tasks/forms.py:50 +msgid "Task-Gruppe" +msgstr "" + +#: tasks/forms.py:51 +msgid "Fälligkeitsdatum" +msgstr "" + +#: templates/admin/base.html:8 +msgid "Welcome," +msgstr "" + +#: templates/admin/base.html:18 +msgid "Documentation" +msgstr "" + +#: templates/admin/base.html:22 +msgid "Change password" +msgstr "" + +#: templates/admin/base.html:24 +msgid "Log out" +msgstr "" + +#: templates/admin/submit_line.html:5 +msgid "Close" +msgstr "" + +#: templates/documents/base.html:17 +msgid "profile" +msgstr "" + +#: templates/documents/base.html:18 +msgid "logout" +msgstr "" + +msgid "January" +msgstr "Jänner" + +msgid "jan" +msgstr "Jän" + +msgctxt "abbrev. month" +msgid "Jan." +msgstr "Jän." + +msgctxt "alt. month" +msgid "January" +msgstr "Jänner" From 3f927bcc75f3126530269846dcaf043df016fca9 Mon Sep 17 00:00:00 2001 From: andis Date: Mon, 18 Jan 2021 23:25:47 +0000 Subject: [PATCH 14/15] Layout css fix header --- fet2020/initdb | 4 ++-- fet2020/static/fet.css | 4 ++++ fet2020/templates/layout.html | 5 +++-- 3 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 fet2020/static/fet.css diff --git a/fet2020/initdb b/fet2020/initdb index 2f2aa251..d28f4ab0 100755 --- a/fet2020/initdb +++ b/fet2020/initdb @@ -1,3 +1,3 @@ #!/bin/sh -python manage.py makemigrations && python manage.py makemigrations posts members blackboard\ -&& python manage.py migrate +python3 manage.py makemigrations && python3 manage.py makemigrations posts members blackboard\ +&& python3 manage.py migrate diff --git a/fet2020/static/fet.css b/fet2020/static/fet.css new file mode 100644 index 00000000..22298c26 --- /dev/null +++ b/fet2020/static/fet.css @@ -0,0 +1,4 @@ +body { + min-height:100%; + position:relative; +} diff --git a/fet2020/templates/layout.html b/fet2020/templates/layout.html index 57f941b5..4e7da485 100644 --- a/fet2020/templates/layout.html +++ b/fet2020/templates/layout.html @@ -8,11 +8,12 @@ FET + {% block extraheader %} {% endblock %} - +