From 74ff9a719933dfa4b5356f0b1a9f06c86f5db5ac Mon Sep 17 00:00:00 2001 From: patrick Date: Mon, 1 Mar 2021 14:52:17 +0000 Subject: [PATCH 01/35] add file uploads to post --- fet2020/posts/admin.py | 20 ++++--- fet2020/posts/models.py | 86 +++++++++++-------------------- fet2020/posts/views.py | 6 ++- fet2020/templates/posts/show.html | 19 ++++++- 4 files changed, 64 insertions(+), 67 deletions(-) diff --git a/fet2020/posts/admin.py b/fet2020/posts/admin.py index 1a5b9f7f..d9431dc7 100644 --- a/fet2020/posts/admin.py +++ b/fet2020/posts/admin.py @@ -1,7 +1,7 @@ from django.contrib import admin, auth, messages from django.utils.translation import gettext_lazy as _ -from .models import Post, Event, News, FetMeeting +from .models import Post, Event, News, FetMeeting, FileUpload from .forms import PostForm, EventForm, NewsForm, FetMeetingForm from documents.api import createPadifNotExists @@ -58,6 +58,13 @@ def make_fetmeeting(self, request, queryset): make_fetmeeting.short_description = "In eine Fachschaftssitzung konvertieren" +class FileUploadInline(admin.TabularInline): + model = FileUpload + extra = 0 + verbose_name = "Dokument" + verbose_name_plural = "Do­ku­men­ten­samm­lung" + + class PostAdmin(admin.ModelAdmin): form = PostForm model = Post @@ -101,6 +108,12 @@ class PostAdmin(admin.ModelAdmin): ] +class NewsAdmin(PostAdmin): + form = NewsForm + model = News + inlines = (FileUploadInline,) + + class EventAdmin(PostAdmin): form = EventForm model = Event @@ -110,11 +123,6 @@ class EventAdmin(PostAdmin): actions = [make_fetmeeting] -class NewsAdmin(PostAdmin): - form = NewsForm - model = News - - class FetMeetingAdmin(EventAdmin): form = FetMeetingForm model = FetMeeting diff --git a/fet2020/posts/models.py b/fet2020/posts/models.py index 7c27fd63..596e8d74 100644 --- a/fet2020/posts/models.py +++ b/fet2020/posts/models.py @@ -28,17 +28,17 @@ def create_pad_for_post(slug, typ="agenda"): "Creates a Etherpad Pad and returns EtherpadKey" print("creatingpadforpost") try: - agenda_key = createPadifNotExists(slug + "-" + typ) + etherpad_key = createPadifNotExists(slug + "-" + typ) except URLError as error: request_logger.info( - """%s konnte von dem Slug '%s' nicht erstellt werden. - Error: %s""", + "%s konnte von dem Slug '%s' nicht erstellt werden. Error: %s", typ, slug, error, ) return None - return agenda_key + + return etherpad_key class Category(models.Model): @@ -59,30 +59,24 @@ class Category(models.Model): class Post(models.Model): - # id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + # legacy id is for the posts from the old website legacy_id = models.IntegerField(null=True, blank=True) - legacy_rubrik_id = models.IntegerField(null=True, blank=True) - # Titel des Posts + title = models.CharField(verbose_name="Titel", max_length=200) subtitle = models.CharField(max_length=500, null=True, blank=True) + tags = TaggableManager(blank=True) # Slug = Text Basierter url bestandteil zb Fetsitzung 22.1.2020 --> fetsitzung_22_1_2020 für Url slug = models.SlugField(unique=True, blank=True) - # Body Text Artikel Text soll später mit WYSIWG Editor bearbeitet werden - body = models.TextField(null=True, blank=True) - # Ein Haupt Bild für den Post - image = models.ImageField(null=True, blank=True) - # Wer hat das geschrieben - author = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True) - tags = TaggableManager(blank=True) - # Datum ab dem etwas öffentlich sein soll + body = models.TextField(null=True, blank=True) + image = models.ImageField(null=True, blank=True) + + author = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True) public_date = models.DateField( verbose_name="Veröffentlichung", null=True, blank=True, default=timezone.now ) - imported_from = models.CharField(max_length=200, null=True, blank=True) - __choices = [("N", _("News")), ("E", _("Event")), ("F", _("FetMeeting"))] post_type = models.CharField(max_length=1, choices=__choices, editable=True) @@ -92,14 +86,12 @@ class Post(models.Model): # post is hidden from newsfeed (e.g. about) is_hidden = models.BooleanField(verbose_name="UNSICHTBAR", default=False) - # Zusatz Info wenn ein Event gepostet wird - event_start = models.DateTimeField( - verbose_name="Event Start", null=True, blank=True - ) + # addional infos for events + event_start = models.DateTimeField(verbose_name="Event Start", null=True, blank=True) event_end = models.DateTimeField(verbose_name="Event Ende", null=True, blank=True) event_place = models.CharField(max_length=200, null=True, blank=True) - # Dokumente v.a. fuer Sitzungen + # protocol for fet meeting has_protocol = models.BooleanField(default=False) has_agenda = models.BooleanField(default=False) protocol_key = models.CharField(max_length=200, null=True, blank=True) @@ -109,6 +101,10 @@ class Post(models.Model): date_modified = models.DateTimeField(auto_now=True) date_created = models.DateTimeField(auto_now_add=True) + # useless (-_-) + legacy_rubrik_id = models.IntegerField(null=True, blank=True) + imported_from = models.CharField(max_length=200, null=True, blank=True) + # Managers objects = PostManager() articles = ArticleManager() @@ -228,9 +224,6 @@ class Post(models.Model): return image.url return "" - # def key(self): - # return self.slug or self.id - def find_an_image(self): "find an image via another post" # TODO: Explain why this image is selected on save of the image @@ -243,10 +236,6 @@ class Post(models.Model): if len(posts1) > 0: return posts1.get().image - # posts2=self.tags.similar_objects() - # for p in posts2: - # if p.image is not None: - # return p.image return None @property @@ -351,34 +340,6 @@ 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_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: @@ -406,3 +367,14 @@ class FetMeeting(Event): self.event_end = self.event_start + timedelta(hours=2) super().save(*args, **kwargs) + + +class FileUpload(models.Model): + title = models.CharField(verbose_name="Titel", max_length=200) + file_field = models.FileField(verbose_name="Dokument", upload_to="uploads/posts/files/") + post = models.ForeignKey(Post, on_delete=models.CASCADE) + + objects = models.Manager() + + def __str__(self): + return self.title diff --git a/fet2020/posts/views.py b/fet2020/posts/views.py index dd88b05d..108c506c 100644 --- a/fet2020/posts/views.py +++ b/fet2020/posts/views.py @@ -11,8 +11,7 @@ from documents.api import get_pad_link from documents.etherpadlib import add_ep_cookie from members.models import Member, JobMember - -from .models import Post, FetMeeting +from .models import Post, FetMeeting, FileUpload logger = logging.getLogger(__name__) @@ -74,6 +73,8 @@ def show(request, id=None): elif id != "" and id is not None: p = Post.objects.get(slug=(id)) + files = deque(FileUpload.objects.filter(post=p)) + post_author = Member.all_members.filter(username=p.author).first() author_image = None author = None @@ -112,6 +113,7 @@ def show(request, id=None): context = { "post": p, + "files": files, "author": author, "author_image": author_image, "next": get_next_dict(p), diff --git a/fet2020/templates/posts/show.html b/fet2020/templates/posts/show.html index 52c56c87..1da5a1ca 100644 --- a/fet2020/templates/posts/show.html +++ b/fet2020/templates/posts/show.html @@ -79,9 +79,9 @@
Nächster Artikel
-
{% if request.user.is_authenticated %} +
{% if post.has_agenda %} Agenda
@@ -101,10 +101,10 @@ Bearbeiten {% endif %} -
{% endif %} {% if post.event_start %} +
Start: {{ post.event_start|date:"d. F Y" }} {{ post.event_start|time:"H:i" }}
{% endif %} {% if post.event_end %} @@ -114,6 +114,21 @@ {% if post.event_start %} {% include 'posts/partials/_date_box.html' %} {% endif %} + + {% if files %} +
+ Dokumente: + + + + {% endif %} + +
+
From 6686ff8c159e07e8adf79ce5acd55fbc73201afa Mon Sep 17 00:00:00 2001 From: patrick Date: Wed, 3 Mar 2021 21:52:34 +0000 Subject: [PATCH 02/35] update css style --- fet2020/fet2020/settings.py | 6 +- fet2020/requirements.txt | 1 + fet2020/static/fet.css | 103 +++++++++++++++++-- fet2020/templates/home.html | 2 +- fet2020/templates/layout.html | 100 +++++++++--------- fet2020/templates/members/index.html | 56 +++++----- fet2020/templates/members/jobs_list.html | 2 - fet2020/templates/members/member.html | 10 +- fet2020/templates/members/member_layout.html | 87 ---------------- 9 files changed, 177 insertions(+), 190 deletions(-) delete mode 100644 fet2020/templates/members/member_layout.html diff --git a/fet2020/fet2020/settings.py b/fet2020/fet2020/settings.py index 8eed5b81..51b8481a 100644 --- a/fet2020/fet2020/settings.py +++ b/fet2020/fet2020/settings.py @@ -76,6 +76,7 @@ INSTALLED_APPS = [ "django_crontab", "django_filters", "django_static_jquery_ui", + "fontawesome-free", "posts.apps.PostsConfig", "members.apps.MembersConfig", "documents.apps.DocumentsConfig", @@ -183,7 +184,7 @@ LOCALE_PATHS = [os.path.join(BASE_DIR, "locale")] # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.0/howto/static-files/ -STATIC_URL = "/assets/" +STATIC_URL = "/static/" STATICFILES_DIRS = [os.path.join(BASE_DIR, "static")] STATIC_ROOT = "assets/" @@ -218,10 +219,9 @@ THUMBNAIL_ALIASES = { }, } ETHERPAD_HOST = env("ETHERPAD_HOST").strip() -if not ETHERPAD_HOST or ETHERPAD_HOST=="": +if not ETHERPAD_HOST or ETHERPAD_HOST == "": ETHERPAD_HOST = urljoin("https://" + env("HOST_NAME"), "etherpad/") - # ETHERPAD CLIENT if DEBUG: ETHERPAD_CLIENT = { diff --git a/fet2020/requirements.txt b/fet2020/requirements.txt index b00d74f9..81d3cdd2 100644 --- a/fet2020/requirements.txt +++ b/fet2020/requirements.txt @@ -14,3 +14,4 @@ etherpad-lite==0.5 ghostscript==0.6 ldap3==2.8.1 mysqlclient==2.0.1 +fontawesome-free==5.15.2 diff --git a/fet2020/static/fet.css b/fet2020/static/fet.css index a19eefb6..53c5fbf1 100644 --- a/fet2020/static/fet.css +++ b/fet2020/static/fet.css @@ -1,21 +1,102 @@ body { - min-height:100%; - position:relative; -} -img.logo { - height:40px; - width:40px; + min-height: 100%; + position: relative; } -div.footer { +img.logo { + height: 50px; + width: 50px; +} + +.title-bar { + background: None; +} + +a.header-link { + background: None; + color: black; + font-size: medium; + font-weight: bold; +} + +a.header-intern-link { + background: lightgrey; + color: black; + font-size: medium; + font-weight: bold; +} + +.header-intern-txt { + background: lightgrey; + color: black; + font-size: medium; +} + +.header-btn:hover { + background: None; +} +.header-btn:focus { + background: None; + color: black; +} + +.header-intern-btn:hover { + background: lightgrey; +} +.header-intern-btn:focus { + background: lightgrey; + color: black; +} + +footer { + height: 100%; + background-color: #444; +} + +.footer-grid-y { height: 100%; } -.footer a { - color: white; + +.footer-link { + color: white; } -.footer a i { - font-size:30px; + +.footer-link i { + font-size:30px; } + +.job-btn { + background-color: gray; + height: 70%; + display: flex; + align-items: center; + justify-content: center; +} +.job-btn:hover { + background-color: black; +} +.job-btn:focus { + background-color: gray; +} + +.memb-btn { + background-color: darkgray; + height: 70%; + display: flex; + align-items: center; + justify-content: center; +} +.memb-btn:hover { + background-color: black; +} +.memb-btn:focus { + background-color: darkgray; +} + +.active { + background-color: black; +} + a.thumbnail { width: 150px; height: 150px; diff --git a/fet2020/templates/home.html b/fet2020/templates/home.html index 951b2834..a7f10aa8 100644 --- a/fet2020/templates/home.html +++ b/fet2020/templates/home.html @@ -29,7 +29,7 @@
-

Neuigkeiten

+

Events

{% with post=featured_event %} {% include 'posts/partials/_article_row.html' %} diff --git a/fet2020/templates/layout.html b/fet2020/templates/layout.html index 26961578..47c1016d 100644 --- a/fet2020/templates/layout.html +++ b/fet2020/templates/layout.html @@ -2,49 +2,42 @@ - - - - - FET - - - - {% block extraheader %} - {% endblock %} - - - + + + + +FET + + + +{% block extraheader %} +{% endblock %} + + +
- + {% block content %} @@ -86,28 +78,38 @@ footer {
diff --git a/fet2020/templates/members/index.html b/fet2020/templates/members/index.html index e29c4803..b16d992c 100644 --- a/fet2020/templates/members/index.html +++ b/fet2020/templates/members/index.html @@ -1,45 +1,38 @@ -{% extends 'layout.html' %} -{% block content %} +{% extends "layout.html" %} {% load softhyphen_tags %} - - +{% block content %}
{% for job in pinned_job_groups %} - {% endfor %} - - {% for job in unpinned_job_groups %} - {% endfor %} - - + {% for job in unpinned_job_groups %} + + {% endfor %} + + + +
@@ -53,9 +46,8 @@ {% if member %} -
- {% include 'members/partials/_member_details.html' %} -
+ {% block members_content %} + {% endblock %} {% endif %} diff --git a/fet2020/templates/members/jobs_list.html b/fet2020/templates/members/jobs_list.html index a8e7adac..85c4cb82 100644 --- a/fet2020/templates/members/jobs_list.html +++ b/fet2020/templates/members/jobs_list.html @@ -1,4 +1,3 @@ - {% regroup job_members by job.name as all_jobmem_list %} {% for jobmem in all_jobmem_list %} @@ -6,7 +5,6 @@

{{jobmem.grouper}} #

- Aktuelle Mitglieder:
diff --git a/fet2020/templates/members/member.html b/fet2020/templates/members/member.html index 10c2a946..fea55124 100644 --- a/fet2020/templates/members/member.html +++ b/fet2020/templates/members/member.html @@ -1,14 +1,14 @@ -{% extends 'members/member_layout.html' %} +{% extends 'members/index.html' %} + {% block extraheader %} - {% endblock %} {% block members_content %} -
+
{% include 'members/partials/_member_details.html' %} -
-{% endblock %} \ No newline at end of file +
+{% endblock %} diff --git a/fet2020/templates/members/member_layout.html b/fet2020/templates/members/member_layout.html deleted file mode 100644 index 5ec9ac0e..00000000 --- a/fet2020/templates/members/member_layout.html +++ /dev/null @@ -1,87 +0,0 @@ -{% extends 'layout.html' %} - - -{% block content %} - -{% load softhyphen_tags %} - - - -
- -
- - {% for job in pinned_job_groups %} - - {% endfor %} - - {% for job in unpinned_job_groups %} - - {% endfor %} - - - - -
- - {% if description %} -
-
- {{ description|safe }} -
-
- {% endif %} - - {% block members_content %} - - {% endblock %} -
- -{% endblock %} - - From 19272b1b296b5110b0966af346ac74535926dbec Mon Sep 17 00:00:00 2001 From: patrick Date: Wed, 3 Mar 2021 21:53:47 +0000 Subject: [PATCH 03/35] fix static url --- fet2020/fet2020/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fet2020/fet2020/settings.py b/fet2020/fet2020/settings.py index 51b8481a..dd9a7e84 100644 --- a/fet2020/fet2020/settings.py +++ b/fet2020/fet2020/settings.py @@ -184,7 +184,7 @@ LOCALE_PATHS = [os.path.join(BASE_DIR, "locale")] # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.0/howto/static-files/ -STATIC_URL = "/static/" +STATIC_URL = "/assets/" STATICFILES_DIRS = [os.path.join(BASE_DIR, "static")] STATIC_ROOT = "assets/" From aab911c638672e808b6345acfe5f2eea03a48ead Mon Sep 17 00:00:00 2001 From: patrick Date: Thu, 4 Mar 2021 11:00:57 +0000 Subject: [PATCH 04/35] fix href --- fet2020/templates/layout.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fet2020/templates/layout.html b/fet2020/templates/layout.html index 47c1016d..713b7c62 100644 --- a/fet2020/templates/layout.html +++ b/fet2020/templates/layout.html @@ -9,7 +9,7 @@ FET - + {% block extraheader %} {% endblock %} From 5f95bdd514f0b9642066bdcd3ba90e5e891662f8 Mon Sep 17 00:00:00 2001 From: patrick Date: Sun, 7 Mar 2021 12:59:15 +0000 Subject: [PATCH 05/35] put manager methods in a separate file --- fet2020/members/managers.py | 64 ++++++++++++++++++++++ fet2020/members/models.py | 106 +++++------------------------------- fet2020/members/views.py | 14 ++--- 3 files changed, 85 insertions(+), 99 deletions(-) create mode 100644 fet2020/members/managers.py diff --git a/fet2020/members/managers.py b/fet2020/members/managers.py new file mode 100644 index 00000000..69968560 --- /dev/null +++ b/fet2020/members/managers.py @@ -0,0 +1,64 @@ +from django.db import models +from django.db.models import Q +from django.utils import timezone + +from datetime import timedelta + + +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") + ) + + def get_queryset(self): + date_today = timezone.now().date() + qs = super().get_queryset().order_by("member__firstname") + + return qs.filter( + Q(member__role="A") & (Q(job_end__gt=date_today) | Q(job_end__isnull=True)) + ) + + +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") + ) + + def get_queryset(self): + date_today = timezone.now().date() + qs = super().get_queryset().order_by("member__firstname") + + return qs.filter( + Q(member__role="P") + | (Q(job_end__lt=date_today + timedelta(days=1)) & Q(job_end__isnull=False)) + ) + + +class JobMemberManager(models.Manager): + def get_members(self, role): + qs = self.get_queryset().order_by("member__firstname") + + return qs.filter(Q(member__role=role)) + + +class JobGroupManager(models.Manager): + def get_pinned_jobgroups(self): + return self.get_queryset().filter(is_pinned=True) + + def get_unpinned_jobgroups(self): + return self.get_queryset().filter(is_pinned=False) + + +class MemberManager(models.Manager): + def get_queryset(self): + return super().get_queryset().order_by("firstname") diff --git a/fet2020/members/models.py b/fet2020/members/models.py index 0a1915f7..455706a8 100644 --- a/fet2020/members/models.py +++ b/fet2020/members/models.py @@ -1,109 +1,32 @@ +import logging + from django.contrib.auth.models import User from django.core.validators import RegexValidator, ValidationError from django.db import models -from django.db.models import Q -from django.utils import timezone from django.utils.text import slugify from django.utils.translation import gettext_lazy as _ -from datetime import timedelta from easy_thumbnails.fields import ThumbnailerImageField -import logging +from .managers import ( + ActiveJobMemberManager, + InactiveJobMemberManager, + JobMemberManager, + JobGroupManager, + MemberManager, +) logger = logging.getLogger(__name__) -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") - ) - - def get_queryset(self): - date_today = timezone.now().date() - qs = super().get_queryset().order_by("member__firstname") - - return qs.filter( - Q(member__role=Member.MemberRole.ACTIVE) - & (Q(job_end__gt=date_today) | Q(job_end__isnull=True)) - ) - - -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") - ) - - def get_queryset(self): - date_today = timezone.now().date() - qs = super().get_queryset().order_by("member__firstname") - - return qs.filter( - Q(member__role=Member.MemberRole.PENSION) - | (Q(job_end__lt=date_today + timedelta(days=1)) & Q(job_end__isnull=False)) - ) - - -class JobMemberManager(models.Manager): - def get_members(self, role): - qs = self.get_queryset().order_by("member__firstname") - - return qs.filter(Q(member__role=role)) - - -class JobGroupManager(models.Manager): - def get_active_jobgroup(self): - job_groups = list(self.get_queryset()) - - # delete job groups which don't have active members - for elem in job_groups: - if not JobMember.active_member.get_all_by_slug(slug=elem.slug): - job_groups.remove(elem) - - return job_groups - - def get_pinned_active_jobgroups(self): - job_groups = [] - - for elem in self.get_active_jobgroup(): - if elem.is_pinned: - job_groups.append(elem) - - return job_groups - - def get_unpinned_active_jobgroups(self): - job_groups = [] - - for elem in self.get_active_jobgroup(): - if not elem.is_pinned: - job_groups.append(elem) - - return job_groups - - -class MemberManager(models.Manager): - def get_queryset(self): - 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) + + # LDAP Username username = models.CharField("Benutzername", blank=True, max_length=128) + + # fet mail account mailaccount = models.CharField("Mailadresse", unique=True, max_length=128) class MemberRole(models.TextChoices): @@ -220,8 +143,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: - # self.job_group=JobGroup.objects.filter(slug=self.job) + super().save(*args, **kwargs) def __str__(self): diff --git a/fet2020/members/views.py b/fet2020/members/views.py index 2f3d5c63..fef04113 100644 --- a/fet2020/members/views.py +++ b/fet2020/members/views.py @@ -1,18 +1,18 @@ +import logging + from django.http import Http404 from django.shortcuts import render from collections import deque - -from .models import Member, JobMember, JobGroup, Job from posts.models import Post -import logging +from .models import Member, JobMember, JobGroup logger = logging.getLogger(__name__) def __remove_if_zero_active_mem(job_group): - for elem in job_group: + for elem in list(job_group): job_members = JobMember.active_member.get_all_by_slug(slug=elem.slug) if not job_members: job_group.remove(elem) @@ -21,8 +21,8 @@ def __remove_if_zero_active_mem(job_group): def __get_job_groups(): - pinned_job_groups = JobGroup.all_jobgroups.get_pinned_active_jobgroups() - unpinned_job_groups = JobGroup.all_jobgroups.get_unpinned_active_jobgroups() + pinned_job_groups = deque(JobGroup.all_jobgroups.get_pinned_jobgroups()) + unpinned_job_groups = deque(JobGroup.all_jobgroups.get_unpinned_jobgroups()) # remove job group if there is no longer an active member pinned_job_groups = __remove_if_zero_active_mem(pinned_job_groups) @@ -61,7 +61,7 @@ def jobs_view(request, slug=None): description = ( JobGroup.all_jobgroups.filter(slug=slug).values().first()["description"] ) - except Exception as e: + except Exception: logger.info("Wrong job '{}'".format(slug)) raise Http404("wrong job") From 1228b15c3182b2ebd2f19fadb3db07177c30fb6e Mon Sep 17 00:00:00 2001 From: patrick Date: Sun, 7 Mar 2021 12:59:50 +0000 Subject: [PATCH 06/35] fix creating slug --- fet2020/members/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fet2020/members/models.py b/fet2020/members/models.py index 455706a8..fdaaecee 100644 --- a/fet2020/members/models.py +++ b/fet2020/members/models.py @@ -116,7 +116,7 @@ class JobGroup(models.Model): def save(self, *args, **kwargs): if not self.slug: - self.slug = self.shortterm + self.slug = slugify(self.shortterm) super().save(*args, **kwargs) From bad0eab3f5f5d1a38e85067e8d9629ddd799ec27 Mon Sep 17 00:00:00 2001 From: patrick Date: Sun, 7 Mar 2021 13:05:45 +0000 Subject: [PATCH 07/35] add jobgroup to the list --- fet2020/members/admin.py | 1 + 1 file changed, 1 insertion(+) diff --git a/fet2020/members/admin.py b/fet2020/members/admin.py index c6a9c196..3e89f891 100644 --- a/fet2020/members/admin.py +++ b/fet2020/members/admin.py @@ -116,6 +116,7 @@ class JobAdmin(admin.ModelAdmin): list_display = [ "name", + "job_group", ] ordering = [ "name", From 6f8cde2a9b763c16a80a21cb3beda5b314fd501f Mon Sep 17 00:00:00 2001 From: patrick Date: Sun, 7 Mar 2021 23:53:01 +0000 Subject: [PATCH 08/35] add testcases --- fet2020/members/tests.py | 120 ++++++++++++++++++++++++++ fet2020/members/tests/files/peter.jpg | Bin 0 -> 7109 bytes 2 files changed, 120 insertions(+) create mode 100644 fet2020/members/tests/files/peter.jpg diff --git a/fet2020/members/tests.py b/fet2020/members/tests.py index e69de29b..831978bf 100644 --- a/fet2020/members/tests.py +++ b/fet2020/members/tests.py @@ -0,0 +1,120 @@ +import os + +from django.core.files.uploadedfile import SimpleUploadedFile +from django.test import TestCase + +from .models import Member, Job, JobGroup +from .forms import MemberForm, JobForm, JobGroupForm + + +class MemberTestCase(TestCase): + def setUp(self): + member = Member() + member.firstname = "Peter" + member.surname = "Traunmüller" + member.nickname = "Pet" + member.mailaccount = "peter@fet.at" + member.role = "A" + member.save() + + def test_member(self): + member = Member.objects.get(firstname="Peter") + self.assertEqual(member.__str__(), "Peter Traunmüller") + self.assertEqual(member.role, "A") + + +class MemberFormTestCase(TestCase): + def test_form(self): + image = SimpleUploadedFile( + name="peter.jpg", + content=open( + os.path.join(os.path.dirname(__file__), "tests/files/peter.jpg"), "rb" + ).read(), + content_type="image/jpeg", + ) + + form = MemberForm( + data={ + "firstname": "Peter", + "surname": "Traunmüller", + "nickname": "Pet", + "mailaccount": "peter@fet.at", + "role": "A", + }, + files={"image": image}, + ) + + self.assertTrue(form.is_valid()) + form.save() + + member = Member.objects.get(firstname="Peter") + self.assertEqual(member.__str__(), "Peter Traunmüller") + + def test_form_error_no_image(self): + form = MemberForm( + data={ + "firstname": "Peter", + "surname": "Traunmüller", + "nickname": "Pet", + "mailaccount": "peter@fet.at", + "role": "A", + }, + ) + + self.assertFalse(form.is_valid()) + self.assertEqual(form.errors.as_data()['__all__'][0].message, "Es fehlt das Profilbild.") + + +class JobGroupFormTestCase(TestCase): + def test_form(self): + form = JobGroupForm( + data={ + "name": "Studienkommission ET", + "shortterm": "Stuko ET", + }, + ) + + self.assertTrue(form.is_valid()) + form.save() + + job_group = JobGroup.objects.get(name="Studienkommission ET") + self.assertEqual(job_group.__str__(), "Studienkommission ET") + self.assertEqual(job_group.slug, "stuko-et") + + def test_form_error_slug(self): + form = JobGroupForm( + data={ + "name": "Studienkommission ET", + "shortterm": "Stuko ET", + }, + ) + + self.assertTrue(form.is_valid()) + form.save() + + job_group = JobGroup.objects.get(name="Studienkommission ET") + self.assertEqual(job_group.__str__(), "Studienkommission ET") + self.assertNotEqual(job_group.slug, "stuko et") + + +class JobFormTestCase(TestCase): + def test_form(self): + job_group = JobGroup() + job_group.name = "Studienkommission ET" + job_group.shortterm = "Stuko ET" + job_group.save() + + form = JobForm( + data={ + "name": "Studienkommission Master", + "shortterm": "Stuko Master", + "job_group": job_group, + }, + ) + + self.assertTrue(form.is_valid()) + form.save() + + job = Job.objects.get(name="Studienkommission Master") + self.assertEqual(job.__str__(), "Stuko Master") + self.assertEqual(job.slug, "stuko-master") diff --git a/fet2020/members/tests/files/peter.jpg b/fet2020/members/tests/files/peter.jpg new file mode 100644 index 0000000000000000000000000000000000000000..68b9b0e008b6019ea84808658e4b3ddb540e5466 GIT binary patch literal 7109 zcmb7IcQ{<%)}E@98NG*Lv`jE+5YbEYUPl{7Cn1QILJ*>b=q1sk%ZM;U?=?#F=z?eo zA|gV3lY8&?yWhXxI?uDu^Xzr@I(x0N-gm9DFJ~`T05C1}+v)%y5C8xYFTmv|fC>N# zhCm=-C~<&7p(LbKWTZs7LP<$Z1;0W|3%>$~(=oC$(b2Oqz~Ri?%&Z(7SFc{BV?yvE zICY0R3Pf0sw*o!EoSZH-HTQ0D-{7 zjs91FATWfuOQMn$2mk|#@?Ra`-^$B*02Of&2nL1`{X8aNo)snDAGa$4GRRyZ9bC*& zVbmZ1$^pd;paO=IkO5R6QD{Dpk>bDSNl_%-?SG9zqCl+n8RVk0_Pp(i(8qklN#J8H z)ML* z&jJv!Cb^aSD08EPVNq|FrUsQ*_90PF-YhMsq_1`>CsLM8S!P1Q7R@yW2+7H znMPVD6Z;Augn6fP=2qJ=5en~D%B=4D`pE^4ir1}%#0M3rHdm$k7Gq=SU~-Bo%4D7X zuQfR44^NNx(PGtGdlNX^dIIZW>$_CkroGH7%K`sf+Yq?roY0n*GAkBzfQ%_AG)?8_ zyox_MKi<8*QGdSp%OcR~sQzw8U-9I4*t6FzOTS!7jt>?PYXdXVVz6E=F$i})#I62$ z@6jvk@3XCTAwy2M@h_s&`*(MyH5|hi+3P>vZs7YgeRJre|5kI1F)mdvrCXw#Kbafk zuXxuYYuskNLRRf-n;#<%!Tb^ zQ0vQk<(A(Z0Af46D-G+*M?cojUS3nGH}eQ!)><{wMSrZarug+<)YjeOs^F(K83*T_ z&z`1Y1Kn9RcKRDFS6+QNiFC={J#6x~8#}Lh!=RjkVs~w#$Y*IVRX!~*{&3G<%lo?# zuZ}udwShpYa+{*elim~mYSMSB3kChz5fS;kH{z*`9&d^oI@*I&G3w?*@jN$f+ujE8 zSxlSb>K&aLb5`OqxMRA#QS99%8B7@wnM|Nm@e==B!Y@=3Eyeawb)0AA&CK_EMjtc7 zkqD$j*z7vLfMU0*6Oz2t& z8t4rM-R2O1zK~jC8X%zhM1%>$06;JZ0)+q}U}B0Bg@`IJ1P+DKqUpG}MV06gV&cjq zJiLkwl6Q%yBO`(l2nAgNa#~$8+WN zO4;ILf0)jk<2S5tlhC8=FJ-bB8RoC!?;p7Bt3NN|yV@a( z9e+W2aNkqP>G=2W){gJW{X{U@e}334$W}(+5sAKE-XSq-ENLpU7vI_>8W{@p2~+nV z-*v?PNCx$0L?=3$7~@YEl*5If9v!)6{ajV#6-|7fm$Z(S3CEGc`ZM!sLE*RMdP>Y-|_5;1}S7_?4_7gk1b$*P?Im_YD3nVS6Mjic(TUk zydBou%Q77j|ENAlQsKAW#}v|0>3NKa(VePpt0R`<=mOnIoq!Cod&=$ zdFw*y;cZ8gA8@^;?vEONb0?VM9IhH*N29xhN~fU8&+}+P9j7^kZ54K1<&*n!G4$&3{qL5=iE<$}w(>JT<2O z%tXYR0GwFrfFLLY^dG1Z!3KhZX}KXVE>SccLQDy2NUv=0FO(6>o&xX^fNh*{hV#U8 zCdBvhZv{3d(D~R`qvu8zjUiyQ(l`pPt!-nrw>K0vj)2i>JIE+S*{{ul2aa) zezxN^>^!8fxEQW+-?l+(j5Whe%92ftAF#@2)np-J;MNqXY5n)7qiHq5TO@)ah7Xt_nvTy*qeN{Igi1oSr`e|moLU!(E-VY!1h zA-sa>Lo~t*&v@996Ot(n1-7|6Or7S&=V%E0O#|Fj5h`H?2C~9Ra10}1L|TH8ht%U2 z@3I<-E@U`WV0+?O3Px87C8V3;wylQYOw+8gR*URP-;vp`@N&J+K=Sz(y{}kRMUfmPno*|LKAWcEd2PZ(TPOA z(0^$aNCE|e!O(xP>R(!g!-(G+LG(*e$)=!&L zs}p9SlMieO%38;jAM`31(3Cj5?L6k_771R;9vtk<9|^B=`kfv1erfDw zsNh{y%ZnTBdQMwsQbG4Sz|r~lSjA40Yeq3ZO40Dj!q2;nxt;IacK9-&vnDVfi?K_< z=<{FfhSqm}d}dvp18aAedf{EomCh?iQ=3x0FWZ_#pw++bU>`C%r*gem#kr;O+BX=> zemzy)k9RUIZ%5V58_YBz-UJwxBx!%nuX)@(cADQ~(;R2w#d>%xq%T1LNIP}1oVY#p zVJ}4B&ZoDBQ)*5JV?i`hjd|X%e;-J`1u#-1w9w;nh$EhJpC}ItRv^j1{ zzgz*mcYK;EEZ%WibkIl7a2-kV$#FwdOfc}i@N(q8ro66WH#E#Tr&6!)GTzBya<0Wq#02ubBlsDt?PX5Ji=TjVb4MovNx+UB*Hfxi)+>Q)LnlvcQ1-a?3M5U>*i%+qM5(& z)_vnPZTd~Eoi5Bd#ORGP-?0#DNsU8BMk*E@Jm&T$|lo~5EQ+>W^N`Si;9M~wsb2KCSno@rcn+L$GE$Se(?kt3Q2E{(dG5IUeEJzfY_!kr@86xsdkCelR@|&wYU6|b%OHJDfs<&&$R~&7h z##y32~f^~U8AvYk}hjv~j*kG+AhB;mS7`A1|hs~w>$^T06Uma$-i|cuec`Hl* zZ9((LM$QX_P?GjAmUE0D)LW+1F-E6;70C8LXY3;=JE11(W=tAVSzjDr+;I0f-E9(~ z5BMdlel+dL6Ava*t#%b#q*6?VZ{rYso==8SiYy>iqEs<$e2!iZ@W;S$sZCL-@@GQC zN4cJ6?m>kT$}&8yiJpL|XP3T(;unoJ-O#mst@nebE5DHW9U?YYbOtO`{00K~UdCJ_ zqx^jHBO&uF75s5Mzr!?CTXN)#xk#Z%QtY=9%bMr#izU~cz|g^`4_gqEJ=F();D+dZ zMBBTLZbp~pz;;8)qwO{EjQXf$%P)uDB|8_wa< zVWcSc*7uyu!#out?iPndHn|_3!@|2b6J2(77c}LCLg=DeS~w1V^~qced$|-f0(haw zk3x)7whA^nDd+qxbAOmZp90Z<&BidxAoU@j`r~rPpmp8u#EoYgU5W!GR57CpL|R3{ ziAMxPVkJ`RKZO>~4MQs#ayj^fi5leN#}EE#s9=9G^^a(&^nH#LqV`jy#5u_Zu*IP< zOL-r_xQSai3bbZ7g$u3TuptW>*BH{5uXJa$H5W2;V&RETj&zgP`MA_Vwcp)bP@wfP zYEGXhq>dNE3?=qovz3yeHD;cXBRdzSrX3U6-#u0@b5+?3GS0@LT>kX^&ZK#zAG$KL zyZc>Qd$;>RK}k!Ta8$t{|FWETP(0!ncOU-y?)T1(ce&+`h(Zc+%XAyB-)Ae>m0WH` z$VhIC$$~ygt}#STdoGj|JQI`0z~UIryzpA_irbN#E5u&EH<7%%P{Mgfq{*pRn5jc-Ivq`&rrB}Eq^k%Aqxz9cjW>+_~<%H zWh5V(kQPxzE@!uOEIMO56#rI9!jL@w!qva>EV786QjgsE%^wO>p{B=`d}>$g;QM8} zdl7Q5pZS}9J-c+P*CPx!Vrv#T{GpZDWV@H0y(-oGStxrWq%L zo~}mq%P%K*WH+m?Ca-IT*g-n&>Ta8x0B)kmLKJO_8t>W<#d1C!!{ZX_vMW^Rq-SbI zAb}ImIiNSzxJVIs|4C@XYqBL$-nY7OIqBcJ{h0h91W^Y@H15Z|KryC4dk@pYgCRxD zv#=?}dTG7Wv#qU1S&Y=S+Z2P7Vt+lL`?%u(W^TqoV z(JyycDdSp-K9w~V-n?(YfSKZZBd#WG8ajl|l@g_&GMzHDa~6H`byp%-Y~vWC!D%0D zkOrAZ7*~I9n9P=(Z7qSEbV()4XHsObuuvqvU3vEk3yGd!8todj{}bdr9<>e9nB-Wb z3_4+KZjMSRE#$c2YV?h16nh^D2Jt77eF~J%m^e>ccQDVI8Y;U`TRuW-nrjfg^j+YF z*iuFqt5JYDgw<722l_)q&>-lQBLH1@{G{`Tn|G`k@4K>jqe&EZjM0vT_u2PX9e--p>d*?#-uh%f zZBaSYV=CrLr_`eA+T}UT1sz)wAb>W~y)9q%ZbUiD7za+2xl-7QgXCweMQ+T9ZS=7> z`krC1Jruw>#|H7^j9BHiCLK8y3@kK2Ua5W9w3E!-6@3RB>1ez7_9}~Y zYAP8jyLR4RC$o zvGf9#F$;P~tyS_;->A^gq41@WyvnTV(`NuMbob81Q?)U^WC5xnDexr#VNyWylSC>S zszxx=%wpWW)Af5e=sLVzB=;OWCOO}l`#_~CSj;b)Ahyx-#Yqbh8UJu0BtFY~-{$?a zgVS4k!SDz|hfce5m@+2M==e0I@M~SI6|=<$fl}#qP^0u_W%;B7xwIl zk^f`Ob!6;H^S7@ghL-5fTd|tlj$`6bGrpN{s;>zf>(QCoQr<7m@yaQI_cs}&xoT*` zlu_}X2lwss+TDUu0V%bo8B*2^e>R*X+qar0k+gVbP+84I__|Ry-ox_}P*mDPDjs-j z@*=U9pin}g`@Z8yZ%@`ta#w7oFir4ngx9ImPxj(FmbQnIor~Vs`_ncbEy@%rN(|J? z{6~2^puR161i)h4TUyp>Jw!Df)YzqaDzNck@kphs_Vl}FU^<6|y*@VhTBEb<`XsH+=b?e|Yw+L0ku$Gv(>nOiV$X-V7Yi7}V zpSoo$_{M3U*y{}s)WYj3++I^jJh>hRjObRf3!Dz2GUmaEi|ry$PVc8jIeSkv6t=Z& z9%X0<^fb`S3fsOM_RPW@ATV3^4?%sr^^Iw4Nc*Yi=XF2Xc+4});-9`|8K=@|?$Ymg z=EI({Vk{g`<|?!=zJ@TD6WK8mhHx7$;XM^-%YUFJ7)+-!rA31wzXK!N>r!qK`+PH0 zZ95HJpk$oH7pP(a+plcl?t31}#bQu4JW}x`pjnH5rNH zO_i?zw*{{RXONntiFc5jTUHGg@TpRBS&)tzC4)HaI}tD5GTk_>=j<8?s^sJ~m^E45u9{ z_l0#Me`oKHJ=nNVGHC6;qP#7!B~0ghGrkQ6BUOxLG!J*6Q4fJNNd06)bPTr;VjcXz zHV8ord-p$!7Ci!qtg9LCQ&c_|fHtAC&bQ59bie;fJwOtHXopbK#OKchqdoAW;yjTI#smo|EVE7Y?~{NSRl zQYjkAtbK%#i648xW`4TZUbB57*9vZOY8G#xJfdstD|N#~>V>rH9(7mUn~}(|14V=V zLot228v?r!)|c;8>F3|BNhQLi4cmF#K4%6dS?M}dkf1|164$m-eDvDh?h)PxnRMjF OPEzykmL-oa=l%zpC$#SX literal 0 HcmV?d00001 From 7c190d04ba3ae37a5f563084798b94f19c57d38e Mon Sep 17 00:00:00 2001 From: patrick Date: Mon, 8 Mar 2021 12:04:00 +0000 Subject: [PATCH 09/35] change string output --- fet2020/members/models.py | 2 +- fet2020/members/tests.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fet2020/members/models.py b/fet2020/members/models.py index fdaaecee..89f0d245 100644 --- a/fet2020/members/models.py +++ b/fet2020/members/models.py @@ -147,7 +147,7 @@ class Job(models.Model): super().save(*args, **kwargs) def __str__(self): - return self.shortterm + return self.name class JobMember(models.Model): diff --git a/fet2020/members/tests.py b/fet2020/members/tests.py index 831978bf..fe6fc53d 100644 --- a/fet2020/members/tests.py +++ b/fet2020/members/tests.py @@ -116,5 +116,5 @@ class JobFormTestCase(TestCase): form.save() job = Job.objects.get(name="Studienkommission Master") - self.assertEqual(job.__str__(), "Stuko Master") + self.assertEqual(job.__str__(), "Studienkommission Master") self.assertEqual(job.slug, "stuko-master") From b48b67723cd8485eb444c24acef2e500731ead1e Mon Sep 17 00:00:00 2001 From: patrick Date: Tue, 9 Mar 2021 10:25:13 +0000 Subject: [PATCH 10/35] update social media button and post date. --- fet2020/static/fet.css | 56 +++++++++++++++++-- fet2020/templates/home.html | 29 +++++++++- fet2020/templates/layout.html | 25 ++++----- .../templates/posts/partials/_posts_hero.html | 6 +- 4 files changed, 95 insertions(+), 21 deletions(-) diff --git a/fet2020/static/fet.css b/fet2020/static/fet.css index 53c5fbf1..b200e7bd 100644 --- a/fet2020/static/fet.css +++ b/fet2020/static/fet.css @@ -9,21 +9,19 @@ img.logo { } .title-bar { - background: None; + background: transparent; } a.header-link { background: None; color: black; font-size: medium; - font-weight: bold; } a.header-intern-link { background: lightgrey; color: black; font-size: medium; - font-weight: bold; } .header-intern-txt { @@ -33,15 +31,17 @@ a.header-intern-link { } .header-btn:hover { - background: None; + background: darkgrey; + color: white; } .header-btn:focus { - background: None; + background: transparent; color: black; } .header-intern-btn:hover { - background: lightgrey; + background: darkgrey; + color: white; } .header-intern-btn:focus { background: lightgrey; @@ -106,3 +106,47 @@ a.thumbnail img { height: 150px; } + +.social-media-box { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: start; + -webkit-justify-content: flex-start; + -ms-flex-pack: start; + justify-content: flex-start; + -webkit-box-align: center; + -webkit-align-items: center; + -ms-flex-align: center; + align-items: center; + height: 71px; + background-color: grey; + color: white; + padding-top: 0rem !important; + padding-right: 0rem !important; + padding-bottom: 0rem !important; + padding-left: 1rem !important; + margin-top: 0rem !important; + margin-right: 0rem !important; + margin-bottom: 1rem !important; + margin-left: 0rem !important; } + .social-media-box .social-media-badge { + background-color: transparent; + width: 41px; + height: 41px; } + .social-media-box .social-media-badge .social-media-badge-symbol { + font-size:30px; } + .social-media-box .social-media-text { + margin-top: 0rem !important; + margin-right: 0rem !important; + margin-bottom: 0rem !important; + margin-left: 1rem !important; } + +.social-media-footer { + background-color: transparent; + color: white; + width: 40px; + height: 40px; } + .social-media-footer .social-media-footer-symbol { + font-size:30px; } diff --git a/fet2020/templates/home.html b/fet2020/templates/home.html index a7f10aa8..26b91ea2 100644 --- a/fet2020/templates/home.html +++ b/fet2020/templates/home.html @@ -12,7 +12,11 @@

{{ post.title|safe }}

@@ -55,6 +59,29 @@
+ + + + + + + + {% for post in events %} {% include 'posts/partials/_date_box.html' %} {% endfor %} diff --git a/fet2020/templates/layout.html b/fet2020/templates/layout.html index 713b7c62..2c5de674 100644 --- a/fet2020/templates/layout.html +++ b/fet2020/templates/layout.html @@ -85,21 +85,20 @@
- - - - - - - - - - - - + + + +
-
diff --git a/fet2020/templates/posts/partials/_posts_hero.html b/fet2020/templates/posts/partials/_posts_hero.html index 42916668..07f1a125 100644 --- a/fet2020/templates/posts/partials/_posts_hero.html +++ b/fet2020/templates/posts/partials/_posts_hero.html @@ -3,7 +3,11 @@

{{ post.title | safe }}

{{ post.subtitle|default_if_none:" " }}

- {{ post }} + {% if post.post_type != 'N' %} +

{{ post.event_start|date:"d. F Y" }}

+ {% else %} +

{{ post.public_date|date:"d. F Y" }}

+ {% endif %}
\ No newline at end of file From 665394517838eec1239d1165762855fe6b09e6ea Mon Sep 17 00:00:00 2001 From: patrick Date: Tue, 9 Mar 2021 10:25:41 +0000 Subject: [PATCH 11/35] update text shadow. --- fet2020/static/app.css | 4 ++-- fet2020/templates/posts/show.html | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/fet2020/static/app.css b/fet2020/static/app.css index f877b12f..407ef6e8 100644 --- a/fet2020/static/app.css +++ b/fet2020/static/app.css @@ -7793,7 +7793,7 @@ div.article-row-content > h6, .h6 { bottom: 15%; left: 5%; color: #fefefe; - text-shadow: 1px 1px 2px #0a0a0a; } + text-shadow: 1px 1px 2px #000, 0px 0px 5px #000, 0px 0px 25px #000; } @media print, screen and (min-width: 40em) { .news-hero .news-hero-text, .news-hero-large .news-hero-text { left: 10%; } } @@ -8344,7 +8344,7 @@ div.footer div.grid-x { bottom: 3.125rem; left: 0; right: 0; - text-shadow: 1px 1px 2px #0a0a0a; } + text-shadow: 1px 1px 2px #000, 0px 0px 5px #000, 0px 0px 25px #000; } @media print, screen and (max-width: 39.99875em) { .large-article-header-content { bottom: 1.25rem; } } diff --git a/fet2020/templates/posts/show.html b/fet2020/templates/posts/show.html index 1da5a1ca..4b18e972 100644 --- a/fet2020/templates/posts/show.html +++ b/fet2020/templates/posts/show.html @@ -26,9 +26,9 @@
- + {% if author_image and author %} From 1ae6ecddae75c271f9fe9a057ed5aa44f68ba04d Mon Sep 17 00:00:00 2001 From: patrick Date: Thu, 13 May 2021 18:24:25 +0000 Subject: [PATCH 34/35] catch wrong post id --- fet2020/posts/views.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/fet2020/posts/views.py b/fet2020/posts/views.py index 0c46473e..521ebf2f 100644 --- a/fet2020/posts/views.py +++ b/fet2020/posts/views.py @@ -3,7 +3,7 @@ import logging from collections import deque from django.conf import settings from django.contrib import messages -from django.http import HttpResponse, JsonResponse, HttpResponseServerError +from django.http import HttpResponse, JsonResponse, HttpResponseServerError, Http404 from django.shortcuts import render from django.template.loader import render_to_string from django.utils import timezone @@ -115,13 +115,18 @@ def tags(request, tag=""): def __get_post_object(id=None): - if id.isdigit() or id is int: - return Post.objects.get(id=int(id)) - elif id != "" and id is not None: - return Post.objects.get(slug=id) + post = None - return None + try: + if id.isdigit() or id is int: + post = Post.objects.get(id=int(id)) + elif id != "" and id is not None: + post = Post.objects.get(slug=id) + except Exception: + logger.info("Wrong id '{}'".format(id)) + raise Http404("wrong post id") + return post def show(request, id=None): p = __get_post_object(id) From 5b86fe9a186db1f478c28a5cd3a8fb3034ddf9d4 Mon Sep 17 00:00:00 2001 From: patrick Date: Sat, 15 May 2021 17:25:23 +0000 Subject: [PATCH 35/35] add 'number of hours' (Stundenanzahl) --- fet2020/blackboard/admin.py | 2 +- fet2020/blackboard/forms.py | 16 +++--- .../migrations/0002_auto_20210515_1916.py | 45 ++++++++++++++++ fet2020/blackboard/models.py | 54 +++++++++++-------- fet2020/blackboard/views.py | 2 +- .../partials/_show_job_posting.html | 18 ++++--- 6 files changed, 97 insertions(+), 40 deletions(-) create mode 100644 fet2020/blackboard/migrations/0002_auto_20210515_1916.py diff --git a/fet2020/blackboard/admin.py b/fet2020/blackboard/admin.py index 47b951dc..f7f8c3e5 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 = ["company_name", "job_name", "salary", "number_of_hours", "publish_date"] admin.site.register(JobPosting, JobPostingAdmin) diff --git a/fet2020/blackboard/forms.py b/fet2020/blackboard/forms.py index 94db3375..16ef17dc 100644 --- a/fet2020/blackboard/forms.py +++ b/fet2020/blackboard/forms.py @@ -7,17 +7,17 @@ from .models import JobPosting class JobPostingForm(forms.ModelForm): class Meta: model = JobPosting - fields = ["companyName", "jobName", "salary", "pdfLocation", "publishDate"] + fields = ["company_name", "job_name", "salary", "number_of_hours", "pdf_location", "publish_date"] labels = { - "companyName": _("Firmenname"), - "jobName": _("Berufsbezeichnung"), - "salary": _("Gehalt"), - "pdfLocation": _("Stellenausschreibung"), - "publishDate": _("Veröffentlichung"), + "company_name": _("Firmenname"), + "job_name": _("Berufsbezeichnung"), + "salary": _("monatliches Gehalt (brutto)/Stundenlohn"), + "pdf_location": _("Stellenausschreibung"), + "publish_date": _("Veröffentlichung"), } help_texts = { - "pdfLocation": _("Verwendbare Formate: PDF"), - "salary": _("in Euro angeben"), + "pdf_location": _("Verwendbare Formate: PDF"), + "salary": _("in Euro angeben; monatliches Gehalt bei >1h, sonst Stundenlohn."), } diff --git a/fet2020/blackboard/migrations/0002_auto_20210515_1916.py b/fet2020/blackboard/migrations/0002_auto_20210515_1916.py new file mode 100644 index 00000000..d5144b46 --- /dev/null +++ b/fet2020/blackboard/migrations/0002_auto_20210515_1916.py @@ -0,0 +1,45 @@ +# Generated by Django 3.1.5 on 2021-05-15 17:16 + +from django.db import migrations, models +import django.db.models.manager + + +class Migration(migrations.Migration): + + dependencies = [ + ('blackboard', '0001_initial'), + ] + + operations = [ + migrations.AlterModelManagers( + name='jobposting', + managers=[ + ('all_job_postings', django.db.models.manager.Manager()), + ], + ), + migrations.RenameField( + model_name='jobposting', + old_name='companyName', + new_name='company_name', + ), + migrations.RenameField( + model_name='jobposting', + old_name='jobName', + new_name='job_name', + ), + migrations.RenameField( + model_name='jobposting', + old_name='pdfLocation', + new_name='pdf_location', + ), + migrations.RenameField( + model_name='jobposting', + old_name='publishDate', + new_name='publish_date', + ), + migrations.AddField( + model_name='jobposting', + name='number_of_hours', + field=models.DecimalField(decimal_places=1, default=40, max_digits=3, verbose_name='Stundenanzahl'), + ), + ] diff --git a/fet2020/blackboard/models.py b/fet2020/blackboard/models.py index 808c0078..d921c914 100644 --- a/fet2020/blackboard/models.py +++ b/fet2020/blackboard/models.py @@ -1,3 +1,8 @@ +import ghostscript +import locale +import logging +import os + from django.conf import settings from django.core.validators import ValidationError from django.db import models @@ -5,40 +10,43 @@ from django.urls import reverse from django.utils import timezone from django.utils.translation import gettext_lazy as _ -import locale -import os from os.path import splitext, basename -import ghostscript - -import logging - 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) + company_name = models.CharField(verbose_name="Firmenname", max_length=128) + job_name = models.CharField(verbose_name="Berufsbezeichnung", max_length=128) + salary = models.PositiveSmallIntegerField( verbose_name="Gehalt", ) - pdfLocation = models.FileField( + number_of_hours = models.DecimalField( + default=40, + verbose_name="Stundenanzahl", + max_digits=3, + decimal_places=1, + ) + + pdf_location = models.FileField( verbose_name="Stellenausschreibung", upload_to="uploads/blackboard/pdf/" ) pdf_thumb_location = models.CharField(max_length=128) - publishDate = models.DateField( + + publish_date = models.DateField( verbose_name="Veröffentlichung", default=timezone.now ) # Managers - all_jobPosting = models.Manager() + all_job_postings = models.Manager() class Meta: verbose_name = "Stellenausschreibung" verbose_name_plural = "Stellenausschreibungen" def __str__(self): - return str(self.publishDate) + "_" + self.companyName + "_" + self.jobName + return str(self.publish_date) + "_" + self.company_name + "_" + self.job_name def get_absolute_url(self): return reverse("blackboard") @@ -61,6 +69,14 @@ class JobPosting(models.Model): with ghostscript.Ghostscript(*args) as g: ghostscript.cleanup() + def clean(self): + count = 0 + for i in self.pdf_location.name: + 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.")) + def save(self, *args, **kwargs): super().save(*args, **kwargs) @@ -70,24 +86,16 @@ class JobPosting(models.Model): pdf_thumb_location_full = ( settings.MEDIA_ROOT + "uploads/blackboard/thumb/" - + splitext(basename(self.pdfLocation.name))[0] + + splitext(basename(self.pdf_location.name))[0] + ".jpg" ) self.pdf_thumb_location = ( "/files/uploads/blackboard/thumb/" - + splitext(basename(self.pdfLocation.name))[0] + + splitext(basename(self.pdf_location.name))[0] + ".jpg" ) - self.pdf2jpeg(self.pdfLocation.path, pdf_thumb_location_full) + self.pdf2jpeg(self.pdf_location.path, pdf_thumb_location_full) logger.info("SavenThumbAs: " + self.pdf_thumb_location) super().save(*args, **kwargs) - - def clean(self): - count = 0 - for i in self.pdfLocation.name: - 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.")) diff --git a/fet2020/blackboard/views.py b/fet2020/blackboard/views.py index 4e308a64..7b970f6c 100644 --- a/fet2020/blackboard/views.py +++ b/fet2020/blackboard/views.py @@ -8,7 +8,7 @@ from .models import JobPosting 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) + job_postings = JobPosting.all_job_postings.filter(publish_date__gt=job_postings_cutoff) bb_info = CustomFlatPage.objects.filter(title__iexact="blackboard").first() bb_empty = CustomFlatPage.objects.filter(title__iexact="blackboard empty").first() diff --git a/fet2020/templates/blackboard/partials/_show_job_posting.html b/fet2020/templates/blackboard/partials/_show_job_posting.html index d107a4a9..56907289 100644 --- a/fet2020/templates/blackboard/partials/_show_job_posting.html +++ b/fet2020/templates/blackboard/partials/_show_job_posting.html @@ -1,15 +1,19 @@
-

{{job.companyName}}

-

{{job.jobName}}
- Mindestgehalt: {{job.salary}}€

+

{{job.company_name}}

+

{{job.job_name}}
+ {% if job.number_of_hours == 1 %} + Mindestgehalt: {{job.salary}}€ Stundenlohn

+ {% else %} + monatliches Mindestgehalt:
+ {{job.salary}}€ für {{job.number_of_hours}}h

+ {% endif %} {# only thumb and name of member #} - +
-

{{job.companyName}}

-

{{job.jobName}}
- Mindestgehalt: {{job.salary}}€

+

{{job.company_name}}

+

{{job.job_name}}