multiple changes

This commit is contained in:
2020-08-26 05:37:49 +00:00
46 changed files with 32258 additions and 450 deletions

6
.gitignore vendored
View File

@@ -4,6 +4,8 @@
fet2020/files/*
fet2020/.env/*
*.sqlite3
fet2020/posts/migrations/*
fet2020/members/migrations/*
fet2020/*/migrations/*
.theia/*
.flake8
migrate
run

View File

@@ -1,32 +1,57 @@
from etherpad_lite import EtherpadLiteClient
from django.conf import settings
from datetime import datetime, timedelta
from django.utils.text import slugify
import urllib.parse
t=datetime.now() + timedelta(days=1)
SERVER_URL="http://etherpad2.2020.fet.at/etherpad/"
SERVER_URL="https://etherpad2.2020.fet.at/etherpad/"
with open("/srv/andis_test/etherpad_test2/etherpad-lite/APIKEY.txt","r") as f:
k=f.read()
epc=EtherpadLiteClient( base_params={'apikey':k,}, base_url="http://localhost:9003/api")
epc=EtherpadLiteClient( base_params={'apikey':k,}, base_url=urllib.parse.urljoin("http://localhost:9003","api"))
a=epc.createAuthorIfNotExistsFor(name="andis", authorMapper="andis")
g=epc.createGroupIfNotExistsFor(groupMapper="fet")
def get_ep_sessionid(request):
if request.user is None:
return "NoUser", None
server = SERVER_URL
author = epc.createAuthorIfNotExistsFor(name=str(request.user), authorMapper=str(request.user))['authorID']
expires = datetime.utcnow() + timedelta(
hours=3
)
try:
result = epc.createSession(
groupID=str(g['groupID']),
authorID=str(author),
validUntil=str(int(expires.timestamp()))
)
except Exception as e:
raise e
return None, None
return result['sessionID'],expires
def get_pad_link(padID):
return urllib.parse.urljoin(SERVER_URL,'p/'+g["groupID"] + '$' + slugify(padID))
def add_ep_to_response(request, response):
if request.user is None:
return response
padID=id
server = urlparse(SERVER_URL)
padLink = SERVER_URL + 'p/' + g["groupID"] + '$' + \
padID
server = SERVER_URL
#padLink = urllib.parse.urljoin(SERVER_URL , 'p/' + g["groupID"] + '$' + padID)
author = epc.createAuthorIfNotExistsFor(name=str(request.user), authorMapper=str(request.user))['authorID']
expires = datetime.datetime.utcnow() + datetime.timedelta(
expires = datetime.utcnow() + timedelta(
hours=3
)
try:
result = epclient.createSession(
groupID=str(group['groupID']),
groupID=str(g['groupID']),
authorID=str(author),
validUntil=str(int(expires.timestamp()))
)
@@ -38,11 +63,11 @@ def add_ep_to_response(request, response):
response.delete_cookie('sessionID', server.hostname)
response.delete_cookie('padSessionID')
response.set_cookie(
response=response.set_cookie(
'sessionID',
value=result['sessionID'],
expires=expires,
domain=server.hostname,
domain="https://etherpad2.2020.fet.at",
httponly=False
)

View File

@@ -1,23 +0,0 @@
from django.contrib import admin
from .models import Document
from django.urls import path
from django.contrib.auth import views as auth_views
from django.shortcuts import render
@admin.register(Document)
class DocumentModelAdmin(admin.ModelAdmin):
def my_view(self,request, extra_context=None):
return render(request,"admin/documents/preview.html")
def get_urls(self):
urls = super().get_urls()
select_list_url = [ path("<int:id>/preview", self.admin_site.admin_view(self.my_view),
name='preview'),
path("preview", self.admin_site.admin_view(self.my_view),
name='preview')
]
return select_list_url #+ urls
#admin.site.register(Document,DocumentModelAdmin)

View File

@@ -1,7 +0,0 @@
from django.apps import AppConfig
class DocumentsConfig(AppConfig):
name = 'documents'
from django.contrib.admin.apps import AdminConfig

View File

@@ -1,8 +0,0 @@
from django.db import models
# Create your models here.
class Document(models.Model):
key = models.CharField(max_length=200, primary_key=True)

View File

@@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

View File

@@ -1,6 +0,0 @@
import documents.views as views
from django.urls import path
urlpatterns=[
path("document/<id>", views.document)
]

View File

@@ -1,91 +0,0 @@
from django.shortcuts import render
# Create your views here.
from django.http import HttpResponseRedirect
from django.template import RequestContext
from django.contrib.auth.decorators import login_required
from django.utils.translation import ugettext_lazy as _
import urllib
from urllib.parse import urlparse
from .models import Document
from documents import epc
from documents import g as group
SERVER_URL="http://etherpad.2020.fet.at/"
import datetime
@login_required
def document(request, id=None):
"""Create and session and display an embedded pad
"""
# Initialize some needed values
#pad = Document.objects.get(key=id)
padID=id
padLink = SERVER_URL + 'p/' + group["groupID"] + '$' + \
padID
server = urlparse(SERVER_URL)
author = epc.createAuthorIfNotExistsFor(name=str(request.user), authorMapper=str(request.user))['authorID']
# Create the session on the etherpad-lite side
expires = datetime.datetime.utcnow() + datetime.timedelta(
hours=3
)
epclient = epc
try:
result = epclient.createSession(
groupID=str(group['groupID']),
authorID=str(author),
validUntil=str(int(expires.timestamp()))
)
except Exception as e:
response = render(
'etherpad-lite/pad.html',
{
'pad': padID,
'link': padLink,
'server': str(server),
'uname': str(request.user),
'error': 'etherpad-lite session request returned:' +
'"' + str(e) + '"'
}
)
return response
# Set up the response
response = render(request,
'documents/pad.html',
{
'pad': padID,
'link': padLink,
'server': str(server),
'uname': str(request.user),
'error': False
}#, context=(request)
)
# Delete the existing session first
if ('padSessionID' in request.COOKIES):
epclient.deleteSession(request.COOKIES['sessionID'])
response.delete_cookie('sessionID', server.hostname)
response.delete_cookie('padSessionID')
# Set the new session cookie for both the server and the local site
response.set_cookie(
'sessionID',
value=result['sessionID'],
expires=expires,
domain=server.hostname,
httponly=False
)
response.set_cookie(
'padSessionID',
value=result['sessionID'],
expires=expires,
httponly=False
)
return response

View File

@@ -1,15 +1,20 @@
from django.contrib.auth.models import User
# from django.contrib.auth.models import User
from django.contrib.auth.middleware import RemoteUserMiddleware
import django
#import logging
#logger=logging.getLogger("django.request")
# import django
# import logging
# logger=logging.getLogger("django.request")
class FETHeaderMiddleware(RemoteUserMiddleware):
header="Remote-User"
header = "Remote-User"
def process_request(self, request):
request.META[self.header]=request.META.get(self.header, request.headers.get(self.header,None))
request.META[self.header] = request.META.get(
self.header,
request.headers.get(self.header, None)
)
super().process_request(request)
if request.user.is_authenticated:
request.user.is_admin=True
request.user.is_superuser=True
request.user.is_staff=True
request.user.is_admin = True
request.user.is_superuser = True
request.user.is_staff = True

View File

@@ -12,10 +12,27 @@ https://docs.djangoproject.com/en/3.0/ref/settings/
import os
# Prints and logs are written to console
# TODO: Change before release
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console': {
'class': 'logging.StreamHandler',
},
},
'root': {
'handlers': ['console'],
'level': 'DEBUG',
},
}
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
SESSION_COOKIE_DOMAIN =".2020.fet.at"
SESSION_COOKIE_DOMAIN = ".2020.fet.at"
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/
@@ -28,15 +45,13 @@ DEBUG = True
ALLOWED_HOSTS = []
DATA_UPLOAD_MAX_MEMORY_SIZE = 1024*1024*1024
DATA_UPLOAD_MAX_MEMORY_SIZE = 1024 * 1024 * 1024
# Application definition
CKEDITOR_UPLOAD_PATH = 'upload'
INSTALLED_APPS = [
'posts.apps.PostsConfig',
'members.apps.MembersConfig',
'documents.apps.DocumentsConfig',
'django.contrib.admin',
'django.contrib.admindocs',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
@@ -45,10 +60,12 @@ INSTALLED_APPS = [
'taggit',
'ckeditor',
'ckeditor_uploader',
'easy_thumbnails',
'rest_framework',
'django_filters',
'django_static_jquery_ui',
'django.contrib.admindocs'
'posts.apps.PostsConfig',
'members.apps.MembersConfig',
]
MIDDLEWARE = [
@@ -67,7 +84,10 @@ ROOT_URLCONF = 'fet2020.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates'),os.path.join(BASE_DIR, 'templates_design1')],
'DIRS': [
os.path.join(BASE_DIR, 'templates'),
os.path.join(BASE_DIR, 'templates_design1')
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
@@ -140,10 +160,8 @@ STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static_design1"),
]
MEDIA_ROOT=os.path.join(BASE_DIR, 'files/')
MEDIA_URL='/files/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'files/')
MEDIA_URL = '/files/'
TAGGIT_FORCE_LOWERCASE = True
@@ -162,5 +180,10 @@ CKEDITOR_CONFIGS = {
},
],
}
}
THUMBNAIL_ALIASES = {
'': {
'avatar': {'size': (50, 50), 'crop': True},
'thumb': {'size': (150, 150), 'crop': True},
},
}

View File

@@ -28,12 +28,11 @@ router.register(r'members', MemberViewSet)
urlpatterns = [
path('posts/', include('posts.urls')),
path('documents/', include('documents.urls')),
path('admin/doc/', include('django.contrib.admindocs.urls')),
path('admin/', admin.site.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')),
]+static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
path('members/', include('members.urls'), name='members'),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

View File

@@ -1,22 +1,30 @@
from django.shortcuts import render
from django.http import HttpResponse
# from django.http import HttpResponse
from collections import deque
from posts.models import Post
from posts.models import Post, FetMeeting, Event
from django.utils import timezone
from django.db.models import Q
def index(request):
posts=deque(Post.article_objects.all())
l=len(posts)
posts = deque(Post.article_objects.all())
date_today = timezone.now().date()
def get_tags(lst):
for p in lst:
for t in list(p.tags.names()):
yield "#"+ t
yield "#" + t
t=set( t for t in get_tags(posts))
if l>=1:
featured_post=posts.popleft()
t = set(t for t in get_tags(posts))
if len(posts) >= 1:
featured_post = posts.popleft()
else:
featured_post=0
featured_post = 0
return render(request, 'home.html',{'posts':posts, 'featured_post':featured_post, "tags_list": ", ".join(t)})
context = {
'posts': posts,
'events': Post.objects.filter(is_event=True).filter(Q(event_start__gt=date_today)).order_by('-public_date').all(),
'featured_post': featured_post,
'featured_post2': FetMeeting.objects.first(),
'tags_list': ", ".join(t)
}
return render(request, 'home.html', context)

View File

@@ -16,52 +16,58 @@ class MemberRoleFilter(admin.SimpleListFilter):
)
def queryset(self, request, queryset):
if self.value() == 'A':
return queryset.filter(role='A')
elif self.value() == 'P':
return queryset.filter(role='P')
if self.value() in Member.MemberRole:
return queryset.filter(role=self.value())
class JobMemberInline(admin.TabularInline):
model = JobMember
extra = 0
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()
return JobMember.active_member.get_all()
class InactiveMemberInline(JobMemberInline):
verbose_name = "Mitglied"
verbose_name_plural = "Inaktive Mitglieder Liste"
def get_queryset(self, request):
return JobMember.inactive_member.all()
return JobMember.inactive_member.get_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 = (JobOverviewInline,)
search_fields = ['firstname', 'surname','nickname','mailaccount']
search_fields = ['firstname', 'surname', 'nickname', 'mailaccount']
list_filter = [MemberRoleFilter]
def save_model(self, request, obj, form, change):
obj.author = request.user
super().save_model(request, obj, form, change)
admin.site.register(Member, MyMemberAdmin)
class MyJobAdmin(admin.ModelAdmin):
form = MyJobForm
model = Job
@@ -74,8 +80,10 @@ class MyJobAdmin(admin.ModelAdmin):
obj.author = request.user
super().save_model(request, obj, form, change)
admin.site.register(Job, MyJobAdmin)
class MyJobGroupAdmin(admin.ModelAdmin):
form = MyJobGroupForm
model = JobGroup
@@ -88,4 +96,5 @@ class MyJobGroupAdmin(admin.ModelAdmin):
obj.author = request.user
super().save_model(request, obj, form, change)
admin.site.register(JobGroup, MyJobGroupAdmin)
admin.site.register(JobGroup, MyJobGroupAdmin)

View File

@@ -20,16 +20,29 @@ class MyMemberForm(forms.ModelForm):
'address'
]
widgets = {'description': CKEditorUploadingWidget(config_name='default')}
widgets = {
'description': CKEditorUploadingWidget(config_name='default')
}
class MyJobForm(forms.ModelForm):
class Meta:
model = Job
fields = ['name', 'shortterm', 'slug', 'job_group', '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']
fields = ['name', 'shortterm', 'slug', 'is_pinned']

View File

@@ -4,50 +4,79 @@ 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
from rest_framework import serializers
class MemberManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(role='A')
class MemberQuerySet(models.QuerySet):
def get_members(self):
date_today = timezone.now().date()
return self.filter(
Q(member__role=Member.MemberRole.ACTIVE)
& (Q(job_end__gt=date_today) | Q(job_end__isnull=True))
)
def get_inactive(self):
date_today = timezone.now().date()
return self.filter(
Q(member__role=Member.MemberRole.PENSION)
| (Q(job_end__lt=date_today + timedelta(days=1)) & Q(job_end__isnull=False))
)
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()
def get_members_of_job(self, job_names):
tmp_list = []
for job_name in job_names:
tmp_list.append(self.get_queryset().get_members().filter(Q(job__name=job_name)))
return tmp_list
def get_all(self):
return self.get_queryset().get_members()
def get_queryset(self):
return MemberQuerySet(self.model, using=self._db)
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()
def get_members_of_job(self, job_names):
tmp_list = []
for job_name in job_names:
tmp_list.append(self.get_queryset().get_inactive().filter(Q(job__name=job_name)))
return tmp_list
def get_all(self):
return self.get_queryset().get_inactive()
def get_queryset(self):
return MemberQuerySet(self.model, using=self._db)
class MemberManager(models.Manager):
def get_members(self, role):
return self.get_queryset().filter(Q(member__role=role))
def get_all(self):
return self.get_queryset()
class JobManager(models.Manager):
def get_job_names(self, slug):
tmp_list = []
for i in self.get_queryset().filter(Q(job__job_group__slug=slug)):
if i.job.name not in tmp_list:
tmp_list.append(i.job.name)
return tmp_list
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)
@@ -55,20 +84,19 @@ class Member(models.Model):
nickname = models.CharField(max_length=128)
mailaccount = models.CharField(max_length=128)
__choices = [
('A', _('Active')),
('P', _('Pension'))
]
role = models.CharField(max_length=1, choices= __choices, default='A')
class MemberRole(models.TextChoices):
ACTIVE = 'A', _('Active')
PENSION = 'P', _('Pension')
role = models.CharField(max_length=1, choices=MemberRole.choices, default=MemberRole.ACTIVE)
description = models.TextField(null=True, blank=True)
image = models.ImageField(null=True, blank=True)
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)
@@ -80,8 +108,6 @@ class Member(models.Model):
# Managers
all_members = models.Manager()
active_member = MemberManager()
pension_member = PensionManager()
class Meta:
verbose_name = "Mitglied"
@@ -90,6 +116,7 @@ class Member(models.Model):
def __str__(self):
return self.firstname + " " + self.surname
class MemberSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Member
@@ -100,17 +127,22 @@ class MemberSerializer(serializers.HyperlinkedModelSerializer):
'mailaccount',
'role',
'description',
'image'
'image',
]
class JobGroup(models.Model):
name = models.CharField(max_length=128)
shortterm = models.CharField(max_length=128)
slug = models.SlugField(unique=True, null=True, blank=True)
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)
@@ -139,6 +171,7 @@ class Job(models.Model):
def __str__(self):
return self.shortterm
class JobMember(models.Model):
member = models.ForeignKey(
Member,
@@ -154,16 +187,18 @@ class JobMember(models.Model):
job_start = models.DateField('Job Start')
job_end = models.DateField('Job Ende', null=True, blank=True)
__choices = [
('1V', _('VorsitzendeR')),
('2V', _('stv VorsitzendeR')),
('3V', _('2. stv VorsitzendeR')),
('M', _('Mitglied')),
('E', _('Ersatzmitglied')),
('V', _('VerantwortlicheR'))
]
job_role = models.CharField(max_length=2, choices=__choices, default='M')
class JobRole(models.TextChoices):
PRESIDENT = '1V', _('VorsitzendeR')
VICE_PRESIDENT = '2V', _('stv VorsitzendeR')
SECOND_VICE_PRESIDENT = '3V', _('2. stv VorsitzendeR')
MEMBER = 'M', _('Mitglied')
SUBSTITUTE_MEMBER = 'E', _('Ersatzmitglied')
PERSON_RESPONSIBLE = 'V', _('VerantwortlicheR')
jobmember = models.Manager()
job_role = models.CharField(max_length=2, choices=JobRole.choices, default=JobRole.MEMBER)
members = MemberManager()
active_member = ActiveMemberManager()
inactive_member = InactiveMemberManager()
inactive_member = InactiveMemberManager()
jobs = JobManager()

View File

@@ -1,3 +1,3 @@
from django.test import TestCase
# from django.test import TestCase
# Create your tests here.

View File

@@ -4,5 +4,7 @@ from . import views
urlpatterns = [
path('', views.index, name='members.index'),
]
path('', views.index, name='members'),
path('<str:filter>', views.index),
path('jobs/<str:slug>', views.index),
]

View File

@@ -1,31 +1,65 @@
from django.shortcuts import render
from django.http import HttpResponse
# from django.http import HttpResponse
from collections import deque
from .models import Member, Job, JobMember, JobGroup, MemberSerializer
from .models import Member, JobMember, JobGroup, MemberSerializer
from rest_framework import viewsets
from rest_framework import permissions
from django_filters.rest_framework import DjangoFilterBackend
# from django_filters.rest_framework import DjangoFilterBackend
def index(request):
#members = deque(Member.all_members.all())
members = deque(Member.all_members.all())
jobmembers = deque(JobMember.jobmember.all())
jobs = deque(Job.objects.all())
jobgroups = deque(JobGroup.objects.all())
def index(request, slug=None, filter=None):
job_group = deque(JobGroup.objects.all())
job_list = []
members = None
if slug is not None:
job_names = JobMember.jobs.get_job_names(slug=slug)
active_members = JobMember.active_member.get_members_of_job(job_names=job_names)
inactive_members = JobMember.inactive_member.get_members_of_job(job_names=job_names)
for idx, item in enumerate(job_names):
job_list.append((job_names[idx], active_members[idx], inactive_members[idx]))
else:
if filter is None:
members = deque(Member.all_members.all())
elif filter in Member.MemberRole:
members = deque(Member.all_members.filter(role=filter))
else:
members = None
context = {
"job_group": job_group,
"job_list": job_list,
"members": members,
"jobmembers" : jobmembers,
"jobgroups" : jobgroups,
"jobs" : jobs,
}
return render(request, 'members/index.html', context)
<<<<<<< HEAD
def show_job(request, slug=None):
job=Job.objects.get(slug=slug)
return render(request, 'members/show_job.html', {"job": job})
def show_member(request, slug=None):
member=Member.objects.get()
return render(request, 'members/show_member.html', {"member": member})
def list(request, filter=None):
"""
View for a list of members filtered or not
"""
if filter is None:
members = deque(Member.all_members.all())
if filter in Member.role_choices:
members=deque(Member.all_members.filter(role=filter).all())
return render(request, 'members/list.html',{"members": members})
=======
>>>>>>> origin/master
class MemberViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
@@ -34,9 +68,9 @@ class MemberViewSet(viewsets.ModelViewSet):
serializer_class = MemberSerializer
permission_classes = [permissions.IsAuthenticated]
#filter_backends = [DjangoFilterBackend]
#filterset_fields = ['legacy_id', 'slug','legacy_rubrik_id']
lookup_field='name'
# filter_backends = [DjangoFilterBackend]
# filterset_fields = ['legacy_id', 'slug','legacy_rubrik_id']
lookup_field = 'name'
def pre_save(self, obj):
obj.image = self.request.FILES.get('image')
obj.image = self.request.FILES.get('image')

View File

@@ -1,5 +1,5 @@
import django.contrib.auth.admin
import django.contrib.auth.models
# import django.contrib.auth.admin
# import django.contrib.auth.models
import taggit.admin
from django.contrib import admin, auth
@@ -11,6 +11,9 @@ admin.site.unregister(auth.models.User)
admin.site.unregister(auth.models.Group)
admin.site.unregister(taggit.models.Tag)
def make_fetmeeting(modeladmin, request, queryset):
queryset.update(post_type ='F')
make_fetmeeting.short_description = "In eine Fachschaftssitzung konvertieren"
class MyPostAdmin(admin.ModelAdmin):
form = MyPostForm
@@ -33,21 +36,27 @@ class MyPostAdmin(admin.ModelAdmin):
"jquery-ui/jquery-ui.min.js",
]
class MyEventAdmin(MyPostAdmin):
form = MyEventForm
model = Event
list_display = ['title', 'subtitle', 'slug', 'event_start', 'public_date']
actions=[make_fetmeeting]
admin.site.register(Event, MyEventAdmin)
class MyNewsAdmin(MyPostAdmin):
form = MyNewsForm
model = News
admin.site.register(News, MyNewsAdmin)
class MyFetMeetingAdmin(MyEventAdmin):
form = MyFetMeetingForm
model = FetMeeting
admin.site.register(FetMeeting, MyFetMeetingAdmin)
admin.site.register(FetMeeting, MyFetMeetingAdmin)

View File

@@ -1,4 +1,4 @@
from ckeditor_uploader.widgets import CKEditorUploadingWidget
from ckeditor_uploader.widgets import CKEditorUploadingWidget
from django import forms
from .models import Post, Event, News, FetMeeting
@@ -8,49 +8,52 @@ class MyPostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'subtitle', 'tags', 'image', 'body', 'slug', 'author']
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
)
class MyNewsForm(MyPostForm):
class Meta:
model = News
fields = ['title', 'subtitle', 'tags', 'image', 'body', 'slug', 'author']
widgets = {'body': CKEditorUploadingWidget(config_name='default')}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) # to get the self.fields set
super().__init__(*args, **kwargs) # to get the self.fields set
class MyEventForm(MyPostForm):
class Meta:
model = Event
fields = ['title', 'subtitle', 'tags', 'image', 'body',
'event_start', 'event_end', 'event_place', 'slug', 'author']
widgets = {'body': CKEditorUploadingWidget(config_name='default')}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) # to get the self.fields set
super().__init__(*args, **kwargs) # to get the self.fields set
self.fields['event_start'].required = True
self.fields['event_end'].required = True
if 'event_place' in self.fields:
self.fields['event_place'].required = True
class MyFetMeetingForm(MyEventForm):
class Meta:
model = FetMeeting
fields = ['event_start', 'event_end', 'tags']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) # to get the self.fields set
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_end'].required = False

View File

@@ -3,14 +3,14 @@ from django.db import models
from django.db.models import Q
from django.urls import reverse
from django.utils import timezone
from django.utils.text import slugify
from django.utils.text import slugify
from django.utils.translation import gettext_lazy as _
from taggit.managers import TaggableManager
#from ckeditor_uploader import RichTextUploadingField
import uuid
import re
# from ckeditor_uploader import RichTextUploadingField
# import uuid
import re
from rest_framework import serializers
from datetime import timedelta
@@ -26,26 +26,30 @@ logger = logging.getLogger('posts')
class PostManager(models.Manager):
def get_queryset(self):
return super().get_queryset()
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'))
return super().get_queryset().filter(Q(post_type='E') | Q(post_type='N')).order_by('-public_date')
class NewsManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(~Q(is_event=True))
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(Q(is_event=True) & Q(post_type='E'))
return super().get_queryset().filter(Q(is_event=True) & ~Q(post_type='F')).order_by('-public_date')
class FetMeetingManager(models.Manager):
def get_queryset(self):
@@ -62,18 +66,19 @@ class Category(models.Model):
subtitle = models.CharField(max_length=500, null=True, blank=True)
# Slug = Text Basierter url bestandteil zb Fetsitzung 22.1.2020 --> fetsitzung_22_1_2020 für Url
slug = models.SlugField(unique=True,null=True,blank=True)
slug = models.SlugField(unique=True, null=True, blank=True)
# Ein Haupt Bild für den Post
image = models.ImageField(null=True, blank=True)
tags = TaggableManager(blank=True)
class Meta:
verbose_name = "Category"
verbose_name_plural = "Categories"
class Post(models.Model):
#id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
# id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
legacy_id = models.IntegerField(null=True)
legacy_rubrik_id = models.IntegerField(null=True)
# Titel des Posts
@@ -88,11 +93,11 @@ class Post(models.Model):
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
public_date = models.DateField('date published', null=True, blank=True, default=timezone.now)
imported_from = models.CharField(max_length=200, null=True, blank=True)
__choices = [
@@ -118,11 +123,11 @@ class Post(models.Model):
# TimeStamps
date_modified = models.DateTimeField(auto_now=True)
date_created = models.DateTimeField(auto_now_add=True)
# Managers
objects = PostManager()
article_objects = ArticleManager()
def get_tags(self):
"""Returns assigned tags as a comma seperated list."""
return ",".join(self.tags.names())
@@ -132,7 +137,7 @@ class Post(models.Model):
if self.image:
return self.image.url
else:
image=self.find_an_image()
image = self.find_an_image()
if image:
return image.url
else:
@@ -145,16 +150,17 @@ class Post(models.Model):
"find an image via another post"
# TODO: Explain why this image is selected on save of the image
# Query all posts that have a slug that equals one of the tags
posts1 = Post.objects.filter(slug__in=self.tags.names()).filter(image__isnull=False)[0:1].all()
posts1 = Post.objects.filter(
slug__in=self.tags.names()).filter(image__isnull=False)[0:1].all()
if len(posts1) > 0:
return posts1.get().image
#posts2=self.tags.similar_objects()
#for p in posts2:
# posts2=self.tags.similar_objects()
# for p in posts2:
# if p.image is not None:
# return p.image
return None
@property
def url(self):
return reverse('posts.show', kwargs={"id": self.slug})
@@ -170,7 +176,8 @@ class Post(models.Model):
*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)
return "Post (%s, %s): %s " % (self.slug, self.public_date.strftime("%d.%m.%Y"), self.title)
class PostSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
@@ -185,10 +192,11 @@ class PostSerializer(serializers.HyperlinkedModelSerializer):
'legacy_id',
'image',
'event_start',
'event_end',
'is_fetsitzung'
'event_end',
'is_fetsitzung',
]
class News(Post):
objects = NewsManager()
@@ -197,19 +205,20 @@ class News(Post):
verbose_name = "News"
verbose_name_plural = "News"
def save(self, *args, **kwargs):
if not self.post_type:
self.post_type = 'N'
super().save(*args, **kwargs)
class Event(Post):
objects = EventManager()
class Meta:
proxy = True
def save(self, *args, **kwargs):
self.is_event = True
@@ -218,6 +227,7 @@ class Event(Post):
super().save(*args, **kwargs)
class FetMeeting(Event):
objects = FetMeetingManager()
@@ -231,14 +241,14 @@ class FetMeeting(Event):
self.title = "Fachschaftssitzung"
self.slug = slugify(self.event_start.date()) + "-" + slugify(self.title)
self.body = "TODO: Agenda + Protokoll Link"
#TODO
#self.image
# TODO
# self.image
self.has_protocol = True
self.has_agenda = True
#TODO
# TODO
# self.protocol_key
# self.agenda_key
@@ -252,4 +262,4 @@ class FetMeeting(Event):
if not self.event_end:
self.event_end = self.event_start + timedelta(hours=2)
super().save(*args, **kwargs)
super().save(*args, **kwargs)

View File

@@ -5,9 +5,8 @@ from django.utils.safestring import mark_safe
register = template.Library()
@register.filter(is_safe=True)
@stringfilter
def tags_to_url(value):
#return "Tag to url: %s" % value
return mark_safe(re.sub(r'\#([\d\w-]+)', '<a href="/posts/t/\g<1>">#\g<1></a>', value))
# return "Tag to url: %s" % value
return mark_safe(re.sub(r'\#([\d\w-]+)', r'<a href="/posts/t/\g<1>">#\g<1></a>', value))

View File

@@ -1,3 +1,3 @@
from django.test import TestCase
# from django.test import TestCase
# Create your tests here.

View File

@@ -2,10 +2,10 @@ from django.urls import path
from . import views
urlpatterns=[
urlpatterns = [
path('func/tag_complete', views.tag_complete),
path('func/slug_calc', views.slug_calc),
path('t/<str:tag>', views.tags, name='posts.tags'),
path('', views.index, name='posts.index'),
path('<str:id>', views.show, name='posts.show'),
]
]

View File

@@ -1,13 +1,13 @@
from django.shortcuts import render
from django.http import HttpResponse, JsonResponse
from django.http import HttpResponse, JsonResponse, HttpResponseServerError
from django_filters.rest_framework import DjangoFilterBackend
from django.core.cache import cache
# from django.core.cache import cache
from django.utils.text import slugify
from django.utils import timezone
from taggit.models import Tag
from rest_framework import viewsets
from rest_framework import permissions
# from rest_framework import permissions
from .models import Post, PostSerializer
@@ -20,26 +20,28 @@ from collections import deque
def index(request):
posts = deque(Post.objects.order_by('-public_date').all())
f = lambda p: p.tags
def f(p):
return p.tags
t = map(f, posts)
return render(request, 'posts/index.html', {"posts": posts, "tags_list": t})
def tags(request,tag=""):
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):
def show(request, id=None):
if id.isdigit() or id is int:
p = Post.objects.get(id=int(id))
elif id != "" and not id is None:
elif id != "" and id is not None:
p = Post.objects.get(slug=(id))
context = {
"post": p,
"next": get_next_dict().get(p.slug,None),
"next": get_next_dict().get(p.slug, None),
"related_posts": p.tags.similar_objects()
}
return render(request, 'posts/show.html', context)
@@ -77,7 +79,7 @@ def tag_complete(request):
tag_objects = Tag.objects.filter(name__istartswith=term)
tag_array =[]
tag_array = []
for elem in tag_objects:
tag_array.append(elem.name)
@@ -87,15 +89,15 @@ def tag_complete(request):
def get_next_dict():
#TODO: Docstring
# TODO: Docstring
posts = Post.article_objects.order_by('-public_date').values('slug')
print(posts)
d = {}
print(d)
for k,v in enumerate(posts):
for k, v in enumerate(posts):
if k == len(posts) - 1:
break
d[v['slug']] = posts[k+1]['slug']
d[v['slug']] = posts[k + 1]['slug']
print(d)
return d
@@ -106,9 +108,9 @@ class PostViewSet(viewsets.ModelViewSet):
"""
queryset = Post.objects.all().order_by('-public_date')
serializer_class = PostSerializer
#permission_classes = [permissions.IsAuthenticated]
# permission_classes = [permissions.IsAuthenticated]
filter_backends = [DjangoFilterBackend]
filterset_fields = ['legacy_id', 'slug','legacy_rubrik_id']
filterset_fields = ['legacy_id', 'slug', 'legacy_rubrik_id']
lookup_field = 'slug'
def pre_save(self, obj):

View File

@@ -4,4 +4,5 @@ django-ckeditor
Pillow
djangorestframework
django-static-jquery-ui
docutils
docutils
easy-thumbnails

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

8911
fet2020/static/app.css Normal file

File diff suppressed because one or more lines are too long

22644
fet2020/static/app.js Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -0,0 +1,162 @@
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ }
/******/ };
/******/
/******/ // define __esModule on exports
/******/ __webpack_require__.r = function(exports) {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/
/******/ // create a fake namespace object
/******/ // mode & 1: value is a module id, require it
/******/ // mode & 2: merge all properties of value into the ns
/******/ // mode & 4: return value when already ns object
/******/ // mode & 8|1: behave like require
/******/ __webpack_require__.t = function(value, mode) {
/******/ if(mode & 1) value = __webpack_require__(value);
/******/ if(mode & 8) return value;
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ var ns = Object.create(null);
/******/ __webpack_require__.r(ns);
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ return ns;
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ({
/***/ "./src/assets/js/building-blocks/responsive-hidden-nav.js":
/*!****************************************************************!*\
!*** ./src/assets/js/building-blocks/responsive-hidden-nav.js ***!
\****************************************************************/
/*! no static exports found */
/***/ (function(module, exports) {
var $topBar = $('[data-responsive-hidden-nav]');
var $button = $('[data-responsive-hidden-nav] .responsive-hidden-button');
var $visibleLinks = $('[data-responsive-hidden-nav] .visible-links');
var $hiddenLinks = $('[data-responsive-hidden-nav] .hidden-links');
var responsiveBreaks = []; // Empty List (Array) on initialization
function updateTopBar() {
var availableSpace = $button.hasClass('hidden') ? $topBar.width() : $topBar.width() - $button.width() - 30; // Calculation of available space on the logic of whether button has the class `hidden` or not
if ($visibleLinks.width() > availableSpace) {
// Logic when visible list is overflowing the nav
responsiveBreaks.push($visibleLinks.width()); // Record the width of the list
$visibleLinks.children().last().prependTo($hiddenLinks); // Move item to the hidden list
// Show the resonsive hidden button
if ($button.hasClass('hidden')) {
$button.removeClass('hidden');
}
} else {
// Logic when visible list is not overflowing the nav
if (availableSpace > responsiveBreaks[responsiveBreaks.length - 1]) {
// Logic when there is space for another item in the nav
$hiddenLinks.children().first().appendTo($visibleLinks);
responsiveBreaks.pop(); // Move the item to the visible list
} // Hide the resonsive hidden button if list is empty
if (responsiveBreaks.length < 1) {
$button.addClass('hidden');
$hiddenLinks.addClass('hidden');
}
}
$button.attr("count", responsiveBreaks.length); // Keeping counter updated
if ($visibleLinks.width() > availableSpace) {
// Occur again if the visible list is still overflowing the nav
updateTopBar();
}
} // Window listeners
$(window).resize(function () {
updateTopBar();
});
$button.on('click', function () {
$hiddenLinks.toggleClass('hidden');
});
updateTopBar();
/***/ }),
/***/ 0:
/*!**********************************************************************!*\
!*** multi ./src/assets/js/building-blocks/responsive-hidden-nav.js ***!
\**********************************************************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(/*! /srv/test_1/myproject/src/assets/js/building-blocks/responsive-hidden-nav.js */"./src/assets/js/building-blocks/responsive-hidden-nav.js");
/***/ })
/******/ });
//# sourceMappingURL=responsive-hidden-nav.js.map

File diff suppressed because one or more lines are too long

View File

@@ -32,36 +32,11 @@
</a>
<div class="article-row-section">
{% with post=featured_post %}
<a href="{{post.url}}">
<article class="article-row">
<div class="article-row-content">
<h1 class="article-row-content-header">{{post.title}}</h1>
<p class="article-row-content-description">{{post.subtitle}}</p>
<p class="article-row-content-author">{{post.author}}</p>
<time class="article-row-content-time" datetime="2008-02-14 20:00">{{post.public_date}}</time>
</div>
</article>
</a>
{% include 'posts/partials/_article_row.html' %}
{% endwith %}
{% with post=featured_post2 %}
{% include 'posts/partials/_article_row.html' %}
{% endwith %}
<a href="#">
<article class="article-row">
<div class="article-row-content">
<h1 class="article-row-content-header">Nächste Fachschaftssitzung</h1>
<p class="article-row-content-description">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Labore accusamus sint quas, odit, enim architecto officiis culpa!</p>
<p class="article-row-content-author">By Yeti</p>
<time class="article-row-content-time" datetime="2008-02-14 20:00">July 14th 2021</time>
</div>
</article>
</a>
</div>
</div>
@@ -74,27 +49,19 @@
<div class="grid-x grid-x-padding">
<div class="medium-8 cell">
<div class="medium-8 small-12 small-order-2 medium-order-1"">
{% for post in posts %}
{% include 'posts/_posts_hero.html' %}
{% include 'posts/partials/_posts_hero.html' %}
{% endfor %}
</div>
<div class="medium-4 cell">
<div class="date-box">
<span class="date-badge badge primary" style="">
<span class="date-badge-day">16</span>
<span class="date-badge-month">Apr</span>
</span>
<span class="date-text"><strong>Title</strong></span>
</div>
<div class="medium-4 small-12 small-order-1 medium-order-2 padding-1">
{% for post in events %}
{% include 'posts/partials/_date_box.html' %}
{% endfor %}
</div>
</div>
</div>
{% endblock %}

View File

@@ -23,7 +23,7 @@
<li class=""><a href="{%url 'home'%}">Aktuelles</a> </li>
<li class=""><a href="/fotos">Fotos</a> </li>
<li class=""><a href="{%url 'members.index'%}">Mitarbeiter</a>
<li class=""><a href="{%url 'members'%}">Mitarbeiter</a>
</li>
</ul>
</div>

View File

@@ -1,79 +1,46 @@
{% 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>
<h1>Mitglieder / Tätigkeiten</h1>
<!-- Nav tabs -->
<ul class="nav nav-tabs nav-fill">
<a class="active" id="members" data-toggle="tab" href="/members">Mitglieder</a>
<a id="members" data-toggle="tab" href="/members/A">Aktive Mitglieder</a>
<a id="members" data-toggle="tab" href="/members/P">Inaktive Mitglieder</a>
{% for job in job_group %}
<a id="jobs-{{job.id}}" data-toggle="tab" href="/members/jobs/{{job.slug}}">{{job.name}}</a>
{% endfor %}
</ul>
<!-- Tab panes -->
<div class="tab-content" id="nav-tabContent">
<div id="members" class="tab-pane fade in active">
{% if members == None %}
{% else %}
{% include 'members/members_list.html' %}
{% 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 id="jobs-{{job.id}}" class="tab-pane">
{% if members is None %}
{% for job in job_list %}
{% if job_list|length > 1 %}
<h2>{{job.0}}</h2>
{% endif %}
{% with active_members=job.1 inactive_members=job.2 %}
{% include 'members/jobs_list.html' %}
{% endwith %}
{% endfor %}
{% endif %}
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,26 @@
<div class="grid-container">
Aktuelle Mitglieder: {{active_members.count}}
<div class="grid-x">
{% for mem in active_members %}
<div class="medium-6 cell">
<h2>{{mem.get_job_role_display}} (seit {{mem.job_start}})</h2>
{% with member=mem.member %}
{% include 'members/partials/_member_details.html' %}
{% endwith %}
</div>
{% endfor %}
</div>
Vergangene Mitglieder: {{inactive_members.count}}
<div class="grid-x">
{% for mem in inactive_members %}
<div class="medium-6 cell">
<h2>{{mem.get_job_role_display}} ({{mem.job_start}} - {{mem.job_end}})</h2>
{% with member=mem.member %}
{% include 'members/partials/_member_details.html' %}
{% endwith %}
</div>
{% endfor %}
</div>

View File

@@ -0,0 +1,26 @@
<div class="grid-container">
<h1> Mitarbeiter Liste </h1>
<h2> Grid Style</h2>
<div class="grid-x">
{% for member in members %}
<div class="medium-3 large-2 small-6 cell">
{% include 'members/partials/_member.html' %}
</div>
{% endfor %}
</div>
<h2> Grid Style 2</h2>
<div class="grid-x">
{% for member in members %}
{% include 'members/partials/_member.html' %}
{% endfor %}
</div>
<h2>Detail List</h2>
<div class="grid-container">
{% for member in members %}
{% include 'members/partials/_member_details.html' %}
{% endfor %}
</div>
</div>

View File

@@ -0,0 +1,8 @@
{# only thumb and name of member #}
{% load thumbnail %}
<a class="thumbnail member-thumb" style="width:150px;height:150px">
{% if member.image %}<img src="{{member.image | thumbnail_url:'thumb'}}" />{% endif %}
<div class="thumb-layer"><div><h1>{{member.nickname}}</h1> <p>{{member.firstname}} {{member.surname}}</p></div></div>
</a>

View File

@@ -0,0 +1,19 @@
{# This template shows one member and all the details (that are ment for public) including a list of current jobs #}
{% load thumbnail %}
<div class="media-object">
<div class="media-object-section">
<div class="thumbnail">
<img src= "{{member.image.url}}" style="width:150px;">
</div>
</div>
<div class="media-object-section main-section">
<h1>{{member.firstname}} {{member.surname}}</h1>
<p>Spitzname: {{member.nickname}} </br>
Name: {{member.firstname}} {{member.surname}} </br>
Mailaccount: {{member.mailaccount}} </br>
Beschreibung: {{member.description|safe}} </br>
</p>
</div>
</div>

View File

@@ -3,10 +3,12 @@
{% block content %}
<div class="grid-container">
<div class="grid-x">
<div class="medium-8 cell">
{% for post in posts %}
{% include 'posts/_posts_hero.html' %}
{% include 'posts/partials/_posts_hero.html' %}
{% endfor %}

View File

@@ -0,0 +1,15 @@
<a href="{{post.url}}">
<article class="article-row">
<div class="article-row-content">
<h1 class="article-row-content-header">{{post.title}}</h1>
<p class="article-row-content-description">{{post.subtitle}}</p>
<p class="article-row-content-author">{{post.author}}</p>
<time class="article-row-content-time" datetime="2008-02-14 20:00">{{post.public_date}}</time>
</div>
</article>
</a>

View File

@@ -0,0 +1,10 @@
<a href ="">
<div class="date-box">
<span>
<span class="date-badge badge primary" style="">
<span class="date-badge-day">16</span>
<span class="date-badge-month">Apr</span>
</span></span>
<span class="date-text"><strong>{{post.title}}</strong></span>
</div></a>

View File

@@ -0,0 +1,8 @@
<a href="{% url 'posts.show' post.slug %}">
<div class="news-hero padding-bottom-1" style="background-image:url('{{post.imageurl}}')">
<div class="news-hero-text">
<h1>{{post.title}}</h1>
<h2>{{post.subtitle}}</h2>{{post}}
</div>
</div>
</a>