Merge remote-tracking branch 'origin'

This commit is contained in:
2020-07-16 16:10:40 +00:00
7 changed files with 279 additions and 96 deletions

View File

@@ -1,29 +1,12 @@
from django.contrib import admin
from .models import Member, Job, JobMember
from .forms import MyMemberForm, MyJobForm
from django.utils.translation import gettext as _
class ActiveJobFilter(admin.SimpleListFilter):
title = _('Aktiv im Job')
from .models import Member, Job, JobMember, JobGroup
from .forms import MyMemberForm, MyJobForm, MyJobGroupForm
parameter_name = 'is_active'
def lookups(self, request, model_admin):
return (
('yes', _('Yes')),
('no', _('No')),
)
def queryset(self, request, queryset):
if self.value() == 'yes':
return queryset.filter(job_end__isnull=True)
elif self.value() == 'no':
return queryset
class MemberRoleFilter(admin.SimpleListFilter):
title = _('Rolle')
parameter_name = 'role'
def lookups(self, request, model_admin):
@@ -39,19 +22,36 @@ class MemberRoleFilter(admin.SimpleListFilter):
return queryset.filter(role='P')
class JobMemberInline(admin.TabularInline):
list_filter = [ActiveJobFilter]
model = JobMember
extra = 0
#def get_queryset(self, request):
# qs = super().get_queryset(request)
# return qs.filter(job_end__isnull=False)
class JobOverviewInline(JobMemberInline):
verbose_name = "Tätigkeit"
verbose_name_plural = "Tätigkeitsübersicht"
class ActiveMemberInline(JobMemberInline):
verbose_name = "Mitglied"
verbose_name_plural = "Aktive Mitglieder Liste"
def get_queryset(self, request):
return JobMember.active_member.all()
class InactiveMemberInline(JobMemberInline):
verbose_name = "Mitglied"
verbose_name_plural = "Inaktive Mitglieder Liste"
def get_queryset(self, request):
return JobMember.inactive_member.all()
class JobInline(admin.TabularInline):
model = Job
extra = 0
class MyMemberAdmin(admin.ModelAdmin):
form = MyMemberForm
model = Member
list_display = ['nickname', 'firstname', 'surname', 'mailaccount', 'role']
inlines = (JobMemberInline,)
inlines = (JobOverviewInline,)
search_fields = ['firstname', 'surname','nickname','mailaccount']
list_filter = [MemberRoleFilter]
@@ -66,7 +66,7 @@ class MyJobAdmin(admin.ModelAdmin):
form = MyJobForm
model = Job
list_display = ['name']
inlines = (JobMemberInline,)
inlines = (ActiveMemberInline, InactiveMemberInline)
search_fields = ['name']
@@ -74,4 +74,18 @@ class MyJobAdmin(admin.ModelAdmin):
obj.author = request.user
super().save_model(request, obj, form, change)
admin.site.register(Job, MyJobAdmin)
admin.site.register(Job, MyJobAdmin)
class MyJobGroupAdmin(admin.ModelAdmin):
form = MyJobGroupForm
model = JobGroup
list_display = ['name']
inlines = (JobInline, )
search_fields = ['name']
def save_model(self, request, obj, form, change):
obj.author = request.user
super().save_model(request, obj, form, change)
admin.site.register(JobGroup, MyJobGroupAdmin)

View File

@@ -1,7 +1,7 @@
from django import forms
from ckeditor_uploader.widgets import CKEditorUploadingWidget
from .models import Member, Job
from .models import Member, Job, JobGroup
class MyMemberForm(forms.ModelForm):
@@ -25,6 +25,11 @@ class MyMemberForm(forms.ModelForm):
class MyJobForm(forms.ModelForm):
class Meta:
model = Job
fields = ['name', 'description', 'image']
fields = ['name', 'shortterm', 'slug', 'job_group', 'description', 'image']
widgets = {'description': CKEditorUploadingWidget(config_name='default')}
widgets = {'description': CKEditorUploadingWidget(config_name='default')}
class MyJobGroupForm(forms.ModelForm):
class Meta:
model = JobGroup
fields = ['name', 'shortterm', 'is_pinned']

View File

@@ -1,10 +1,15 @@
from django.core.validators import RegexValidator
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 rest_framework import serializers
import uuid
from datetime import timedelta
class MemberManager(models.Manager):
def get_queryset(self):
@@ -14,6 +19,36 @@ class PensionManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(role='P')
class ActiveMemberManager(models.Manager):
'''
return a list of active member, and members who are still working
'''
def get_queryset(self):
date_today = timezone.now().date()
return super().get_queryset().filter(
Q(member__role='A') &
(
Q(job_end__gt=date_today) |
Q(job_end__isnull=True)
)
)
class InactiveMemberManager(models.Manager):
'''
return a list of inactive member
'''
def get_queryset(self):
date_today = timezone.now().date()
return super().get_queryset().filter(
Q(member__role='P') |
(
Q(job_end__lt=date_today + timedelta(days=1)) &
Q(job_end__isnull=False)
)
)
class Member(models.Model):
firstname = models.CharField(max_length=128)
surname = models.CharField(max_length=128)
@@ -31,8 +66,10 @@ class Member(models.Model):
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_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)
@@ -41,17 +78,15 @@ class Member(models.Model):
date_modified = models.DateTimeField(auto_now=True)
date_created = models.DateTimeField(auto_now_add=True)
has_jobs = models.ManyToManyField(
'Job',
through='JobMember',
through_fields=('member', 'job')
)
# Managers
all_members = models.Manager()
active_member = MemberManager()
pension_member = PensionManager()
class Meta:
verbose_name = "Mitglied"
verbose_name_plural = "Mitglieder"
def __str__(self):
return self.firstname + " " + self.surname
@@ -68,24 +103,53 @@ class MemberSerializer(serializers.HyperlinkedModelSerializer):
'image'
]
class Job(models.Model):
class JobGroup(models.Model):
name = models.CharField(max_length=128)
description = models.TextField(null=True, blank=True)
image = models.ImageField(null=True, blank=True)
has_members = models.ManyToManyField(
'Member',
through='JobMember',
through_fields=('job', 'member')
)
shortterm = models.CharField(max_length=128)
is_pinned = models.BooleanField(default=False)
def __str__(self):
return self.name
class Job(models.Model):
name = models.CharField(max_length=128)
shortterm = models.CharField(max_length=128)
slug = models.SlugField(unique=True, null=True, blank=True)
description = models.TextField(null=True, blank=True)
image = models.ImageField(null=True, blank=True)
job_group = models.ForeignKey(
JobGroup,
on_delete=models.CASCADE,
verbose_name="Job Gruppe",
)
class Meta:
verbose_name = "Tätigkeit"
verbose_name_plural = "Tätigkeiten"
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.shortterm)
super().save(*args, **kwargs)
def __str__(self):
return self.shortterm
class JobMember(models.Model):
member = models.ForeignKey(Member, on_delete=models.CASCADE)
job = models.ForeignKey(Job, on_delete=models.CASCADE)
member = models.ForeignKey(
Member,
on_delete=models.CASCADE,
verbose_name="Mitglied",
)
job = models.ForeignKey(
Job,
on_delete=models.CASCADE,
verbose_name="Tätigkeit",
)
job_start = models.DateField('Job Start')
job_end = models.DateField('Job Ende', null=True, blank=True)
@@ -100,7 +164,6 @@ class JobMember(models.Model):
]
job_role = models.CharField(max_length=2, choices=__choices, default='M')
class Meta:
unique_together = [['member', 'job']]
jobmember = models.Manager()
jobmember = models.Manager()
active_member = ActiveMemberManager()
inactive_member = InactiveMemberManager()

View File

@@ -3,7 +3,7 @@ from django.http import HttpResponse
from collections import deque
from .models import Member, JobMember, MemberSerializer
from .models import Member, Job, JobMember, JobGroup, MemberSerializer
from rest_framework import viewsets
from rest_framework import permissions
@@ -12,12 +12,16 @@ from django_filters.rest_framework import DjangoFilterBackend
def index(request):
#members = deque(Member.all_members.all())
members = deque(Member.all_members.prefetch_related('has_jobs'))
#jobmember = deque(JobMember.jobmember.all())
members = deque(Member.all_members.all())
jobmembers = deque(JobMember.jobmember.all())
jobs = deque(Job.objects.all())
jobgroups = deque(JobGroup.objects.all())
context = {
"member": members
"members": members,
"jobmembers" : jobmembers,
"jobgroups" : jobgroups,
"jobs" : jobs,
}
return render(request, 'members/index.html', context)

View File

@@ -33,7 +33,7 @@ class ArticleManager(models.Manager):
regular fet meetings should not be contained in the news stream
"""
def get_queryset(self):
return super().get_queryset().filter(Q(news_type='E') | Q(news_type='N'))
return super().get_queryset().filter(Q(post_type='E') | Q(post_type='N'))
class NewsManager(models.Manager):
def get_queryset(self):
@@ -45,11 +45,11 @@ class EventManager(models.Manager):
regular fet meetings should not be contained in the news stream
"""
def get_queryset(self):
return super().get_queryset().filter(Q(is_event=True) & Q(news_type='E'))
return super().get_queryset().filter(Q(is_event=True) & Q(post_type='E'))
class FetMeetingManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(Q(news_type='F'))
return super().get_queryset().filter(Q(post_type='F'))
##########
@@ -100,7 +100,7 @@ class Post(models.Model):
('E', _('Event')),
('F', _('FetMeeting'))
]
news_type = models.CharField(max_length=1, choices=__choices, default='N', editable=False)
post_type = models.CharField(max_length=1, choices=__choices, editable=False)
is_event = models.BooleanField(default=False)
@@ -163,12 +163,12 @@ class Post(models.Model):
"save the post with some defaults"
if (self.id is None) and (not self.slug):
self.slug = slugify(self.public_date.date()) + "-" + slugify(self.title)
super().save(*args, **kwargs)
self.tags.set(*re.findall(r'\#([\d\w-]+)', str(self.subtitle)),
*re.findall(r'\#([\d\w-]+)', str(self.title)))
def __str__(self):
return "Post (%s, %s): %s " %(self.slug, self.public_date.strftime("%d.%m.%Y"), self.title)
@@ -199,7 +199,8 @@ class News(Post):
verbose_name_plural = "News"
def save(self, *args, **kwargs):
self.news_type = 'N'
if not self.post_type:
self.post_type = 'N'
super().save(*args, **kwargs)
@@ -211,8 +212,9 @@ class Event(Post):
def save(self, *args, **kwargs):
self.is_event = True
if self.news_type == 'N':
self.news_type = 'E'
if not self.post_type:
self.post_type = 'E'
super().save(*args, **kwargs)
@@ -240,8 +242,8 @@ class FetMeeting(Event):
# self.protocol_key
# self.agenda_key
if self.news_type == 'N':
self.news_type = 'F'
if not self.post_type:
self.post_type = 'F'
if not self.event_place:
self.event_place = "FET"

View File

@@ -1,43 +1,36 @@
from django.shortcuts import render
from django.http import HttpResponse, JsonResponse
from collections import deque
from django_filters.rest_framework import DjangoFilterBackend
from django.core.cache import cache
from django.utils.text import slugify
from django.utils import timezone
from .models import Post, PostSerializer
from taggit.models import Tag
from rest_framework import viewsets
from rest_framework import permissions
from django_filters.rest_framework import DjangoFilterBackend
from django.core.cache import cache
from .models import Post, PostSerializer
from django.utils.text import slugify
from django.utils import timezone
from collections import deque
def get_next_dict():
posts = Post.article_objects.order_by('-public_date').values('slug')
print(posts)
d = {}
print(d)
for k,v in enumerate(posts):
if k == len(posts) - 1:
break
d[v['slug']] = posts[k+1]['slug']
print(d)
return d
##################
# RENDERED VIEWS #
##################
# Create your views here.
def index(request):
posts = deque(Post.objects.order_by('-public_date').all())
f = lambda p: p.tags
f = lambda p: p.tags
t = map(f, posts)
return render(request, 'posts/index.html', {"posts": posts, "tags_list": t})
def tags(request,tag=""):
posts = deque(Post.objects.filter(tags__name=tag))
return render(request, 'posts/index.html', {"posts": posts, "tags_list": None})
def show(request,id=None):
if id.isdigit() or id is int:
p = Post.objects.get(id=int(id))
@@ -51,9 +44,15 @@ def show(request,id=None):
}
return render(request, 'posts/show.html', context)
# Ajax function that is called to calculate a slug from the title
def slug_calc(request):
###########
# HELPERS #
###########
def slug_calc(request):
"""
Ajax function that is called to calculate a slug from the title
"""
if request.method == "GET":
get = request.GET.copy()
title = get['title']
@@ -67,9 +66,11 @@ def slug_calc(request):
return HttpResponseServerError("Requires a title field.")
# Ajax function that returns autocomplete suggestions for a given tag input
def tag_complete(request):
def tag_complete(request):
"""
Ajax function that returns autocomplete suggestions for a given tag input
"""
if request.method == "GET":
get = request.GET.copy()
term = get['term']
@@ -81,9 +82,24 @@ def tag_complete(request):
tag_array.append(elem.name)
return JsonResponse(tag_array, safe=False)
return HttpResponseServerError("Requires a term field.")
def get_next_dict():
#TODO: Docstring
posts = Post.article_objects.order_by('-public_date').values('slug')
print(posts)
d = {}
print(d)
for k,v in enumerate(posts):
if k == len(posts) - 1:
break
d[v['slug']] = posts[k+1]['slug']
print(d)
return d
class PostViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
@@ -94,6 +110,6 @@ class PostViewSet(viewsets.ModelViewSet):
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')

View File

@@ -0,0 +1,79 @@
{% extends 'layout.html' %}
{% block content %}
<div class="grid-container">
<div class="grid-x">
<div class="medium-8 cell">
<h1>Members</h1>
{% for m in members %}
<div class="member-hero-text">
{% if m.image %}
<img src={{m.image.url}} style="width:150px;"/> </br>
{% else %}
{% endif %}
Name: {{m.firstname|safe}} {{m.surname}} </br>
Spitzname: {{m.nickname|safe}} </br>
Mailaccount: {{m.mailaccount|safe}} </br>
Beschreibung: {{m.description|safe}} </br>
Geburtstag: {{m.birthday}} </br>
Telefonnummer: {{m.phone}} </br>
Adresse: {{m.address}} </br>
</div>
</br>
<h2>Jobs</h2>
{% for jobm in jobmembers %}
{% if m == jobm.member %}
Job: {{ jobm.job.shortterm }} </br>
Job Start: {{ jobm.job_start }} </br>
Job Ende: {{ jobm.job_end }} </br>
{% else %}
{% endif %}
{% endfor %}
<hr/>
{% endfor %}
<h1>Job Groups</h1>
<h2>pinned JG</h2>
{% for jg in jobgroups %}
{% if jg.is_pinned %}
JobGroup: {{ jg.name }} </br>
{% for job in jobs %}
{% if job.job_group.name == jg.name %}
Job: {{ job.name }} </br>
{% for jobm in jobmembers %}
{% if job.name == jobm.job.name %}
Member Name: {{ jobm.member.nickname }} </br>
{% else %}
{% endif %}
{% endfor %}
{% else %}
{% endif %}
{% endfor %}
{% else %}
{% endif %}
{% endfor %}
<hr/>
<h2>unpinned JG</h2>
{% for jg in jobgroups %}
{% if jg.is_pinned %}
{% else %}
JobGroup: {{ jg.name }} </br>
{% for job in jobs %}
{% if job.job_group.name == jg.name %}
Job: {{ job.name }} </br>
{% for jobm in jobmembers %}
{% if job.name == jobm.job.name %}
Member Name: {{ jobm.member.nickname }} </br>
{% else %}
{% endif %}
{% endfor %}
{% else %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
</div>
</div>
</div>
{% endblock %}