multiple changes
This commit is contained in:
6
.gitignore
vendored
6
.gitignore
vendored
@@ -4,6 +4,8 @@
|
|||||||
fet2020/files/*
|
fet2020/files/*
|
||||||
fet2020/.env/*
|
fet2020/.env/*
|
||||||
*.sqlite3
|
*.sqlite3
|
||||||
fet2020/posts/migrations/*
|
fet2020/*/migrations/*
|
||||||
fet2020/members/migrations/*
|
|
||||||
.theia/*
|
.theia/*
|
||||||
|
.flake8
|
||||||
|
migrate
|
||||||
|
run
|
||||||
@@ -1,32 +1,57 @@
|
|||||||
from etherpad_lite import EtherpadLiteClient
|
from etherpad_lite import EtherpadLiteClient
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
from django.utils.text import slugify
|
||||||
|
import urllib.parse
|
||||||
t=datetime.now() + timedelta(days=1)
|
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:
|
with open("/srv/andis_test/etherpad_test2/etherpad-lite/APIKEY.txt","r") as f:
|
||||||
k=f.read()
|
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")
|
a=epc.createAuthorIfNotExistsFor(name="andis", authorMapper="andis")
|
||||||
g=epc.createGroupIfNotExistsFor(groupMapper="fet")
|
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):
|
def add_ep_to_response(request, response):
|
||||||
if request.user is None:
|
if request.user is None:
|
||||||
return response
|
return response
|
||||||
padID=id
|
padID=id
|
||||||
server = urlparse(SERVER_URL)
|
server = SERVER_URL
|
||||||
padLink = SERVER_URL + 'p/' + g["groupID"] + '$' + \
|
#padLink = urllib.parse.urljoin(SERVER_URL , 'p/' + g["groupID"] + '$' + padID)
|
||||||
padID
|
|
||||||
author = epc.createAuthorIfNotExistsFor(name=str(request.user), authorMapper=str(request.user))['authorID']
|
author = epc.createAuthorIfNotExistsFor(name=str(request.user), authorMapper=str(request.user))['authorID']
|
||||||
expires = datetime.datetime.utcnow() + datetime.timedelta(
|
expires = datetime.utcnow() + timedelta(
|
||||||
hours=3
|
hours=3
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = epclient.createSession(
|
result = epclient.createSession(
|
||||||
groupID=str(group['groupID']),
|
groupID=str(g['groupID']),
|
||||||
authorID=str(author),
|
authorID=str(author),
|
||||||
validUntil=str(int(expires.timestamp()))
|
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('sessionID', server.hostname)
|
||||||
response.delete_cookie('padSessionID')
|
response.delete_cookie('padSessionID')
|
||||||
|
|
||||||
response.set_cookie(
|
response=response.set_cookie(
|
||||||
'sessionID',
|
'sessionID',
|
||||||
value=result['sessionID'],
|
value=result['sessionID'],
|
||||||
expires=expires,
|
expires=expires,
|
||||||
domain=server.hostname,
|
domain="https://etherpad2.2020.fet.at",
|
||||||
httponly=False
|
httponly=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
from django.apps import AppConfig
|
|
||||||
|
|
||||||
|
|
||||||
class DocumentsConfig(AppConfig):
|
|
||||||
name = 'documents'
|
|
||||||
from django.contrib.admin.apps import AdminConfig
|
|
||||||
|
|
||||||
@@ -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)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
from django.test import TestCase
|
|
||||||
|
|
||||||
# Create your tests here.
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
import documents.views as views
|
|
||||||
from django.urls import path
|
|
||||||
|
|
||||||
urlpatterns=[
|
|
||||||
path("document/<id>", views.document)
|
|
||||||
]
|
|
||||||
@@ -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
|
|
||||||
@@ -1,13 +1,18 @@
|
|||||||
from django.contrib.auth.models import User
|
# from django.contrib.auth.models import User
|
||||||
from django.contrib.auth.middleware import RemoteUserMiddleware
|
from django.contrib.auth.middleware import RemoteUserMiddleware
|
||||||
import django
|
# import django
|
||||||
# import logging
|
# import logging
|
||||||
# logger=logging.getLogger("django.request")
|
# logger=logging.getLogger("django.request")
|
||||||
|
|
||||||
|
|
||||||
class FETHeaderMiddleware(RemoteUserMiddleware):
|
class FETHeaderMiddleware(RemoteUserMiddleware):
|
||||||
header = "Remote-User"
|
header = "Remote-User"
|
||||||
|
|
||||||
def process_request(self, request):
|
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)
|
super().process_request(request)
|
||||||
if request.user.is_authenticated:
|
if request.user.is_authenticated:
|
||||||
request.user.is_admin = True
|
request.user.is_admin = True
|
||||||
|
|||||||
@@ -12,6 +12,23 @@ https://docs.djangoproject.com/en/3.0/ref/settings/
|
|||||||
|
|
||||||
import os
|
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, ...)
|
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
@@ -33,10 +50,8 @@ DATA_UPLOAD_MAX_MEMORY_SIZE = 1024*1024*1024
|
|||||||
CKEDITOR_UPLOAD_PATH = 'upload'
|
CKEDITOR_UPLOAD_PATH = 'upload'
|
||||||
|
|
||||||
INSTALLED_APPS = [
|
INSTALLED_APPS = [
|
||||||
'posts.apps.PostsConfig',
|
|
||||||
'members.apps.MembersConfig',
|
|
||||||
'documents.apps.DocumentsConfig',
|
|
||||||
'django.contrib.admin',
|
'django.contrib.admin',
|
||||||
|
'django.contrib.admindocs',
|
||||||
'django.contrib.auth',
|
'django.contrib.auth',
|
||||||
'django.contrib.contenttypes',
|
'django.contrib.contenttypes',
|
||||||
'django.contrib.sessions',
|
'django.contrib.sessions',
|
||||||
@@ -45,10 +60,12 @@ INSTALLED_APPS = [
|
|||||||
'taggit',
|
'taggit',
|
||||||
'ckeditor',
|
'ckeditor',
|
||||||
'ckeditor_uploader',
|
'ckeditor_uploader',
|
||||||
|
'easy_thumbnails',
|
||||||
'rest_framework',
|
'rest_framework',
|
||||||
'django_filters',
|
'django_filters',
|
||||||
'django_static_jquery_ui',
|
'django_static_jquery_ui',
|
||||||
'django.contrib.admindocs'
|
'posts.apps.PostsConfig',
|
||||||
|
'members.apps.MembersConfig',
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
@@ -67,7 +84,10 @@ ROOT_URLCONF = 'fet2020.urls'
|
|||||||
TEMPLATES = [
|
TEMPLATES = [
|
||||||
{
|
{
|
||||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
'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,
|
'APP_DIRS': True,
|
||||||
'OPTIONS': {
|
'OPTIONS': {
|
||||||
'context_processors': [
|
'context_processors': [
|
||||||
@@ -143,8 +163,6 @@ STATICFILES_DIRS = [
|
|||||||
MEDIA_ROOT = os.path.join(BASE_DIR, 'files/')
|
MEDIA_ROOT = os.path.join(BASE_DIR, 'files/')
|
||||||
MEDIA_URL = '/files/'
|
MEDIA_URL = '/files/'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
TAGGIT_FORCE_LOWERCASE = True
|
TAGGIT_FORCE_LOWERCASE = True
|
||||||
|
|
||||||
CKEDITOR_CONFIGS = {
|
CKEDITOR_CONFIGS = {
|
||||||
@@ -162,5 +180,10 @@ CKEDITOR_CONFIGS = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
THUMBNAIL_ALIASES = {
|
||||||
|
'': {
|
||||||
|
'avatar': {'size': (50, 50), 'crop': True},
|
||||||
|
'thumb': {'size': (150, 150), 'crop': True},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
@@ -28,12 +28,11 @@ router.register(r'members', MemberViewSet)
|
|||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('posts/', include('posts.urls')),
|
path('posts/', include('posts.urls')),
|
||||||
path('documents/', include('documents.urls')),
|
|
||||||
path('admin/doc/', include('django.contrib.admindocs.urls')),
|
path('admin/doc/', include('django.contrib.admindocs.urls')),
|
||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls),
|
||||||
path('', views.index, name='home'),
|
path('', views.index, name='home'),
|
||||||
path('index.html', views.index, name='home'),
|
path('index.html', views.index, name='home'),
|
||||||
path('ckeditor/', include('ckeditor_uploader.urls')),
|
path('ckeditor/', include('ckeditor_uploader.urls')),
|
||||||
path('api/', include(router.urls)),
|
path('api/', include(router.urls)),
|
||||||
path('members/', include('members.urls')),
|
path('members/', include('members.urls'), name='members'),
|
||||||
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
|
|||||||
@@ -1,22 +1,30 @@
|
|||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.http import HttpResponse
|
# from django.http import HttpResponse
|
||||||
from collections import deque
|
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):
|
def index(request):
|
||||||
posts = deque(Post.article_objects.all())
|
posts = deque(Post.article_objects.all())
|
||||||
l=len(posts)
|
date_today = timezone.now().date()
|
||||||
def get_tags(lst):
|
def get_tags(lst):
|
||||||
for p in lst:
|
for p in lst:
|
||||||
for t in list(p.tags.names()):
|
for t in list(p.tags.names()):
|
||||||
yield "#" + t
|
yield "#" + t
|
||||||
|
|
||||||
|
|
||||||
t = set(t for t in get_tags(posts))
|
t = set(t for t in get_tags(posts))
|
||||||
if l>=1:
|
if len(posts) >= 1:
|
||||||
featured_post = posts.popleft()
|
featured_post = posts.popleft()
|
||||||
else:
|
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)
|
||||||
|
|||||||
@@ -16,37 +16,41 @@ class MemberRoleFilter(admin.SimpleListFilter):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def queryset(self, request, queryset):
|
def queryset(self, request, queryset):
|
||||||
if self.value() == 'A':
|
if self.value() in Member.MemberRole:
|
||||||
return queryset.filter(role='A')
|
return queryset.filter(role=self.value())
|
||||||
elif self.value() == 'P':
|
|
||||||
return queryset.filter(role='P')
|
|
||||||
|
|
||||||
class JobMemberInline(admin.TabularInline):
|
class JobMemberInline(admin.TabularInline):
|
||||||
model = JobMember
|
model = JobMember
|
||||||
extra = 0
|
extra = 0
|
||||||
|
|
||||||
|
|
||||||
class JobOverviewInline(JobMemberInline):
|
class JobOverviewInline(JobMemberInline):
|
||||||
verbose_name = "Tätigkeit"
|
verbose_name = "Tätigkeit"
|
||||||
verbose_name_plural = "Tätigkeitsübersicht"
|
verbose_name_plural = "Tätigkeitsübersicht"
|
||||||
|
|
||||||
|
|
||||||
class ActiveMemberInline(JobMemberInline):
|
class ActiveMemberInline(JobMemberInline):
|
||||||
verbose_name = "Mitglied"
|
verbose_name = "Mitglied"
|
||||||
verbose_name_plural = "Aktive Mitglieder Liste"
|
verbose_name_plural = "Aktive Mitglieder Liste"
|
||||||
|
|
||||||
def get_queryset(self, request):
|
def get_queryset(self, request):
|
||||||
return JobMember.active_member.all()
|
return JobMember.active_member.get_all()
|
||||||
|
|
||||||
|
|
||||||
class InactiveMemberInline(JobMemberInline):
|
class InactiveMemberInline(JobMemberInline):
|
||||||
verbose_name = "Mitglied"
|
verbose_name = "Mitglied"
|
||||||
verbose_name_plural = "Inaktive Mitglieder Liste"
|
verbose_name_plural = "Inaktive Mitglieder Liste"
|
||||||
|
|
||||||
def get_queryset(self, request):
|
def get_queryset(self, request):
|
||||||
return JobMember.inactive_member.all()
|
return JobMember.inactive_member.get_all()
|
||||||
|
|
||||||
|
|
||||||
class JobInline(admin.TabularInline):
|
class JobInline(admin.TabularInline):
|
||||||
model = Job
|
model = Job
|
||||||
extra = 0
|
extra = 0
|
||||||
|
|
||||||
|
|
||||||
class MyMemberAdmin(admin.ModelAdmin):
|
class MyMemberAdmin(admin.ModelAdmin):
|
||||||
form = MyMemberForm
|
form = MyMemberForm
|
||||||
model = Member
|
model = Member
|
||||||
@@ -60,8 +64,10 @@ class MyMemberAdmin(admin.ModelAdmin):
|
|||||||
obj.author = request.user
|
obj.author = request.user
|
||||||
super().save_model(request, obj, form, change)
|
super().save_model(request, obj, form, change)
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Member, MyMemberAdmin)
|
admin.site.register(Member, MyMemberAdmin)
|
||||||
|
|
||||||
|
|
||||||
class MyJobAdmin(admin.ModelAdmin):
|
class MyJobAdmin(admin.ModelAdmin):
|
||||||
form = MyJobForm
|
form = MyJobForm
|
||||||
model = Job
|
model = Job
|
||||||
@@ -74,8 +80,10 @@ class MyJobAdmin(admin.ModelAdmin):
|
|||||||
obj.author = request.user
|
obj.author = request.user
|
||||||
super().save_model(request, obj, form, change)
|
super().save_model(request, obj, form, change)
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Job, MyJobAdmin)
|
admin.site.register(Job, MyJobAdmin)
|
||||||
|
|
||||||
|
|
||||||
class MyJobGroupAdmin(admin.ModelAdmin):
|
class MyJobGroupAdmin(admin.ModelAdmin):
|
||||||
form = MyJobGroupForm
|
form = MyJobGroupForm
|
||||||
model = JobGroup
|
model = JobGroup
|
||||||
@@ -88,4 +96,5 @@ class MyJobGroupAdmin(admin.ModelAdmin):
|
|||||||
obj.author = request.user
|
obj.author = request.user
|
||||||
super().save_model(request, obj, form, change)
|
super().save_model(request, obj, form, change)
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(JobGroup, MyJobGroupAdmin)
|
admin.site.register(JobGroup, MyJobGroupAdmin)
|
||||||
@@ -20,16 +20,29 @@ class MyMemberForm(forms.ModelForm):
|
|||||||
'address'
|
'address'
|
||||||
]
|
]
|
||||||
|
|
||||||
widgets = {'description': CKEditorUploadingWidget(config_name='default')}
|
widgets = {
|
||||||
|
'description': CKEditorUploadingWidget(config_name='default')
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class MyJobForm(forms.ModelForm):
|
class MyJobForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Job
|
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 MyJobGroupForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = JobGroup
|
model = JobGroup
|
||||||
fields = ['name', 'shortterm', 'is_pinned']
|
fields = ['name', 'shortterm', 'slug', 'is_pinned']
|
||||||
|
|||||||
@@ -4,50 +4,79 @@ from django.db.models import Q
|
|||||||
from django.utils import timezone
|
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 django.utils.translation import gettext_lazy as _
|
||||||
from rest_framework import serializers
|
|
||||||
|
|
||||||
import uuid
|
|
||||||
|
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
|
||||||
class MemberManager(models.Manager):
|
class MemberQuerySet(models.QuerySet):
|
||||||
def get_queryset(self):
|
def get_members(self):
|
||||||
return super().get_queryset().filter(role='A')
|
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):
|
class ActiveMemberManager(models.Manager):
|
||||||
'''
|
'''
|
||||||
return a list of active member, and members who are still working
|
return a list of active member, and members who are still working
|
||||||
'''
|
'''
|
||||||
def get_queryset(self):
|
def get_members_of_job(self, job_names):
|
||||||
date_today = timezone.now().date()
|
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):
|
class InactiveMemberManager(models.Manager):
|
||||||
'''
|
'''
|
||||||
return a list of inactive member
|
return a list of inactive member
|
||||||
'''
|
'''
|
||||||
def get_queryset(self):
|
def get_members_of_job(self, job_names):
|
||||||
date_today = timezone.now().date()
|
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):
|
class Member(models.Model):
|
||||||
firstname = models.CharField(max_length=128)
|
firstname = models.CharField(max_length=128)
|
||||||
@@ -55,11 +84,11 @@ class Member(models.Model):
|
|||||||
nickname = models.CharField(max_length=128)
|
nickname = models.CharField(max_length=128)
|
||||||
mailaccount = models.CharField(max_length=128)
|
mailaccount = models.CharField(max_length=128)
|
||||||
|
|
||||||
__choices = [
|
class MemberRole(models.TextChoices):
|
||||||
('A', _('Active')),
|
ACTIVE = 'A', _('Active')
|
||||||
('P', _('Pension'))
|
PENSION = 'P', _('Pension')
|
||||||
]
|
|
||||||
role = models.CharField(max_length=1, choices= __choices, default='A')
|
role = models.CharField(max_length=1, choices=MemberRole.choices, default=MemberRole.ACTIVE)
|
||||||
|
|
||||||
description = models.TextField(null=True, blank=True)
|
description = models.TextField(null=True, blank=True)
|
||||||
image = models.ImageField(null=True, blank=True)
|
image = models.ImageField(null=True, blank=True)
|
||||||
@@ -67,8 +96,7 @@ class Member(models.Model):
|
|||||||
birthday = models.DateField(null=True, blank=True)
|
birthday = models.DateField(null=True, blank=True)
|
||||||
|
|
||||||
phone_error_msg = _((
|
phone_error_msg = _((
|
||||||
"Phone number must be entered in the format: "
|
"Phone number must be entered in the format: +999999999'. Up to 15 digits allowed."
|
||||||
"+999999999'. Up to 15 digits allowed."
|
|
||||||
))
|
))
|
||||||
phone_regex = RegexValidator(regex=r'^\+?1?\d{9,15}$', message=phone_error_msg)
|
phone_regex = RegexValidator(regex=r'^\+?1?\d{9,15}$', message=phone_error_msg)
|
||||||
phone = models.CharField(validators=[phone_regex], max_length=17, blank=True)
|
phone = models.CharField(validators=[phone_regex], max_length=17, blank=True)
|
||||||
@@ -80,8 +108,6 @@ class Member(models.Model):
|
|||||||
|
|
||||||
# Managers
|
# Managers
|
||||||
all_members = models.Manager()
|
all_members = models.Manager()
|
||||||
active_member = MemberManager()
|
|
||||||
pension_member = PensionManager()
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = "Mitglied"
|
verbose_name = "Mitglied"
|
||||||
@@ -90,6 +116,7 @@ class Member(models.Model):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.firstname + " " + self.surname
|
return self.firstname + " " + self.surname
|
||||||
|
|
||||||
|
|
||||||
class MemberSerializer(serializers.HyperlinkedModelSerializer):
|
class MemberSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Member
|
model = Member
|
||||||
@@ -100,17 +127,22 @@ class MemberSerializer(serializers.HyperlinkedModelSerializer):
|
|||||||
'mailaccount',
|
'mailaccount',
|
||||||
'role',
|
'role',
|
||||||
'description',
|
'description',
|
||||||
'image'
|
'image',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class JobGroup(models.Model):
|
class JobGroup(models.Model):
|
||||||
name = models.CharField(max_length=128)
|
name = models.CharField(max_length=128)
|
||||||
shortterm = 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)
|
is_pinned = models.BooleanField(default=False)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
class Job(models.Model):
|
class Job(models.Model):
|
||||||
name = models.CharField(max_length=128)
|
name = models.CharField(max_length=128)
|
||||||
shortterm = models.CharField(max_length=128)
|
shortterm = models.CharField(max_length=128)
|
||||||
@@ -139,6 +171,7 @@ class Job(models.Model):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.shortterm
|
return self.shortterm
|
||||||
|
|
||||||
|
|
||||||
class JobMember(models.Model):
|
class JobMember(models.Model):
|
||||||
member = models.ForeignKey(
|
member = models.ForeignKey(
|
||||||
Member,
|
Member,
|
||||||
@@ -154,16 +187,18 @@ class JobMember(models.Model):
|
|||||||
job_start = models.DateField('Job Start')
|
job_start = models.DateField('Job Start')
|
||||||
job_end = models.DateField('Job Ende', null=True, blank=True)
|
job_end = models.DateField('Job Ende', null=True, blank=True)
|
||||||
|
|
||||||
__choices = [
|
class JobRole(models.TextChoices):
|
||||||
('1V', _('VorsitzendeR')),
|
PRESIDENT = '1V', _('VorsitzendeR')
|
||||||
('2V', _('stv VorsitzendeR')),
|
VICE_PRESIDENT = '2V', _('stv VorsitzendeR')
|
||||||
('3V', _('2. stv VorsitzendeR')),
|
SECOND_VICE_PRESIDENT = '3V', _('2. stv VorsitzendeR')
|
||||||
('M', _('Mitglied')),
|
MEMBER = 'M', _('Mitglied')
|
||||||
('E', _('Ersatzmitglied')),
|
SUBSTITUTE_MEMBER = 'E', _('Ersatzmitglied')
|
||||||
('V', _('VerantwortlicheR'))
|
PERSON_RESPONSIBLE = 'V', _('VerantwortlicheR')
|
||||||
]
|
|
||||||
job_role = models.CharField(max_length=2, choices=__choices, default='M')
|
|
||||||
|
|
||||||
jobmember = models.Manager()
|
job_role = models.CharField(max_length=2, choices=JobRole.choices, default=JobRole.MEMBER)
|
||||||
|
|
||||||
|
members = MemberManager()
|
||||||
active_member = ActiveMemberManager()
|
active_member = ActiveMemberManager()
|
||||||
inactive_member = InactiveMemberManager()
|
inactive_member = InactiveMemberManager()
|
||||||
|
|
||||||
|
jobs = JobManager()
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
from django.test import TestCase
|
# from django.test import TestCase
|
||||||
|
|
||||||
# Create your tests here.
|
# Create your tests here.
|
||||||
|
|||||||
@@ -4,5 +4,7 @@ from . import views
|
|||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', views.index, name='members.index'),
|
path('', views.index, name='members'),
|
||||||
|
path('<str:filter>', views.index),
|
||||||
|
path('jobs/<str:slug>', views.index),
|
||||||
]
|
]
|
||||||
@@ -1,31 +1,65 @@
|
|||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.http import HttpResponse
|
# from django.http import HttpResponse
|
||||||
|
|
||||||
from collections import deque
|
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 viewsets
|
||||||
from rest_framework import permissions
|
from rest_framework import permissions
|
||||||
from django_filters.rest_framework import DjangoFilterBackend
|
# from django_filters.rest_framework import DjangoFilterBackend
|
||||||
|
|
||||||
|
|
||||||
def index(request):
|
def index(request, slug=None, filter=None):
|
||||||
#members = deque(Member.all_members.all())
|
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())
|
members = deque(Member.all_members.all())
|
||||||
jobmembers = deque(JobMember.jobmember.all())
|
elif filter in Member.MemberRole:
|
||||||
jobs = deque(Job.objects.all())
|
members = deque(Member.all_members.filter(role=filter))
|
||||||
jobgroups = deque(JobGroup.objects.all())
|
else:
|
||||||
|
members = None
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
|
"job_group": job_group,
|
||||||
|
"job_list": job_list,
|
||||||
"members": members,
|
"members": members,
|
||||||
"jobmembers" : jobmembers,
|
|
||||||
"jobgroups" : jobgroups,
|
|
||||||
"jobs" : jobs,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return render(request, 'members/index.html', context)
|
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):
|
class MemberViewSet(viewsets.ModelViewSet):
|
||||||
"""
|
"""
|
||||||
API endpoint that allows users to be viewed or edited.
|
API endpoint that allows users to be viewed or edited.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import django.contrib.auth.admin
|
# import django.contrib.auth.admin
|
||||||
import django.contrib.auth.models
|
# import django.contrib.auth.models
|
||||||
import taggit.admin
|
import taggit.admin
|
||||||
|
|
||||||
from django.contrib import admin, auth
|
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(auth.models.Group)
|
||||||
admin.site.unregister(taggit.models.Tag)
|
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):
|
class MyPostAdmin(admin.ModelAdmin):
|
||||||
form = MyPostForm
|
form = MyPostForm
|
||||||
@@ -33,21 +36,27 @@ class MyPostAdmin(admin.ModelAdmin):
|
|||||||
"jquery-ui/jquery-ui.min.js",
|
"jquery-ui/jquery-ui.min.js",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class MyEventAdmin(MyPostAdmin):
|
class MyEventAdmin(MyPostAdmin):
|
||||||
form = MyEventForm
|
form = MyEventForm
|
||||||
model = Event
|
model = Event
|
||||||
list_display = ['title', 'subtitle', 'slug', 'event_start', 'public_date']
|
list_display = ['title', 'subtitle', 'slug', 'event_start', 'public_date']
|
||||||
|
actions=[make_fetmeeting]
|
||||||
|
|
||||||
admin.site.register(Event, MyEventAdmin)
|
admin.site.register(Event, MyEventAdmin)
|
||||||
|
|
||||||
|
|
||||||
class MyNewsAdmin(MyPostAdmin):
|
class MyNewsAdmin(MyPostAdmin):
|
||||||
form = MyNewsForm
|
form = MyNewsForm
|
||||||
model = News
|
model = News
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(News, MyNewsAdmin)
|
admin.site.register(News, MyNewsAdmin)
|
||||||
|
|
||||||
|
|
||||||
class MyFetMeetingAdmin(MyEventAdmin):
|
class MyFetMeetingAdmin(MyEventAdmin):
|
||||||
form = MyFetMeetingForm
|
form = MyFetMeetingForm
|
||||||
model = FetMeeting
|
model = FetMeeting
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(FetMeeting, MyFetMeetingAdmin)
|
admin.site.register(FetMeeting, MyFetMeetingAdmin)
|
||||||
@@ -17,6 +17,7 @@ class MyPostForm(forms.ModelForm):
|
|||||||
'js/tag_completion.js', # to get a list for tag autocompletion via ajax
|
'js/tag_completion.js', # to get a list for tag autocompletion via ajax
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class MyNewsForm(MyPostForm):
|
class MyNewsForm(MyPostForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = News
|
model = News
|
||||||
@@ -27,6 +28,7 @@ class MyNewsForm(MyPostForm):
|
|||||||
def __init__(self, *args, **kwargs):
|
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 MyEventForm(MyPostForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Event
|
model = Event
|
||||||
@@ -44,6 +46,7 @@ class MyEventForm(MyPostForm):
|
|||||||
if 'event_place' in self.fields:
|
if 'event_place' in self.fields:
|
||||||
self.fields['event_place'].required = True
|
self.fields['event_place'].required = True
|
||||||
|
|
||||||
|
|
||||||
class MyFetMeetingForm(MyEventForm):
|
class MyFetMeetingForm(MyEventForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = FetMeeting
|
model = FetMeeting
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
from taggit.managers import TaggableManager
|
from taggit.managers import TaggableManager
|
||||||
|
|
||||||
# from ckeditor_uploader import RichTextUploadingField
|
# from ckeditor_uploader import RichTextUploadingField
|
||||||
import uuid
|
# import uuid
|
||||||
import re
|
import re
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
@@ -27,25 +27,29 @@ class PostManager(models.Manager):
|
|||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return super().get_queryset()
|
return super().get_queryset()
|
||||||
|
|
||||||
|
|
||||||
class ArticleManager(models.Manager):
|
class ArticleManager(models.Manager):
|
||||||
"""
|
"""
|
||||||
Provide a query set only for "Article"
|
Provide a query set only for "Article"
|
||||||
regular fet meetings should not be contained in the news stream
|
regular fet meetings should not be contained in the news stream
|
||||||
"""
|
"""
|
||||||
def get_queryset(self):
|
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):
|
class NewsManager(models.Manager):
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return super().get_queryset().filter(~Q(is_event=True))
|
return super().get_queryset().filter(~Q(is_event=True))
|
||||||
|
|
||||||
|
|
||||||
class EventManager(models.Manager):
|
class EventManager(models.Manager):
|
||||||
"""
|
"""
|
||||||
Provide a query set only for "Events"
|
Provide a query set only for "Events"
|
||||||
regular fet meetings should not be contained in the news stream
|
regular fet meetings should not be contained in the news stream
|
||||||
"""
|
"""
|
||||||
def get_queryset(self):
|
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):
|
class FetMeetingManager(models.Manager):
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
@@ -72,6 +76,7 @@ class Category(models.Model):
|
|||||||
verbose_name = "Category"
|
verbose_name = "Category"
|
||||||
verbose_name_plural = "Categories"
|
verbose_name_plural = "Categories"
|
||||||
|
|
||||||
|
|
||||||
class Post(models.Model):
|
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_id = models.IntegerField(null=True)
|
||||||
@@ -145,7 +150,8 @@ class Post(models.Model):
|
|||||||
"find an image via another post"
|
"find an image via another post"
|
||||||
# TODO: Explain why this image is selected on save of the image
|
# 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
|
# 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:
|
if len(posts1) > 0:
|
||||||
return posts1.get().image
|
return posts1.get().image
|
||||||
|
|
||||||
@@ -172,6 +178,7 @@ class Post(models.Model):
|
|||||||
def __str__(self):
|
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 PostSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Post
|
model = Post
|
||||||
@@ -186,9 +193,10 @@ class PostSerializer(serializers.HyperlinkedModelSerializer):
|
|||||||
'image',
|
'image',
|
||||||
'event_start',
|
'event_start',
|
||||||
'event_end',
|
'event_end',
|
||||||
'is_fetsitzung'
|
'is_fetsitzung',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class News(Post):
|
class News(Post):
|
||||||
objects = NewsManager()
|
objects = NewsManager()
|
||||||
|
|
||||||
@@ -204,6 +212,7 @@ class News(Post):
|
|||||||
|
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class Event(Post):
|
class Event(Post):
|
||||||
objects = EventManager()
|
objects = EventManager()
|
||||||
|
|
||||||
@@ -218,6 +227,7 @@ class Event(Post):
|
|||||||
|
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class FetMeeting(Event):
|
class FetMeeting(Event):
|
||||||
objects = FetMeetingManager()
|
objects = FetMeetingManager()
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,8 @@ from django.utils.safestring import mark_safe
|
|||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@register.filter(is_safe=True)
|
@register.filter(is_safe=True)
|
||||||
@stringfilter
|
@stringfilter
|
||||||
def tags_to_url(value):
|
def tags_to_url(value):
|
||||||
# return "Tag to url: %s" % 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 mark_safe(re.sub(r'\#([\d\w-]+)', r'<a href="/posts/t/\g<1>">#\g<1></a>', value))
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
from django.test import TestCase
|
# from django.test import TestCase
|
||||||
|
|
||||||
# Create your tests here.
|
# Create your tests here.
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
from django.shortcuts import render
|
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_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.text import slugify
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from taggit.models import Tag
|
from taggit.models import Tag
|
||||||
from rest_framework import viewsets
|
from rest_framework import viewsets
|
||||||
from rest_framework import permissions
|
# from rest_framework import permissions
|
||||||
|
|
||||||
from .models import Post, PostSerializer
|
from .models import Post, PostSerializer
|
||||||
|
|
||||||
@@ -20,7 +20,9 @@ from collections import deque
|
|||||||
|
|
||||||
def index(request):
|
def index(request):
|
||||||
posts = deque(Post.objects.order_by('-public_date').all())
|
posts = deque(Post.objects.order_by('-public_date').all())
|
||||||
f = lambda p: p.tags
|
|
||||||
|
def f(p):
|
||||||
|
return p.tags
|
||||||
t = map(f, posts)
|
t = map(f, posts)
|
||||||
|
|
||||||
return render(request, 'posts/index.html', {"posts": posts, "tags_list": t})
|
return render(request, 'posts/index.html', {"posts": posts, "tags_list": t})
|
||||||
@@ -34,7 +36,7 @@ def tags(request,tag=""):
|
|||||||
def show(request, id=None):
|
def show(request, id=None):
|
||||||
if id.isdigit() or id is int:
|
if id.isdigit() or id is int:
|
||||||
p = Post.objects.get(id=int(id))
|
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))
|
p = Post.objects.get(slug=(id))
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
|
|||||||
@@ -5,3 +5,4 @@ Pillow
|
|||||||
djangorestframework
|
djangorestframework
|
||||||
django-static-jquery-ui
|
django-static-jquery-ui
|
||||||
docutils
|
docutils
|
||||||
|
easy-thumbnails
|
||||||
BIN
fet2020/static/Acumin-RPro.woff
Normal file
BIN
fet2020/static/Acumin-RPro.woff
Normal file
Binary file not shown.
BIN
fet2020/static/FET-Logo-2014-quadrat.png
Normal file
BIN
fet2020/static/FET-Logo-2014-quadrat.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
8911
fet2020/static/app.css
Normal file
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
22644
fet2020/static/app.js
Normal file
File diff suppressed because it is too large
Load Diff
1
fet2020/static/app.js.map
Normal file
1
fet2020/static/app.js.map
Normal file
File diff suppressed because one or more lines are too long
BIN
fet2020/static/img/logo2014_64.png
Normal file
BIN
fet2020/static/img/logo2014_64.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
162
fet2020/static/responsive-hidden-nav.js
Normal file
162
fet2020/static/responsive-hidden-nav.js
Normal 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
|
||||||
1
fet2020/static/responsive-hidden-nav.js.map
Normal file
1
fet2020/static/responsive-hidden-nav.js.map
Normal file
File diff suppressed because one or more lines are too long
@@ -32,36 +32,11 @@
|
|||||||
</a>
|
</a>
|
||||||
<div class="article-row-section">
|
<div class="article-row-section">
|
||||||
{% with post=featured_post %}
|
{% with post=featured_post %}
|
||||||
<a href="{{post.url}}">
|
{% include 'posts/partials/_article_row.html' %}
|
||||||
|
{% endwith %}
|
||||||
<article class="article-row">
|
{% with post=featured_post2 %}
|
||||||
|
{% include 'posts/partials/_article_row.html' %}
|
||||||
<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>
|
|
||||||
{% endwith %}
|
{% 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>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -74,26 +49,18 @@
|
|||||||
|
|
||||||
|
|
||||||
<div class="grid-x grid-x-padding">
|
<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 %}
|
{% for post in posts %}
|
||||||
{% include 'posts/_posts_hero.html' %}
|
{% include 'posts/partials/_posts_hero.html' %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<div class="medium-4 cell">
|
<div class="medium-4 small-12 small-order-1 medium-order-2 padding-1">
|
||||||
<div class="date-box">
|
{% for post in events %}
|
||||||
|
{% include 'posts/partials/_date_box.html' %}
|
||||||
<span class="date-badge badge primary" style="">
|
{% endfor %}
|
||||||
<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>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
<li class=""><a href="{%url 'home'%}">Aktuelles</a> </li>
|
<li class=""><a href="{%url 'home'%}">Aktuelles</a> </li>
|
||||||
<li class=""><a href="/fotos">Fotos</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>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,79 +1,46 @@
|
|||||||
{% extends 'layout.html' %}
|
{% extends 'layout.html' %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class="grid-container">
|
<div class="grid-container">
|
||||||
<div class="grid-x">
|
<h1>Mitglieder / Tätigkeiten</h1>
|
||||||
<div class="medium-8 cell">
|
|
||||||
<h1>Members</h1>
|
<!-- Nav tabs -->
|
||||||
{% for m in members %}
|
<ul class="nav nav-tabs nav-fill">
|
||||||
<div class="member-hero-text">
|
<a class="active" id="members" data-toggle="tab" href="/members">Mitglieder</a>
|
||||||
{% if m.image %}
|
<a id="members" data-toggle="tab" href="/members/A">Aktive Mitglieder</a>
|
||||||
<img src={{m.image.url}} style="width:150px;"/> </br>
|
<a id="members" data-toggle="tab" href="/members/P">Inaktive Mitglieder</a>
|
||||||
{% else %}
|
{% for job in job_group %}
|
||||||
{% endif %}
|
<a id="jobs-{{job.id}}" data-toggle="tab" href="/members/jobs/{{job.slug}}">{{job.name}}</a>
|
||||||
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 %}
|
{% endfor %}
|
||||||
<hr/>
|
</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 %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<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 %}
|
{% 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 %}
|
{% endif %}
|
||||||
{% endfor %}
|
</div>
|
||||||
{% else %}
|
</div>
|
||||||
{% 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>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
26
fet2020/templates/members/jobs_list.html
Normal file
26
fet2020/templates/members/jobs_list.html
Normal 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>
|
||||||
26
fet2020/templates/members/members_list.html
Normal file
26
fet2020/templates/members/members_list.html
Normal 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>
|
||||||
8
fet2020/templates/members/partials/_member.html
Normal file
8
fet2020/templates/members/partials/_member.html
Normal 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>
|
||||||
19
fet2020/templates/members/partials/_member_details.html
Normal file
19
fet2020/templates/members/partials/_member_details.html
Normal 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>
|
||||||
|
|
||||||
@@ -3,10 +3,12 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="grid-container">
|
<div class="grid-container">
|
||||||
|
|
||||||
|
|
||||||
<div class="grid-x">
|
<div class="grid-x">
|
||||||
<div class="medium-8 cell">
|
<div class="medium-8 cell">
|
||||||
{% for post in posts %}
|
{% for post in posts %}
|
||||||
{% include 'posts/_posts_hero.html' %}
|
{% include 'posts/partials/_posts_hero.html' %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
15
fet2020/templates/posts/partials/_article_row.html
Normal file
15
fet2020/templates/posts/partials/_article_row.html
Normal 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>
|
||||||
10
fet2020/templates/posts/partials/_date_box.html
Normal file
10
fet2020/templates/posts/partials/_date_box.html
Normal 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>
|
||||||
8
fet2020/templates/posts/partials/_posts_hero.html
Normal file
8
fet2020/templates/posts/partials/_posts_hero.html
Normal 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>
|
||||||
Reference in New Issue
Block a user