This commit is contained in:
2021-01-18 23:27:15 +00:00
46 changed files with 1164 additions and 628 deletions

View File

@@ -2,4 +2,4 @@ from django.apps import AppConfig
class AuthenticationsConfig(AppConfig): class AuthenticationsConfig(AppConfig):
name = 'authentications' name = "authentications"

View File

@@ -11,25 +11,25 @@ def authentication(username, password):
return None return None
# username format # username format
new_username = 'uid={username},ou=user,dc=fet,dc=htu,dc=tuwien,dc=ac,dc=at' new_username = "uid={username},ou=user,dc=fet,dc=htu,dc=tuwien,dc=ac,dc=at"
userdn = new_username.format(username=username) userdn = new_username.format(username=username)
server_uri = 'ldap://gagarin.fet.htu.tuwien.ac.at' server_uri = "ldap://gagarin.fet.htu.tuwien.ac.at"
server = ldap3.Server(server_uri, port=389, use_ssl=True) server = ldap3.Server(server_uri, port=389, use_ssl=True)
has_user = False has_user = False
try: try:
conn = ldap3.Connection(server, user=userdn, password=password, auto_bind=True) conn = ldap3.Connection(server, user=userdn, password=password, auto_bind=True)
conn.search('dc=fet,dc=htu,dc=tuwien,dc=ac,dc=at', '(objectclass=person)') conn.search("dc=fet,dc=htu,dc=tuwien,dc=ac,dc=at", "(objectclass=person)")
for user in sorted(conn.entries): for user in sorted(conn.entries):
if ("DN: uid=" + str(username.lower())) in str(user): if ("DN: uid=" + str(username.lower())) in str(user):
has_user = True has_user = True
except LDAPBindError as e: except LDAPBindError as e:
logger.info('Username does not exist. Error: {}'.format(e)) logger.info("Username does not exist. Error: {}".format(e))
username = None username = None
except Exception as e: except Exception as e:
logger.info('Connection to server lost. Error: {}'.format(e)) logger.info("Connection to server lost. Error: {}".format(e))
username = None username = None
if not has_user: if not has_user:

View File

@@ -4,7 +4,7 @@ from django.shortcuts import redirect
def unauthenticated_user(view_func): def unauthenticated_user(view_func):
def wrapper_func(request, *args, **kwargs): def wrapper_func(request, *args, **kwargs):
if request.user.is_authenticated: if request.user.is_authenticated:
return redirect('home') return redirect("home")
else: else:
return view_func(request, *args, **kwargs) return view_func(request, *args, **kwargs)
@@ -16,7 +16,7 @@ def authenticated_user(view_func):
if request.user.is_authenticated: if request.user.is_authenticated:
return view_func(request, *args, **kwargs) return view_func(request, *args, **kwargs)
else: else:
return redirect('login') return redirect("login")
return wrapper_func return wrapper_func

View File

@@ -3,4 +3,4 @@ from django import forms
class LoginForm(forms.Form): class LoginForm(forms.Form):
username = forms.CharField() username = forms.CharField()
password = forms.CharField(label='Passwort', widget=forms.PasswordInput()) password = forms.CharField(label="Passwort", widget=forms.PasswordInput())

View File

@@ -3,6 +3,6 @@ from . import views
urlpatterns = [ urlpatterns = [
path('login/', views.loginPage, name="login"), path("login/", views.loginPage, name="login"),
path('logout/', views.logoutUser, name="logout"), path("logout/", views.logoutUser, name="logout"),
] ]

View File

@@ -12,9 +12,9 @@ from .forms import LoginForm
@unauthenticated_user @unauthenticated_user
def loginPage(request): def loginPage(request):
if request.method == 'POST': if request.method == "POST":
username = request.POST.get('username') username = request.POST.get("username")
password = request.POST.get('password') password = request.POST.get("password")
auth_user = authentication(username, password) auth_user = authentication(username, password)
@@ -27,25 +27,25 @@ def loginPage(request):
login(request, user) login(request, user)
try: try:
return redirect(request.GET.get('next')) return redirect(request.GET.get("next"))
except: except:
return redirect('home') return redirect("home")
else: else:
messages.info(request, 'username or password is incorrect') messages.info(request, "username or password is incorrect")
form = LoginForm() form = LoginForm()
context = { context = {
"form": form, "form": form,
} }
return render(request, 'authentications/login.html', context) return render(request, "authentications/login.html", context)
@authenticated_user @authenticated_user
def logoutUser(request): def logoutUser(request):
logout(request) logout(request)
response = redirect('home') response = redirect("home")
response = del_ep_cookie(request, response) response = del_ep_cookie(request, response)
return response return response

View File

@@ -8,7 +8,7 @@ class JobPostingAdmin(admin.ModelAdmin):
form = JobPostingForm form = JobPostingForm
model = JobPosting model = JobPosting
list_display = ['companyName', 'jobName', 'salary', 'publishDate'] list_display = ["companyName", "jobName", "salary", "publishDate"]
admin.site.register(JobPosting, JobPostingAdmin) admin.site.register(JobPosting, JobPostingAdmin)

View File

@@ -2,4 +2,4 @@ from django.apps import AppConfig
class BlackboardConfig(AppConfig): class BlackboardConfig(AppConfig):
name = 'blackboard' name = "blackboard"

View File

@@ -7,19 +7,17 @@ from .models import JobPosting
class JobPostingForm(forms.ModelForm): class JobPostingForm(forms.ModelForm):
class Meta: class Meta:
model = JobPosting model = JobPosting
fields = ['companyName', 'jobName', 'salary', 'pdfLocation', 'publishDate'] fields = ["companyName", "jobName", "salary", "pdfLocation", "publishDate"]
labels = { labels = {
'companyName': _("Firmenname"), "companyName": _("Firmenname"),
'jobName': _("Berufsbezeichnung"), "jobName": _("Berufsbezeichnung"),
'salary': _("Gehalt"), "salary": _("Gehalt"),
'pdfLocation': _("Stellenausschreibung"), "pdfLocation": _("Stellenausschreibung"),
'publishDate': _("Veröffentlichung"), "publishDate": _("Veröffentlichung"),
} }
help_texts = { help_texts = {
'pdfLocation': _( "pdfLocation": _("Verwendbare Formate: PDF"),
"Verwendbare Formate: PDF" "salary": _("in Euro angeben"),
),
'salary': _("in Euro angeben"),
} }

View File

@@ -11,16 +11,23 @@ from os.path import splitext, basename
import ghostscript import ghostscript
import logging import logging
logger = logging.getLogger('blackboard')
logger = logging.getLogger("blackboard")
class JobPosting(models.Model): class JobPosting(models.Model):
companyName = models.CharField(verbose_name="Firmenname", max_length=128) companyName = models.CharField(verbose_name="Firmenname", max_length=128)
jobName = models.CharField(verbose_name="Berufsbezeichnung", max_length=128) jobName = models.CharField(verbose_name="Berufsbezeichnung", max_length=128)
salary = models.PositiveSmallIntegerField(verbose_name="Gehalt", ) salary = models.PositiveSmallIntegerField(
pdfLocation = models.FileField(verbose_name="Stellenausschreibung", upload_to='uploads/blackboard/pdf/') verbose_name="Gehalt",
)
pdfLocation = models.FileField(
verbose_name="Stellenausschreibung", upload_to="uploads/blackboard/pdf/"
)
pdf_thumb_location = models.CharField(max_length=128) pdf_thumb_location = models.CharField(max_length=128)
publishDate = models.DateField(verbose_name="Veröffentlichung", default=timezone.now) publishDate = models.DateField(
verbose_name="Veröffentlichung", default=timezone.now
)
# Managers # Managers
all_jobPosting = models.Manager() all_jobPosting = models.Manager()
@@ -40,7 +47,7 @@ class JobPosting(models.Model):
"-dDEVICEWIDTHPOINTS=600", "-dDEVICEWIDTHPOINTS=600",
"-dDEVICEHEIGHTPOINTS=800", "-dDEVICEHEIGHTPOINTS=800",
"-sOutputFile=" + jpeg_output_path, "-sOutputFile=" + jpeg_output_path,
pdf_input_path pdf_input_path,
] ]
encoding = locale.getpreferredencoding() encoding = locale.getpreferredencoding()
@@ -54,14 +61,18 @@ class JobPosting(models.Model):
if not os.path.exists(settings.MEDIA_ROOT + "uploads/blackboard/thumb/"): if not os.path.exists(settings.MEDIA_ROOT + "uploads/blackboard/thumb/"):
os.makedirs(settings.MEDIA_ROOT + "uploads/blackboard/thumb/") os.makedirs(settings.MEDIA_ROOT + "uploads/blackboard/thumb/")
pdf_thumb_location_full = settings.MEDIA_ROOT \ pdf_thumb_location_full = (
+ "uploads/blackboard/thumb/" \ settings.MEDIA_ROOT
+ splitext(basename(self.pdfLocation.name))[0] \ + "uploads/blackboard/thumb/"
+ splitext(basename(self.pdfLocation.name))[0]
+ ".jpg" + ".jpg"
)
self.pdf_thumb_location = "/files/uploads/blackboard/thumb/" \ self.pdf_thumb_location = (
+ splitext(basename(self.pdfLocation.name))[0] \ "/files/uploads/blackboard/thumb/"
+ splitext(basename(self.pdfLocation.name))[0]
+ ".jpg" + ".jpg"
)
self.pdf2jpeg(self.pdfLocation.path, pdf_thumb_location_full) self.pdf2jpeg(self.pdfLocation.path, pdf_thumb_location_full)
logger.info("SavenThumbAs: " + self.pdf_thumb_location) logger.info("SavenThumbAs: " + self.pdf_thumb_location)
@@ -70,7 +81,7 @@ class JobPosting(models.Model):
def clean(self): def clean(self):
count = 0 count = 0
for i in self.pdfLocation.name: for i in self.pdfLocation.name:
if i == '.': if i == ".":
count = count + 1 count = count + 1
if count > 1: # if more than one dot in filename if count > 1: # if more than one dot in filename
raise ValidationError(_('Keine Dateien mit >1 Punkten im Namen erlaubt.')) raise ValidationError(_("Keine Dateien mit >1 Punkten im Namen erlaubt."))

View File

@@ -4,5 +4,5 @@ from . import views
urlpatterns = [ urlpatterns = [
path('', views.index, name='blackboard'), path("", views.index, name="blackboard"),
] ]

View File

@@ -10,8 +10,8 @@ from posts.models import Post
def index(request): def index(request):
job_postings_cutoff = timezone.now().date() - timedelta(30) # 30days from now job_postings_cutoff = timezone.now().date() - timedelta(30) # 30days from now
job_postings = JobPosting.all_jobPosting.filter(publishDate__gt=job_postings_cutoff) job_postings = JobPosting.all_jobPosting.filter(publishDate__gt=job_postings_cutoff)
bb_info = Post.objects.filter(slug='blackboard').first() bb_info = Post.objects.filter(slug="blackboard").first()
bb_empty = Post.objects.filter(slug='blackboard-empty').first() bb_empty = Post.objects.filter(slug="blackboard-empty").first()
context = { context = {
"job_postings": job_postings, "job_postings": job_postings,
@@ -19,4 +19,4 @@ def index(request):
"bb_empty": bb_empty, "bb_empty": bb_empty,
} }
return render(request, 'blackboard/index.html', context) return render(request, "blackboard/index.html", context)

View File

@@ -6,6 +6,7 @@ import urllib.parse
from etherpad_lite import EtherpadLiteClient, EtherpadException from etherpad_lite import EtherpadLiteClient, EtherpadException
import logging import logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
SERVER_URL = settings.ETHERPAD_CLIENT["exturl"] SERVER_URL = settings.ETHERPAD_CLIENT["exturl"]
@@ -20,9 +21,11 @@ def get_ep_client():
apikey = f.read() apikey = f.read()
apikey = apikey.rstrip() apikey = apikey.rstrip()
epc = EtherpadLiteClient( epc = EtherpadLiteClient(
base_params={'apikey': apikey, }, base_params={
"apikey": apikey,
},
base_url=urllib.parse.urljoin(settings.ETHERPAD_CLIENT["url"], "api"), base_url=urllib.parse.urljoin(settings.ETHERPAD_CLIENT["url"], "api"),
api_version='1.2.14', api_version="1.2.14",
) )
group = epc.createGroupIfNotExistsFor(groupMapper="fet") group = epc.createGroupIfNotExistsFor(groupMapper="fet")
except Exception as e: except Exception as e:
@@ -62,7 +65,9 @@ def createPadifNotExists(padID):
# Pad doesn't exist # Pad doesn't exist
if not __checkPadExists(padID=padID): if not __checkPadExists(padID=padID):
try: try:
epc.createGroupPad(groupID=group["groupID"], padName=padID, text="helloworld") epc.createGroupPad(
groupID=group["groupID"], padName=padID, text="helloworld"
)
except EtherpadException as e: except EtherpadException as e:
logger.info("Can't create Pad '{}'. EtherpadException: {}".format(padID, e)) logger.info("Can't create Pad '{}'. EtherpadException: {}".format(padID, e))
return None return None
@@ -81,7 +86,9 @@ def getPadHTML(padID):
try: try:
text = epc.getHTML(padID=group["groupID"] + "$" + padID)["html"] text = epc.getHTML(padID=group["groupID"] + "$" + padID)["html"]
except EtherpadException as e: except EtherpadException as e:
logger.info("Can't get HTML from padID '{}'. EtherpadException: {}".format(padID, e)) logger.info(
"Can't get HTML from padID '{}'. EtherpadException: {}".format(padID, e)
)
return None return None
except Exception as e: except Exception as e:
raise e raise e
@@ -107,4 +114,6 @@ def get_pad_link(padID):
if not epc or not group: if not epc or not group:
return "#" return "#"
return urllib.parse.urljoin(settings.ETHERPAD_CLIENT["exturl"], 'p/' + group["groupID"] + '$' + str(padID)) return urllib.parse.urljoin(
settings.ETHERPAD_CLIENT["exturl"], "p/" + group["groupID"] + "$" + str(padID)
)

View File

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

View File

@@ -11,22 +11,21 @@ def __get_ep_sessionid(request):
return None, None return None, None
author = epc.createAuthorIfNotExistsFor( author = epc.createAuthorIfNotExistsFor(
name=str(request.user), name=str(request.user), authorMapper=str(request.user)
authorMapper=str(request.user) )["authorID"]
)['authorID']
expires = datetime.utcnow() + timedelta(hours=3) expires = datetime.utcnow() + timedelta(hours=3)
try: try:
result = epc.createSession( result = epc.createSession(
groupID=str(group['groupID']), groupID=str(group["groupID"]),
authorID=str(author), authorID=str(author),
validUntil=str(int(expires.timestamp())) validUntil=str(int(expires.timestamp())),
) )
except Exception as e: except Exception as e:
raise e raise e
return None, None return None, None
return result['sessionID'], expires return result["sessionID"], expires
def add_ep_cookie(request, response): def add_ep_cookie(request, response):
@@ -34,32 +33,19 @@ def add_ep_cookie(request, response):
if ep_sessid: if ep_sessid:
response.set_cookie( response.set_cookie(
"sessionID", "sessionID", ep_sessid, expires=expires, domain=".2020.fet.at", path="/"
ep_sessid,
expires=expires,
domain=".2020.fet.at",
path="/"
)
response.set_cookie(
"sessionID",
ep_sessid,
expires=expires,
path="/etherpad"
) )
response.set_cookie("sessionID", ep_sessid, expires=expires, path="/etherpad")
return response return response
def del_ep_cookie(request, response): def del_ep_cookie(request, response):
if 'sessionID' in request.COOKIES: if "sessionID" in request.COOKIES:
ep_sessionID = request.COOKIES['sessionID'] ep_sessionID = request.COOKIES["sessionID"]
epc, group = get_ep_client() epc, group = get_ep_client()
epc.deleteSession(sessionID=ep_sessionID) epc.deleteSession(sessionID=ep_sessionID)
response.delete_cookie( response.delete_cookie("sessionID", domain=".2020.fet.at", path="/")
"sessionID",
domain=".2020.fet.at",
path="/"
)
return response return response

View File

@@ -2,6 +2,6 @@ import os
from django.core.asgi import get_asgi_application from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'fet2020.settings') os.environ.setdefault("DJANGO_SETTINGS_MODULE", "fet2020.settings")
application = get_asgi_application() application = get_asgi_application()

View File

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

View File

@@ -11,23 +11,23 @@ env = environ.Env(
MYSQL_USER=(str), MYSQL_USER=(str),
MYSQL_PASSWORD=(str), MYSQL_PASSWORD=(str),
HOST_NAME=(str, "localhost"), HOST_NAME=(str, "localhost"),
ETHERPAD_PORT=(str,"9001"), ETHERPAD_PORT=(str, "9001"),
ETHERPAD_HOST=(str,"etherpad2.2020.fet.at") ETHERPAD_HOST=(str, "etherpad2.2020.fet.at"),
) )
# Prints and logs are written to console # Prints and logs are written to console
# TODO: Change before release # TODO: Change before release
LOGGING = { LOGGING = {
'version': 1, "version": 1,
'disable_existing_loggers': False, "disable_existing_loggers": False,
'handlers': { "handlers": {
'console': { "console": {
'class': 'logging.StreamHandler', "class": "logging.StreamHandler",
}, },
}, },
'root': { "root": {
'handlers': ['console'], "handlers": ["console"],
'level': 'DEBUG', "level": "DEBUG",
}, },
} }
@@ -41,106 +41,107 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/ # See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/
# SECURITY WARNING: don't run with debug turned on in production! # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = env('DEBUG') DEBUG = env("DEBUG")
if DEBUG: if DEBUG:
# SECURITY WARNING: keep the secret key used in production secret! # SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'r37-i7l)vrduzz2-gira+z#u!p!di9#f+%s*5-bb($hg)55@ns' SECRET_KEY = "r37-i7l)vrduzz2-gira+z#u!p!di9#f+%s*5-bb($hg)55@ns"
else: else:
SECRET_KEY = env('SECRET_KEY') SECRET_KEY = env("SECRET_KEY")
ALLOWED_HOSTS = ["127.0.0.1", env('HOST_NAME')] ALLOWED_HOSTS = ["127.0.0.1", env("HOST_NAME")]
HOST_NAME = env('HOST_NAME') HOST_NAME = env("HOST_NAME")
DATA_UPLOAD_MAX_MEMORY_SIZE = 1024 * 1024 * 1024 DATA_UPLOAD_MAX_MEMORY_SIZE = 1024 * 1024 * 1024
# Application definition # Application definition
CKEDITOR_UPLOAD_PATH = 'upload' CKEDITOR_UPLOAD_PATH = "upload"
INSTALLED_APPS = [ INSTALLED_APPS = [
'django.contrib.admin', "django.contrib.admin",
'django.contrib.admindocs', "django.contrib.admindocs",
'django.contrib.auth', "django.contrib.auth",
'django.contrib.contenttypes', "django.contrib.contenttypes",
'django.contrib.sessions', "django.contrib.sessions",
'django.contrib.messages', "django.contrib.messages",
'django.contrib.staticfiles', "django.contrib.staticfiles",
'taggit', "taggit",
'ckeditor', "ckeditor",
'ckeditor_uploader', "ckeditor_uploader",
'easy_thumbnails', "easy_thumbnails",
'rest_framework', "rest_framework",
'softhyphen', "softhyphen",
'django_crontab', "django_crontab",
'django_filters', "django_filters",
'django_static_jquery_ui', "django_static_jquery_ui",
'posts.apps.PostsConfig', "posts.apps.PostsConfig",
'members.apps.MembersConfig', "members.apps.MembersConfig",
'documents.apps.DocumentsConfig', "documents.apps.DocumentsConfig",
'blackboard.apps.BlackboardConfig', "blackboard.apps.BlackboardConfig",
'tasks.apps.TasksConfig', "tasks.apps.TasksConfig",
] ]
MIDDLEWARE = [ MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware', "django.middleware.security.SecurityMiddleware",
'django.contrib.sessions.middleware.SessionMiddleware', "django.contrib.sessions.middleware.SessionMiddleware",
'django.middleware.locale.LocaleMiddleware', "django.middleware.locale.LocaleMiddleware",
'django.middleware.common.CommonMiddleware', "django.middleware.common.CommonMiddleware",
'django.middleware.csrf.CsrfViewMiddleware', "django.middleware.csrf.CsrfViewMiddleware",
'django.contrib.auth.middleware.AuthenticationMiddleware', "django.contrib.auth.middleware.AuthenticationMiddleware",
'django.contrib.messages.middleware.MessageMiddleware', "fet2020.middleware.FETHeaderMiddleware",
'django.middleware.clickjacking.XFrameOptionsMiddleware', "django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
] ]
ROOT_URLCONF = 'fet2020.urls' ROOT_URLCONF = "fet2020.urls"
TEMPLATES = [ TEMPLATES = [
{ {
'BACKEND': 'django.template.backends.django.DjangoTemplates', "BACKEND": "django.template.backends.django.DjangoTemplates",
'DIRS': [ "DIRS": [
os.path.join(BASE_DIR, 'templates'), os.path.join(BASE_DIR, "templates"),
], ],
'APP_DIRS': True, "APP_DIRS": True,
'OPTIONS': { "OPTIONS": {
'context_processors': [ "context_processors": [
'django.template.context_processors.debug', "django.template.context_processors.debug",
'django.template.context_processors.request', "django.template.context_processors.request",
'django.contrib.auth.context_processors.auth', "django.contrib.auth.context_processors.auth",
'django.contrib.messages.context_processors.messages', "django.contrib.messages.context_processors.messages",
'django.template.context_processors.i18n', "django.template.context_processors.i18n",
], ],
}, },
}, },
] ]
WSGI_APPLICATION = 'fet2020.wsgi.application' WSGI_APPLICATION = "fet2020.wsgi.application"
# Database # Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases # https://docs.djangoproject.com/en/3.0/ref/settings/#databases
if DEBUG: if DEBUG:
DATABASES = { DATABASES = {
'default': { "default": {
'ENGINE': 'django.db.backends.sqlite3', "ENGINE": "django.db.backends.sqlite3",
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), "NAME": os.path.join(BASE_DIR, "db.sqlite3"),
} }
} }
else: else:
DATABASES = { DATABASES = {
'default': { "default": {
'ENGINE': 'django.db.backends.mysql', "ENGINE": "django.db.backends.mysql",
'NAME': env('MYSQL_DATABASE'), "NAME": env("MYSQL_DATABASE"),
'USER': env('MYSQL_USER'), "USER": env("MYSQL_USER"),
'PASSWORD': env('MYSQL_PASSWORD'), "PASSWORD": env("MYSQL_PASSWORD"),
'HOST': env('MYSQL_HOST'), "HOST": env("MYSQL_HOST"),
'PORT': env('MYSQL_PORT') "PORT": env("MYSQL_PORT"),
} }
} }
AUTHENTICATION_BACKENDS = [ AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend', "django.contrib.auth.backends.ModelBackend",
] ]
# Password validation # Password validation
@@ -148,16 +149,16 @@ AUTHENTICATION_BACKENDS = [
AUTH_PASSWORD_VALIDATORS = [ AUTH_PASSWORD_VALIDATORS = [
{ {
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
}, },
{ {
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
}, },
{ {
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
}, },
{ {
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
}, },
] ]
@@ -165,9 +166,9 @@ AUTH_PASSWORD_VALIDATORS = [
# Internationalization # Internationalization
# https://docs.djangoproject.com/en/3.0/topics/i18n/ # https://docs.djangoproject.com/en/3.0/topics/i18n/
LANGUAGE_CODE = 'de-at' LANGUAGE_CODE = "de-at"
TIME_ZONE = 'CET' TIME_ZONE = "CET"
USE_I18N = True USE_I18N = True
@@ -175,32 +176,32 @@ USE_L10N = True
USE_TZ = True USE_TZ = True
LOCALE_PATHS = [os.path.join(BASE_DIR, 'locale')]
# Static files (CSS, JavaScript, Images) # Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/ # https://docs.djangoproject.com/en/3.0/howto/static-files/
STATIC_URL = '/assets/' STATIC_URL = "/assets/"
STATICFILES_DIRS = [ STATICFILES_DIRS = [os.path.join(BASE_DIR, "static")]
os.path.join(BASE_DIR, "static") STATIC_ROOT = "assets/"
] MEDIA_ROOT = os.path.join(BASE_DIR, "files/")
STATIC_ROOT = 'assets/' MEDIA_URL = "/files/"
MEDIA_ROOT = os.path.join(BASE_DIR, 'files/')
MEDIA_URL = '/files/'
TAGGIT_FORCE_LOWERCASE = True TAGGIT_FORCE_LOWERCASE = True
CKEDITOR_CONFIGS = { CKEDITOR_CONFIGS = {
'default': { "default": {
'stylesSet': [ "stylesSet": [
{ {
"name": 'Überschrift 2', "name": "Überschrift 2",
"element": 'h2', "element": "h2",
"attributes": {}, "attributes": {},
}, },
{ {
"name": 'Code', "name": "Code",
"element": 'code', "element": "code",
"attributes": {"class": "code-block"}, "attributes": {"class": "code-block"},
}, },
], ],
@@ -209,41 +210,41 @@ CKEDITOR_CONFIGS = {
# THUMBNAIL # THUMBNAIL
THUMBNAIL_ALIASES = { THUMBNAIL_ALIASES = {
'': { "": {
'avatar': {'size': (50, 50), 'crop': True}, "avatar": {"size": (50, 50), "crop": True},
'thumb': {'size': (150, 150), 'crop': True}, "thumb": {"size": (150, 150), "crop": True},
}, },
} }
# ETHERPAD CLIENT # ETHERPAD CLIENT
if DEBUG: if DEBUG:
ETHERPAD_CLIENT = { ETHERPAD_CLIENT = {
'url': "http://etherpad:"+env('ETHERPAD_PORT'), "url": "http://etherpad:" + env("ETHERPAD_PORT"),
'exturl': env('ETHERPAD_HOST'), "exturl": env("ETHERPAD_HOST"),
'apikey': "/srv/etherpad/APIKEY.txt" "apikey": "/srv/etherpad/APIKEY.txt",
} }
else: else:
ETHERPAD_CLIENT = { ETHERPAD_CLIENT = {
'url': "http://etherpad:"+env('ETHERPAD_PORT'), "url": "http://etherpad:" + env("ETHERPAD_PORT"),
'exturl': urljoin('https://' + env('HOST_NAME'),"etherpad/"), "exturl": urljoin("https://" + env("HOST_NAME"), "etherpad/"),
'apikey': "/app/etherpad/APIKEY.txt" "apikey": "/app/etherpad/APIKEY.txt",
} }
# REST FRAMEWORK # REST FRAMEWORK
REST_FRAMEWORK={ REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES_CLASSES':[ "DEFAULT_PERMISSION_CLASSES_CLASSES": [
'rest_framework.permissions.AllowAny', "rest_framework.permissions.AllowAny",
], ],
'DEFAULT_AUTHENTICATION_CLASSES':() "DEFAULT_AUTHENTICATION_CLASSES": (),
} }
# DJANGO MAIL # DJANGO MAIL
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = 'buran.htu.tuwien.ac.at' EMAIL_HOST = "buran.htu.tuwien.ac.at"
EMAIL_PORT = 587 EMAIL_PORT = 587
EMAIL_USE_TLS = True EMAIL_USE_TLS = True
# CRON JOBS # CRON JOBS
CRONJOBS = [ CRONJOBS = [
('0 16 * * *', 'posts.cronjobs.check_to_send_agenda_mail'), ("0 16 * * *", "posts.cronjobs.check_to_send_agenda_mail"),
] ]

View File

@@ -6,29 +6,34 @@ from django.views.generic import RedirectView
from . import views from . import views
from posts.viewsets import PostViewSet from posts.viewsets import PostViewSet
from members.urls import member_urlpatterns, jobs_urlpatterns from members.urls import member_urlpatterns, jobs_urlpatterns
from members.viewsets import MemberViewSet, JobViewSet, JobGroupViewSet, JobMemberViewSet from members.viewsets import (
MemberViewSet,
JobViewSet,
JobGroupViewSet,
JobMemberViewSet,
)
from rest_framework import routers from rest_framework import routers
router = routers.DefaultRouter() router = routers.DefaultRouter()
router.register(r'posts', PostViewSet) router.register(r"posts", PostViewSet)
router.register(r'members', MemberViewSet) router.register(r"members", MemberViewSet)
router.register(r'jobgroups', JobGroupViewSet) router.register(r"jobgroups", JobGroupViewSet)
router.register(r'jobs', JobViewSet) router.register(r"jobs", JobViewSet)
router.register(r'jobmembers', JobMemberViewSet) router.register(r"jobmembers", JobMemberViewSet)
urlpatterns = [ urlpatterns = [
path('posts/', include('posts.urls')), path("posts/", include("posts.urls")),
path('admin/doc/', include('django.contrib.admindocs.urls')), path("admin/doc/", include("django.contrib.admindocs.urls")),
path('admin/login/', RedirectView.as_view(pattern_name='login')), path("admin/login/", RedirectView.as_view(pattern_name="login")),
path('admin/', admin.site.urls), path("admin/", admin.site.urls),
path('auth/', include('authentications.urls')), path("auth/", include("authentications.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'), name='members'), path("members/", include("members.urls"), name="members"),
path('jobs/', include(jobs_urlpatterns), name='jobs'), path("jobs/", include(jobs_urlpatterns), name="jobs"),
path('member/', include(member_urlpatterns), name='member'), path("member/", include(member_urlpatterns), name="member"),
path('blackboard/', include('blackboard.urls'), name='blackboard'), path("blackboard/", include("blackboard.urls"), name="blackboard"),
path('tasks/', include('tasks.urls'), name='tasks'), path("tasks/", include("tasks.urls"), name="tasks"),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

View File

@@ -1,4 +1,5 @@
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, FetMeeting, Event from posts.models import Post, FetMeeting, Event
@@ -34,12 +35,12 @@ def index(request):
featured_meeting = FetMeeting.objects.get_meetings() featured_meeting = FetMeeting.objects.get_meetings()
context = { context = {
'posts': deque(list(posts)[:5]), "posts": deque(list(posts)[:5]),
'events': Event.all_events.get_five_events(), "events": Event.all_events.get_five_events(),
'featured_post': featured_post, "featured_post": featured_post,
'featured_event': featured_event, "featured_event": featured_event,
'featured_meeting': featured_meeting, "featured_meeting": featured_meeting,
'tags_list': " ".join(t) "tags_list": " ".join(t),
} }
return render(request, 'home.html', context) return render(request, "home.html", context)

View File

@@ -2,6 +2,6 @@ import os
from django.core.wsgi import get_wsgi_application from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'fet2020.settings') os.environ.setdefault("DJANGO_SETTINGS_MODULE", "fet2020.settings")
application = get_wsgi_application() application = get_wsgi_application()

Binary file not shown.

View File

@@ -0,0 +1,346 @@
# Translation for Austrian German 'de_AT'. You have to use 'de' because Django doesn't support 'de_AT'.
msgid ""
msgstr ""
"Project-Id-Version: fet2020\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-01-17 12:57+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FET\n"
"Language-Team: German\n"
"Language: de_AT\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: blackboard/forms.py:13
msgid "Firmenname"
msgstr ""
#: blackboard/forms.py:14
msgid "Berufsbezeichnung"
msgstr ""
#: blackboard/forms.py:15
msgid "Gehalt"
msgstr ""
#: blackboard/forms.py:16
msgid "Stellenausschreibung"
msgstr ""
#: blackboard/forms.py:17 posts/forms.py:55 posts/forms.py:109
msgid "Veröffentlichung"
msgstr ""
#: blackboard/forms.py:21
msgid "Verwendbare Formate: PDF"
msgstr ""
#: blackboard/forms.py:22
msgid "in Euro angeben"
msgstr ""
#: blackboard/models.py:87
msgid "Keine Dateien mit >1 Punkten im Namen erlaubt."
msgstr ""
#: members/admin.py:9
msgid "Rolle"
msgstr ""
#: members/admin.py:14
msgid "Aktiv"
msgstr ""
#: members/admin.py:15 members/models.py:107
msgid "Pension"
msgstr ""
#: members/forms.py:29
msgid "Beschreibung zu der Person"
msgstr ""
#: members/forms.py:30
msgid "Porträt"
msgstr ""
#: members/forms.py:31
msgid "Geburtstag"
msgstr ""
#: members/forms.py:32
msgid "Telefonnummer"
msgstr ""
#: members/forms.py:33
msgid "Wohnadresse"
msgstr ""
#: members/forms.py:37
msgid "Mindestgröße: 150*150 px, Verwendbare Formate: ..."
msgstr ""
#: members/forms.py:38
msgid "Die Mailadresse mit '@fet.at' angeben."
msgstr ""
#: members/forms.py:53
msgid "Kürzel der Tätigkeit"
msgstr ""
#: members/forms.py:54
msgid "Tätigkeitsbereich"
msgstr ""
#: members/forms.py:72
msgid "Kürzel des Tätigkeitsbereichs"
msgstr ""
#: members/forms.py:73
msgid "Beschreibung des Tätigkeitsbereichs"
msgstr ""
#: members/forms.py:75
msgid ""
"Dieser Tätigkeitsbereich soll im Fachschaftsbereich angeheftet werden, damit "
"es sofort ersichtlich ist."
msgstr ""
#: members/models.py:106
msgid "Active"
msgstr ""
#: members/models.py:144
msgid "Es fehlt das Profilbild."
msgstr ""
#: members/models.py:148
msgid "Das Bild ist zu klein. (Höhe: {}, Breite: {})"
msgstr ""
#: members/models.py:154
msgid "In der Mailadresse fehlt die Domäne."
msgstr ""
#: members/models.py:234
msgid "VorsitzendeR"
msgstr ""
#: members/models.py:235
msgid "stv VorsitzendeR"
msgstr ""
#: members/models.py:236
msgid "2. stv VorsitzendeR"
msgstr ""
#: members/models.py:237
msgid "VerantwortlicheR"
msgstr ""
#: members/models.py:238
msgid "Mitglied"
msgstr ""
#: members/models.py:239
msgid "Ersatzmitglied"
msgstr ""
#: posts/admin.py:27
#, python-format
msgid "Das Agenda konnte nicht erstellt werden. Error: %s"
msgstr ""
#: posts/admin.py:37
#, python-format
msgid "Das Protokoll konnte nicht erstellt werden. Error: %s"
msgstr ""
#: posts/admin.py:52
#, python-format
msgid "Das Event %s wurde erfolgreich in eine FET Sitzung konvertiert."
msgstr ""
#: posts/forms.py:50 posts/forms.py:101 tasks/forms.py:19
msgid "Titel"
msgstr ""
#: posts/forms.py:51 posts/forms.py:102
msgid "Untertitel"
msgstr ""
#: posts/forms.py:52 posts/forms.py:103
msgid "Hintergrundbild"
msgstr ""
#: posts/forms.py:53 posts/forms.py:104
msgid "Text"
msgstr ""
#: posts/forms.py:54 posts/forms.py:108
msgid "Autor"
msgstr ""
#: posts/forms.py:56
msgid "Post anheften"
msgstr ""
#: posts/forms.py:57
msgid "Post verstecken"
msgstr ""
#: posts/forms.py:62 posts/forms.py:115 posts/forms.py:153
msgid ""
"Die Hashtags ohne '#' eintragen, und mit Komma kann man mehrere Tags anfügen."
msgstr ""
#: posts/forms.py:64
msgid "Verwendbare Formate: ..."
msgstr ""
#: posts/forms.py:66
msgid "Dieser Post soll an die Startseite als erster Post angeheftet werden."
msgstr ""
#: posts/forms.py:69
msgid "Dieser Post soll im News Feed nicht auftauchen, z.B. Impressum."
msgstr ""
#: posts/forms.py:105
msgid "Start des Events"
msgstr ""
#: posts/forms.py:106
msgid "Ende des Events"
msgstr ""
#: posts/forms.py:107
msgid "Ort des Events"
msgstr ""
#: posts/forms.py:110
msgid "Event anheften"
msgstr ""
#: posts/forms.py:117
msgid "Verwendbare Formate: "
msgstr ""
#: posts/forms.py:119
msgid "Dieses Event soll an die Startseite als erster Post angeheftet werden."
msgstr ""
#: posts/forms.py:145
msgid "Start der Sitzung"
msgstr ""
#: posts/forms.py:146
msgid "Ende der Sitzung"
msgstr ""
#: posts/models.py:86
msgid "News"
msgstr ""
#: posts/models.py:86
msgid "Event"
msgstr ""
#: posts/models.py:86
msgid "FetMeeting"
msgstr ""
#: posts/models.py:258
msgid "Das Ende des Events liegt vor dem Beginn."
msgstr ""
#: posts/models.py:318
msgid "Das Datum des Events fehlt."
msgstr ""
#: posts/models.py:349
msgid "Es existiert bereits eine Sitzung mit demselben Datum."
msgstr ""
#: tasks/forms.py:20
msgid "Aufgabenbereich"
msgstr ""
#: tasks/forms.py:21
msgid "Fälligkeit"
msgstr ""
#: tasks/forms.py:22
msgid "Abgeschlossen"
msgstr ""
#: tasks/forms.py:23
msgid "Datum der Fertigstellung"
msgstr ""
#: tasks/forms.py:24 tasks/forms.py:52
msgid "Zuweisen an"
msgstr ""
#: tasks/forms.py:25
msgid "Notizen"
msgstr ""
#: tasks/forms.py:26
msgid "Priorität"
msgstr ""
#: tasks/forms.py:49
msgid "Titel des Tasks"
msgstr ""
#: tasks/forms.py:50
msgid "Task-Gruppe"
msgstr ""
#: tasks/forms.py:51
msgid "Fälligkeitsdatum"
msgstr ""
#: templates/admin/base.html:8
msgid "Welcome,"
msgstr ""
#: templates/admin/base.html:18
msgid "Documentation"
msgstr ""
#: templates/admin/base.html:22
msgid "Change password"
msgstr ""
#: templates/admin/base.html:24
msgid "Log out"
msgstr ""
#: templates/admin/submit_line.html:5
msgid "Close"
msgstr ""
#: templates/documents/base.html:17
msgid "profile"
msgstr ""
#: templates/documents/base.html:18
msgid "logout"
msgstr ""
msgid "January"
msgstr "Jänner"
msgid "jan"
msgstr "Jän"
msgctxt "abbrev. month"
msgid "Jan."
msgstr "Jän."
msgctxt "alt. month"
msgid "January"
msgstr "Jänner"

View File

@@ -6,13 +6,13 @@ from .forms import MemberForm, JobForm, JobGroupForm
class MemberRoleFilter(admin.SimpleListFilter): class MemberRoleFilter(admin.SimpleListFilter):
title = _('Rolle') title = _("Rolle")
parameter_name = 'role' parameter_name = "role"
def lookups(self, request, model_admin): def lookups(self, request, model_admin):
return ( return (
('A', _('Aktiv')), ("A", _("Aktiv")),
('P', _('Pension')), ("P", _("Pension")),
) )
def queryset(self, request, queryset): def queryset(self, request, queryset):
@@ -55,40 +55,53 @@ class MemberAdmin(admin.ModelAdmin):
form = MemberForm form = MemberForm
model = Member model = Member
fieldsets = ( fieldsets = (
(None, { (
'fields': ( None,
('firstname', 'surname',), {
'nickname', "fields": (
'username', (
'mailaccount', "firstname",
'role', "surname",
'description', ),
'image', "nickname",
'birthday', "username",
'phone', "mailaccount",
'address', "role",
) "description",
}), "image",
"birthday",
"phone",
"address",
)
},
),
) )
inlines = (JobOverviewInline,) inlines = (JobOverviewInline,)
list_display = ['nickname', 'firstname', 'surname', 'mailaccount', 'role'] list_display = ["nickname", "firstname", "surname", "mailaccount", "role"]
ordering = ['firstname', ] ordering = [
search_fields = ['firstname', 'surname', 'nickname', 'mailaccount'] "firstname",
]
search_fields = ["firstname", "surname", "nickname", "mailaccount"]
list_filter = [MemberRoleFilter] list_filter = [MemberRoleFilter]
def add_view(self, request, form_url='', extra_context=None): def add_view(self, request, form_url="", extra_context=None):
extra_context = extra_context or {} extra_context = extra_context or {}
extra_context['help_text'] = "Fette Schriften sind Pflichtfelder." extra_context["help_text"] = "Fette Schriften sind Pflichtfelder."
return super().add_view( return super().add_view(
request, form_url, extra_context=extra_context, request,
form_url,
extra_context=extra_context,
) )
def change_view(self, request, object_id, form_url='', extra_context=None): def change_view(self, request, object_id, form_url="", extra_context=None):
extra_context = extra_context or {} extra_context = extra_context or {}
extra_context['help_text'] = "Fette Schriften sind Pflichtfelder." extra_context["help_text"] = "Fette Schriften sind Pflichtfelder."
return super().change_view( return super().change_view(
request, object_id, form_url, extra_context=extra_context, request,
object_id,
form_url,
extra_context=extra_context,
) )
def save_model(self, request, obj, form, change): def save_model(self, request, obj, form, change):
@@ -101,22 +114,33 @@ class JobAdmin(admin.ModelAdmin):
model = Job model = Job
inlines = (ActiveMemberInline, InactiveMemberInline) inlines = (ActiveMemberInline, InactiveMemberInline)
list_display = ['name', ] list_display = [
ordering = ['name', ] "name",
search_fields = ['name', ] ]
ordering = [
"name",
]
search_fields = [
"name",
]
def add_view(self, request, form_url='', extra_context=None): def add_view(self, request, form_url="", extra_context=None):
extra_context = extra_context or {} extra_context = extra_context or {}
extra_context['help_text'] = "Fette Schriften sind Pflichtfelder." extra_context["help_text"] = "Fette Schriften sind Pflichtfelder."
return super().add_view( return super().add_view(
request, form_url, extra_context=extra_context, request,
form_url,
extra_context=extra_context,
) )
def change_view(self, request, object_id, form_url='', extra_context=None): def change_view(self, request, object_id, form_url="", extra_context=None):
extra_context = extra_context or {} extra_context = extra_context or {}
extra_context['help_text'] = "Fette Schriften sind Pflichfelder." extra_context["help_text"] = "Fette Schriften sind Pflichfelder."
return super().change_view( return super().change_view(
request, object_id, form_url, extra_context=extra_context, request,
object_id,
form_url,
extra_context=extra_context,
) )
def save_model(self, request, obj, form, change): def save_model(self, request, obj, form, change):
@@ -127,24 +151,36 @@ class JobAdmin(admin.ModelAdmin):
class JobGroupAdmin(admin.ModelAdmin): class JobGroupAdmin(admin.ModelAdmin):
form = JobGroupForm form = JobGroupForm
model = JobGroup model = JobGroup
inlines = (JobInline, ) inlines = (JobInline,)
list_display = ['name', 'is_pinned', ] list_display = [
ordering = ['name', ] "name",
search_fields = ['name', ] "is_pinned",
]
ordering = [
"name",
]
search_fields = [
"name",
]
def add_view(self, request, form_url='', extra_context=None): def add_view(self, request, form_url="", extra_context=None):
extra_context = extra_context or {} extra_context = extra_context or {}
extra_context['help_text'] = "Fette Schriften sind Pflichtfelder." extra_context["help_text"] = "Fette Schriften sind Pflichtfelder."
return super().add_view( return super().add_view(
request, form_url, extra_context=extra_context, request,
form_url,
extra_context=extra_context,
) )
def change_view(self, request, object_id, form_url='', extra_context=None): def change_view(self, request, object_id, form_url="", extra_context=None):
extra_context = extra_context or {} extra_context = extra_context or {}
extra_context['help_text'] = "Fette Schriften sind Pflichfelder." extra_context["help_text"] = "Fette Schriften sind Pflichfelder."
return super().change_view( return super().change_view(
request, object_id, form_url, extra_context=extra_context, request,
object_id,
form_url,
extra_context=extra_context,
) )
def save_model(self, request, obj, form, change): def save_model(self, request, obj, form, change):

View File

@@ -2,4 +2,4 @@ from django.apps import AppConfig
class MembersConfig(AppConfig): class MembersConfig(AppConfig):
name = 'members' name = "members"

View File

@@ -10,56 +10,68 @@ class MemberForm(forms.ModelForm):
class Meta: class Meta:
model = Member model = Member
fields = [ fields = [
'firstname', 'surname', 'nickname', 'username', 'mailaccount', 'role', 'description', "firstname",
'image', 'birthday', 'phone', 'address', "surname",
"nickname",
"username",
"mailaccount",
"role",
"description",
"image",
"birthday",
"phone",
"address",
] ]
widgets = { widgets = {"description": CKEditorUploadingWidget(config_name="default")}
'description': CKEditorUploadingWidget(config_name='default')
}
labels = { labels = {
'description': _("Beschreibung zu der Person"), "description": _("Beschreibung zu der Person"),
'image': _("Porträt"), "image": _("Porträt"),
'birthday': _("Geburtstag"), "birthday": _("Geburtstag"),
'phone': _("Telefonnummer"), "phone": _("Telefonnummer"),
'address': _("Wohnadresse"), "address": _("Wohnadresse"),
} }
help_texts = { help_texts = {
'image': _( "image": _("Mindestgröße: 150*150 px, Verwendbare Formate: ..."),
"Mindestgröße: 150*150 px, Verwendbare Formate: ..." "mailaccount": _("Die Mailadresse mit '@fet.at' angeben."),
),
'mailaccount': _(
"Die Mailadresse mit '@fet.at' angeben."
),
} }
class JobForm(forms.ModelForm): class JobForm(forms.ModelForm):
class Meta: class Meta:
model = Job model = Job
fields = ['name', 'shortterm', 'slug', 'job_group',] fields = [
"name",
"shortterm",
"slug",
"job_group",
]
labels = { labels = {
'shortterm': _("Kürzel der Tätigkeit"), "shortterm": _("Kürzel der Tätigkeit"),
'job_group': _("Tätigkeitsbereich"), "job_group": _("Tätigkeitsbereich"),
} }
class JobGroupForm(forms.ModelForm): class JobGroupForm(forms.ModelForm):
class Meta: class Meta:
model = JobGroup model = JobGroup
fields = ['name', 'shortterm', 'slug', 'description', 'is_pinned',] fields = [
"name",
"shortterm",
"slug",
"description",
"is_pinned",
]
widgets = { widgets = {"description": CKEditorUploadingWidget(config_name="default")}
'description': CKEditorUploadingWidget(config_name='default')
}
labels = { labels = {
'shortterm': _("Kürzel des Tätigkeitsbereichs"), "shortterm": _("Kürzel des Tätigkeitsbereichs"),
'description': _("Beschreibung des Tätigkeitsbereichs"), "description": _("Beschreibung des Tätigkeitsbereichs"),
'is_pinned': _( "is_pinned": _(
"Dieser Tätigkeitsbereich soll im Fachschaftsbereich angeheftet werden, damit es sofort ersichtlich ist." "Dieser Tätigkeitsbereich soll im Fachschaftsbereich angeheftet werden, damit es sofort ersichtlich ist."
), ),
} }

View File

@@ -10,15 +10,20 @@ from easy_thumbnails.fields import ThumbnailerImageField
class ActiveJobMemberManager(models.Manager): class ActiveJobMemberManager(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_all_by_slug(self, slug): def get_all_by_slug(self, slug):
return self.get_queryset().filter(job__job_group__slug=slug).order_by('job__slug', 'job_role', 'member__firstname') return (
self.get_queryset()
.filter(job__job_group__slug=slug)
.order_by("job__slug", "job_role", "member__firstname")
)
def get_queryset(self): def get_queryset(self):
date_today = timezone.now().date() date_today = timezone.now().date()
qs = super().get_queryset().order_by('member__firstname') qs = super().get_queryset().order_by("member__firstname")
return qs.filter( return qs.filter(
Q(member__role=Member.MemberRole.ACTIVE) Q(member__role=Member.MemberRole.ACTIVE)
@@ -27,15 +32,20 @@ class ActiveJobMemberManager(models.Manager):
class InactiveJobMemberManager(models.Manager): class InactiveJobMemberManager(models.Manager):
''' """
return a list of inactive member return a list of inactive member
''' """
def get_all_by_slug(self, slug): def get_all_by_slug(self, slug):
return self.get_queryset().filter(job__job_group__slug=slug).order_by('job__slug', 'job_role', 'member__firstname') return (
self.get_queryset()
.filter(job__job_group__slug=slug)
.order_by("job__slug", "job_role", "member__firstname")
)
def get_queryset(self): def get_queryset(self):
date_today = timezone.now().date() date_today = timezone.now().date()
qs = super().get_queryset().order_by('member__firstname') qs = super().get_queryset().order_by("member__firstname")
return qs.filter( return qs.filter(
Q(member__role=Member.MemberRole.PENSION) Q(member__role=Member.MemberRole.PENSION)
@@ -45,7 +55,7 @@ class InactiveJobMemberManager(models.Manager):
class JobMemberManager(models.Manager): class JobMemberManager(models.Manager):
def get_members(self, role): def get_members(self, role):
qs = self.get_queryset().order_by('member__firstname') qs = self.get_queryset().order_by("member__firstname")
return qs.filter(Q(member__role=role)) return qs.filter(Q(member__role=role))
@@ -82,19 +92,19 @@ class JobGroupManager(models.Manager):
class MemberManager(models.Manager): class MemberManager(models.Manager):
def get_queryset(self): def get_queryset(self):
return super().get_queryset().order_by('firstname') return super().get_queryset().order_by("firstname")
class Member(models.Model): class Member(models.Model):
firstname = models.CharField("Vorname", max_length=128) firstname = models.CharField("Vorname", max_length=128)
surname = models.CharField("Nachname", max_length=128) surname = models.CharField("Nachname", max_length=128)
nickname = models.CharField("Spitzname", max_length=128) nickname = models.CharField("Spitzname", max_length=128)
username = models.CharField("Benutzername", blank=True, max_length=128) username = models.CharField("Benutzername", blank=True, max_length=128)
mailaccount = models.CharField("Mailadresse", unique=True, max_length=128) mailaccount = models.CharField("Mailadresse", unique=True, max_length=128)
class MemberRole(models.TextChoices): class MemberRole(models.TextChoices):
ACTIVE = 'A', _('Active') ACTIVE = "A", _("Active")
PENSION = 'P', _('Pension') PENSION = "P", _("Pension")
role = models.CharField( role = models.CharField(
"Rolle", "Rolle",
@@ -104,14 +114,16 @@ class Member(models.Model):
) )
description = models.TextField(null=True, blank=True) description = models.TextField(null=True, blank=True)
image = ThumbnailerImageField(upload_to='uploads/members/image/') image = ThumbnailerImageField(upload_to="uploads/members/image/")
birthday = models.DateField(null=True, blank=True) birthday = models.DateField(null=True, blank=True)
phone_error_msg = _(( phone_error_msg = _(
"Phone number must be entered in the format: +999999999'. Up to 15 digits allowed." (
)) "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_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)
address = models.TextField(null=True, blank=True) address = models.TextField(null=True, blank=True)
@@ -134,15 +146,12 @@ class Member(models.Model):
if self.image.height < 150 or self.image.width < 150: if self.image.height < 150 or self.image.width < 150:
raise ValidationError( raise ValidationError(
_("Das Bild ist zu klein. (Höhe: {}, Breite: {})").format( _("Das Bild ist zu klein. (Höhe: {}, Breite: {})").format(
self.image.height, self.image.height, self.image.width
self.image.width
) )
) )
if not "@fet.at" in self.mailaccount: if not "@fet.at" in self.mailaccount:
raise ValidationError( raise ValidationError(_("In der Mailadresse fehlt die Domäne."))
_("In der Mailadresse fehlt die Domäne.")
)
def __str__(self): def __str__(self):
return self.firstname + " " + self.surname return self.firstname + " " + self.surname
@@ -198,7 +207,7 @@ class Job(models.Model):
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
if not self.slug: if not self.slug:
self.slug = slugify(self.shortterm) self.slug = slugify(self.shortterm)
#if type(self.job_group) = str: # if type(self.job_group) = str:
# self.job_group=JobGroup.objects.filter(slug=self.job) # self.job_group=JobGroup.objects.filter(slug=self.job)
super().save(*args, **kwargs) super().save(*args, **kwargs)
@@ -218,18 +227,20 @@ class JobMember(models.Model):
verbose_name="Tätigkeit", verbose_name="Tätigkeit",
) )
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)
class JobRole(models.TextChoices): class JobRole(models.TextChoices):
PRESIDENT = ('10', _('VorsitzendeR')) PRESIDENT = ("10", _("VorsitzendeR"))
VICE_PRESIDENT = ('20', _('stv VorsitzendeR')) VICE_PRESIDENT = ("20", _("stv VorsitzendeR"))
SECOND_VICE_PRESIDENT = ('30', _('2. stv VorsitzendeR')) SECOND_VICE_PRESIDENT = ("30", _("2. stv VorsitzendeR"))
PERSON_RESPONSIBLE = ('40', _('VerantwortlicheR')) PERSON_RESPONSIBLE = ("40", _("VerantwortlicheR"))
MEMBER = ('50', _('Mitglied')) MEMBER = ("50", _("Mitglied"))
SUBSTITUTE_MEMBER = ('60', _('Ersatzmitglied')) SUBSTITUTE_MEMBER = ("60", _("Ersatzmitglied"))
job_role = models.CharField(max_length=2, choices=JobRole.choices, default=JobRole.MEMBER) job_role = models.CharField(
max_length=2, choices=JobRole.choices, default=JobRole.MEMBER
)
objects = models.Manager() objects = models.Manager()
members = JobMemberManager() members = JobMemberManager()

View File

@@ -4,65 +4,50 @@ from rest_framework import serializers
class MemberSerializer(serializers.HyperlinkedModelSerializer): class MemberSerializer(serializers.HyperlinkedModelSerializer):
class Meta: class Meta:
model = Member model = Member
fields = ['id', fields = [
'firstname', "id",
'surname', "firstname",
'nickname', "surname",
'mailaccount', "nickname",
'role', "mailaccount",
'description', "role",
'image', "description",
'birthday', "image",
"birthday",
] ]
class JobGroupSerializer(serializers.HyperlinkedModelSerializer): class JobGroupSerializer(serializers.HyperlinkedModelSerializer):
class Meta: class Meta:
model = JobGroup model = JobGroup
fields = [ fields = ["id", "name", "shortterm", "slug"]
'id',
'name',
'shortterm',
'slug'
]
class JobSerializer(serializers.HyperlinkedModelSerializer): class JobSerializer(serializers.HyperlinkedModelSerializer):
#job_group = JobGroupSerializer() # job_group = JobGroupSerializer()
job_group = serializers.SlugRelatedField( job_group = serializers.SlugRelatedField(
slug_field='slug',queryset = JobGroup.objects slug_field="slug", queryset=JobGroup.objects
) )
class Meta: class Meta:
model = Job model = Job
fields = [ fields = ["id", "name", "shortterm", "job_group", "slug"]
'id',
'name',
'shortterm',
'job_group',
'slug'
]
class JobMemberSerializer(serializers.HyperlinkedModelSerializer): class JobMemberSerializer(serializers.HyperlinkedModelSerializer):
#member = MemberSerializer() # member = MemberSerializer()
#job = JobSerializer() # job = JobSerializer()
job = serializers.SlugRelatedField( job = serializers.SlugRelatedField(slug_field="slug", queryset=Job.objects)
slug_field='slug',queryset = Job.objects member = serializers.SlugRelatedField(
) slug_field="mailaccount", queryset=Member.objects
member= serializers.SlugRelatedField( )
slug_field='mailaccount',queryset = Member.objects
)
class Meta: class Meta:
model = JobMember model = JobMember
fields = [ fields = ["id", "job_start", "job_end", "member", "job", "job_role"]
'id',
'job_start',
'job_end',
'member',
'job',
'job_role'
]
# def create(self, validated_data): # def create(self, validated_data):
# member_data = validated_data.pop('member') # member_data = validated_data.pop('member')

View File

@@ -4,14 +4,14 @@ from . import views
urlpatterns = [ urlpatterns = [
path('', views.index, name='members'), path("", views.index, name="members"),
path('<str:filter>', views.members_view), path("<str:filter>", views.members_view),
] ]
member_urlpatterns = [ member_urlpatterns = [
path('<str:member_id>', views.profile_view, name='member'), path("<str:member_id>", views.profile_view, name="member"),
] ]
jobs_urlpatterns = [ jobs_urlpatterns = [
path('<str:slug>', views.jobs_view, name='jobs'), path("<str:slug>", views.jobs_view, name="jobs"),
] ]

View File

@@ -7,6 +7,7 @@ from .models import Member, JobMember, JobGroup, Job
from posts.models import Post from posts.models import Post
import logging import logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -41,7 +42,7 @@ def index(request):
pinned_job_groups, unpinned_job_groups = __get_job_groups() pinned_job_groups, unpinned_job_groups = __get_job_groups()
members = deque(Member.all_members.all()) members = deque(Member.all_members.all())
fs_info = Post.objects.filter(slug='fachschaft-info').first() fs_info = Post.objects.filter(slug="fachschaft-info").first()
context = { context = {
"pinned_job_groups": pinned_job_groups, "pinned_job_groups": pinned_job_groups,
@@ -50,14 +51,16 @@ def index(request):
"fs_info": fs_info, "fs_info": fs_info,
} }
return render(request, 'members/index.html', context) return render(request, "members/index.html", context)
def jobs_view(request, slug=None): def jobs_view(request, slug=None):
pinned_job_groups, unpinned_job_groups = __get_job_groups() pinned_job_groups, unpinned_job_groups = __get_job_groups()
try: try:
description = JobGroup.all_jobgroups.filter(slug=slug).values().first()['description'] description = (
JobGroup.all_jobgroups.filter(slug=slug).values().first()["description"]
)
except Exception as e: except Exception as e:
logger.info("Wrong job '{}'".format(slug)) logger.info("Wrong job '{}'".format(slug))
raise Http404("wrong job") raise Http404("wrong job")
@@ -71,7 +74,7 @@ def jobs_view(request, slug=None):
"job_members": job_members, "job_members": job_members,
} }
return render(request, 'members/index.html', context) return render(request, "members/index.html", context)
def members_view(request, filter=None): def members_view(request, filter=None):
@@ -83,7 +86,7 @@ def members_view(request, filter=None):
logger.info("Wrong member role '{}'".format(filter)) logger.info("Wrong member role '{}'".format(filter))
raise Http404("no member role") raise Http404("no member role")
fs_info = Post.objects.filter(slug='fachschaft-info').first() fs_info = Post.objects.filter(slug="fachschaft-info").first()
context = { context = {
"pinned_job_groups": pinned_job_groups, "pinned_job_groups": pinned_job_groups,
@@ -92,7 +95,7 @@ def members_view(request, filter=None):
"fs_info": fs_info, "fs_info": fs_info,
} }
return render(request, 'members/index.html', context) return render(request, "members/index.html", context)
def profile_view(request, member_id=None): def profile_view(request, member_id=None):
@@ -112,4 +115,4 @@ def profile_view(request, member_id=None):
"jobs": jobs, "jobs": jobs,
} }
return render(request, 'members/member.html', context) return render(request, "members/member.html", context)

View File

@@ -2,54 +2,63 @@ from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import viewsets from rest_framework import viewsets
from .models import Member, JobMember, JobGroup, Job from .models import Member, JobMember, JobGroup, Job
from .serializers import MemberSerializer, JobSerializer, JobGroupSerializer, JobMemberSerializer from .serializers import (
MemberSerializer,
JobSerializer,
JobGroupSerializer,
JobMemberSerializer,
)
class MemberViewSet(viewsets.ModelViewSet): class MemberViewSet(viewsets.ModelViewSet):
""" """
API endpoint that allows users to be viewed or edited. API endpoint that allows users to be viewed or edited.
""" """
queryset = Member.all_members.order_by('nickname')
queryset = Member.all_members.order_by("nickname")
serializer_class = MemberSerializer serializer_class = MemberSerializer
#permission_classes = [permissions.IsAuthenticated] # permission_classes = [permissions.IsAuthenticated]
filter_backends = [DjangoFilterBackend] filter_backends = [DjangoFilterBackend]
filterset_fields = ['nickname','mailaccount'] filterset_fields = ["nickname", "mailaccount"]
#lookup_field = 'name' # lookup_field = 'name'
def pre_save(self, obj): def pre_save(self, obj):
obj.image = self.request.FILES.get('image') obj.image = self.request.FILES.get("image")
class JobGroupViewSet(viewsets.ModelViewSet): class JobGroupViewSet(viewsets.ModelViewSet):
""" """
API endpoint that allows users to be viewed or edited. API endpoint that allows users to be viewed or edited.
""" """
queryset = JobGroup.all_jobgroups.all() queryset = JobGroup.all_jobgroups.all()
serializer_class = JobGroupSerializer serializer_class = JobGroupSerializer
filter_backends = [DjangoFilterBackend] filter_backends = [DjangoFilterBackend]
filterset_fields = ['name','slug'] filterset_fields = ["name", "slug"]
#lookup_field = 'name' # lookup_field = 'name'
class JobViewSet(viewsets.ModelViewSet): class JobViewSet(viewsets.ModelViewSet):
""" """
API endpoint that allows users to be viewed or edited. API endpoint that allows users to be viewed or edited.
""" """
queryset = Job.objects.all() queryset = Job.objects.all()
serializer_class = JobSerializer serializer_class = JobSerializer
filter_backends = [DjangoFilterBackend] filter_backends = [DjangoFilterBackend]
filterset_fields = ['name','slug'] filterset_fields = ["name", "slug"]
#lookup_field = 'slug' # lookup_field = 'slug'
class JobMemberViewSet(viewsets.ModelViewSet): class JobMemberViewSet(viewsets.ModelViewSet):
""" """
API endpoint that allows users to be viewed or edited. API endpoint that allows users to be viewed or edited.
""" """
queryset = JobMember.objects.all() queryset = JobMember.objects.all()
serializer_class = JobMemberSerializer serializer_class = JobMemberSerializer
filter_backends = [DjangoFilterBackend] filter_backends = [DjangoFilterBackend]
filterset_fields = ['member','job','job_role','job_start'] filterset_fields = ["member", "job", "job_role", "job_start"]
#lookup_field = 'nickname' # lookup_field = 'nickname'

View File

@@ -13,7 +13,7 @@ admin.site.unregister(taggit.models.Tag)
def make_fetmeeting(self, request, queryset): def make_fetmeeting(self, request, queryset):
qs = self.get_queryset(request).filter(id=request.POST['_selected_action']).first() qs = self.get_queryset(request).filter(id=request.POST["_selected_action"]).first()
failed = False failed = False
agenda_key = None agenda_key = None
@@ -24,7 +24,7 @@ def make_fetmeeting(self, request, queryset):
except Exception as e: except Exception as e:
self.message_user( self.message_user(
request, request,
_('Das Agenda konnte nicht erstellt werden. Error: %s') % str(e), _("Das Agenda konnte nicht erstellt werden. Error: %s") % str(e),
messages.ERROR, messages.ERROR,
) )
failed = True failed = True
@@ -34,14 +34,14 @@ def make_fetmeeting(self, request, queryset):
except Exception as e: except Exception as e:
self.message_user( self.message_user(
request, request,
_('Das Protokoll konnte nicht erstellt werden. Error: %s') % str(e), _("Das Protokoll konnte nicht erstellt werden. Error: %s") % str(e),
messages.ERROR, messages.ERROR,
) )
failed = True failed = True
if not failed: if not failed:
queryset.update( queryset.update(
post_type='F', post_type="F",
has_agenda=True, has_agenda=True,
has_protocol=True, has_protocol=True,
agenda_key=agenda_key, agenda_key=agenda_key,
@@ -49,7 +49,8 @@ def make_fetmeeting(self, request, queryset):
) )
self.message_user( self.message_user(
request, request,
_('Das Event %s wurde erfolgreich in eine FET Sitzung konvertiert.') % (qs.title), _("Das Event %s wurde erfolgreich in eine FET Sitzung konvertiert.")
% (qs.title),
messages.SUCCESS, messages.SUCCESS,
) )
@@ -60,22 +61,27 @@ make_fetmeeting.short_description = "In eine Fachschaftssitzung konvertieren"
class PostAdmin(admin.ModelAdmin): class PostAdmin(admin.ModelAdmin):
form = PostForm form = PostForm
model = Post model = Post
list_filter = ['is_pinned', 'is_hidden'] list_filter = ["is_pinned", "is_hidden"]
list_display = ['title', 'slug', 'public_date', 'is_pinned', 'is_hidden'] list_display = ["title", "slug", "public_date", "is_pinned", "is_hidden"]
ordering = ['is_hidden', '-public_date'] ordering = ["is_hidden", "-public_date"]
def add_view(self, request, form_url='', extra_context=None): def add_view(self, request, form_url="", extra_context=None):
extra_context = extra_context or {} extra_context = extra_context or {}
extra_context['help_text'] = "Fette Schriften sind Pflichtfelder." extra_context["help_text"] = "Fette Schriften sind Pflichtfelder."
return super().add_view( return super().add_view(
request, form_url, extra_context=extra_context, request,
form_url,
extra_context=extra_context,
) )
def change_view(self, request, object_id, form_url='', extra_context=None): def change_view(self, request, object_id, form_url="", extra_context=None):
extra_context = extra_context or {} extra_context = extra_context or {}
extra_context['help_text'] = "Fette Schriften sind Pflichtfelder." extra_context["help_text"] = "Fette Schriften sind Pflichtfelder."
return super().change_view( return super().change_view(
request, object_id, form_url, extra_context=extra_context, request,
object_id,
form_url,
extra_context=extra_context,
) )
def save_model(self, request, obj, form, change): def save_model(self, request, obj, form, change):
@@ -98,9 +104,9 @@ class PostAdmin(admin.ModelAdmin):
class EventAdmin(PostAdmin): class EventAdmin(PostAdmin):
form = EventForm form = EventForm
model = Event model = Event
list_filter = ['is_pinned'] list_filter = ["is_pinned"]
list_display = ['title', 'slug', 'event_start', 'public_date', 'is_pinned'] list_display = ["title", "slug", "event_start", "public_date", "is_pinned"]
ordering = ['-event_start'] ordering = ["-event_start"]
actions = [make_fetmeeting] actions = [make_fetmeeting]
@@ -113,7 +119,7 @@ class FetMeetingAdmin(EventAdmin):
form = FetMeetingForm form = FetMeetingForm
model = FetMeeting model = FetMeeting
list_filter = [] list_filter = []
list_display = ['title', 'slug', 'event_start', 'public_date'] list_display = ["title", "slug", "event_start", "public_date"]
actions = [] actions = []

View File

@@ -2,4 +2,4 @@ from django.apps import AppConfig
class PostsConfig(AppConfig): class PostsConfig(AppConfig):
name = 'posts' name = "posts"

View File

@@ -10,14 +10,23 @@ from .models import Post, Event, News, FetMeeting
class PostForm(forms.ModelForm): class PostForm(forms.ModelForm):
class Meta: class Meta:
model = Post model = Post
fields = ['title', 'subtitle', 'tags', 'image', 'body', 'slug', 'author', 'public_date'] fields = [
"title",
"subtitle",
"tags",
"image",
"body",
"slug",
"author",
"public_date",
]
widgets = {'body': CKEditorUploadingWidget(config_name='default')} widgets = {"body": CKEditorUploadingWidget(config_name="default")}
class Media: class Media:
js = ( js = (
'js/auto_slug.js', # automatic slag completion via ajax "js/auto_slug.js", # automatic slag completion via ajax
'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
) )
@@ -25,106 +34,124 @@ class NewsForm(PostForm):
class Meta: class Meta:
model = News model = News
fields = [ fields = [
'title', 'subtitle', 'tags', 'image', 'body', 'slug', 'author', 'public_date', "title",
'is_pinned', 'is_hidden', "subtitle",
"tags",
"image",
"body",
"slug",
"author",
"public_date",
"is_pinned",
"is_hidden",
] ]
labels = { labels = {
'title': _("Titel"), "title": _("Titel"),
'subtitle': _("Untertitel"), "subtitle": _("Untertitel"),
'image': _("Hintergrundbild"), "image": _("Hintergrundbild"),
'body': _("Text"), "body": _("Text"),
'author': _("Autor"), "author": _("Autor"),
'public_date': _("Veröffentlichung"), "public_date": _("Veröffentlichung"),
'is_pinned': _("Post anheften"), "is_pinned": _("Post anheften"),
'is_hidden': _("Post verstecken"), "is_hidden": _("Post verstecken"),
} }
help_texts = { help_texts = {
'tags': _( "tags": _(
"Die Hashtags ohne '#' eintragen, und mit Komma kann man mehrere Tags anfügen." "Die Hashtags ohne '#' eintragen, und mit Komma kann man mehrere Tags anfügen."
), ),
'image': _( "image": _("Verwendbare Formate: ..."),
"Verwendbare Formate: ..." "is_pinned": _(
),
'is_pinned': _(
"Dieser Post soll an die Startseite als erster Post angeheftet werden." "Dieser Post soll an die Startseite als erster Post angeheftet werden."
), ),
'is_hidden': _( "is_hidden": _(
"Dieser Post soll im News Feed nicht auftauchen, z.B. Impressum." "Dieser Post soll im News Feed nicht auftauchen, z.B. Impressum."
), ),
} }
widgets = {'body': CKEditorUploadingWidget(config_name='default')} widgets = {"body": CKEditorUploadingWidget(config_name="default")}
def __init__(self, *args, **kwargs): 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['author'].queryset = self.fields['author'].queryset.order_by('username') self.fields["author"].queryset = self.fields["author"].queryset.order_by(
"username"
)
class EventForm(PostForm): class EventForm(PostForm):
class Meta: class Meta:
model = Event model = Event
fields = [ fields = [
'title', 'subtitle', 'tags', 'image', 'body', 'event_start', 'event_end', "title",
'event_place', 'slug', 'author', 'public_date', 'is_pinned', "subtitle",
"tags",
"image",
"body",
"event_start",
"event_end",
"event_place",
"slug",
"author",
"public_date",
"is_pinned",
] ]
labels = { labels = {
'title': _("Titel"), "title": _("Titel"),
'subtitle': _("Untertitel"), "subtitle": _("Untertitel"),
'image': _("Hintergrundbild"), "image": _("Hintergrundbild"),
'body': _("Text"), "body": _("Text"),
'event_start': _("Start des Events"), "event_start": _("Start des Events"),
'event_end': _("Ende des Events"), "event_end": _("Ende des Events"),
'event_place': _("Ort des Events"), "event_place": _("Ort des Events"),
'author': _("Autor"), "author": _("Autor"),
'public_date': _("Veröffentlichung"), "public_date": _("Veröffentlichung"),
'is_pinned': _("Event anheften"), "is_pinned": _("Event anheften"),
} }
help_texts = { help_texts = {
'tags': _( "tags": _(
"Die Hashtags ohne '#' eintragen, und mit Komma kann man mehrere Tags anfügen." "Die Hashtags ohne '#' eintragen, und mit Komma kann man mehrere Tags anfügen."
), ),
'image': _( "image": _("Verwendbare Formate: "),
"Verwendbare Formate: " "is_pinned": _(
),
'is_pinned': _(
"Dieses Event soll an die Startseite als erster Post angeheftet werden." "Dieses Event soll an die Startseite als erster Post angeheftet werden."
), ),
} }
widgets = {'body': CKEditorUploadingWidget(config_name='default')} widgets = {"body": CKEditorUploadingWidget(config_name="default")}
def __init__(self, *args, **kwargs): 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['author'].queryset = self.fields['author'].queryset.order_by('username') self.fields["author"].queryset = self.fields["author"].queryset.order_by(
"username"
)
self.fields['event_start'].required = True self.fields["event_start"].required = True
self.fields['event_end'].required = False self.fields["event_end"].required = False
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 FetMeetingForm(PostForm): class FetMeetingForm(PostForm):
# agenda_html = forms.CharField(widget = forms.TextInput()) # agenda_html = forms.CharField(widget = forms.TextInput())
class Meta: class Meta:
model = FetMeeting model = FetMeeting
fields = ['event_start', 'event_end', 'tags']#, 'has_agenda', 'has_protocol'] fields = ["event_start", "event_end", "tags"] # , 'has_agenda', 'has_protocol']
labels = { labels = {
'event_start': _("Start der Sitzung"), "event_start": _("Start der Sitzung"),
'event_end': _("Ende der Sitzung")#, "event_end": _("Ende der Sitzung") # ,
# 'has_agenda': _("Agenda"), # 'has_agenda': _("Agenda"),
# 'has_protocol': _("Protokoll"), # 'has_protocol': _("Protokoll"),
} }
help_texts = { help_texts = {
'tags': _( "tags": _(
"Die Hashtags ohne '#' eintragen, und mit Komma kann man mehrere Tags anfügen." "Die Hashtags ohne '#' eintragen, und mit Komma kann man mehrere Tags anfügen."
)#, ) # ,
#'has_agenda': _("Agenda zur Sitzung hinzufügen."), #'has_agenda': _("Agenda zur Sitzung hinzufügen."),
#'has_protocol': _("Protokoll zur Sitzung hinzufügen."), #'has_protocol': _("Protokoll zur Sitzung hinzufügen."),
} }
@@ -132,13 +159,13 @@ class FetMeetingForm(PostForm):
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
self.fields['event_start'].required = True self.fields["event_start"].required = True
self.fields['event_end'].required = False self.fields["event_end"].required = False
#self.fields['has_agenda'].initial = True # self.fields['has_agenda'].initial = True
#self.fields['has_protocol'].initial = True # self.fields['has_protocol'].initial = True
tags = [] tags = []
tags.append(Tag()) tags.append(Tag())
tags[0].name = "fachschaft" tags[0].name = "fachschaft"
self.fields['tags'].initial = tags self.fields["tags"].initial = tags

View File

@@ -3,15 +3,22 @@ from django.core.mail import send_mail
def send_agenda_mail(date, time, slug): def send_agenda_mail(date, time, slug):
msg = "Liebe Alle,\n\n" \ msg = (
"wir haben am " + str(date) + " um " + str(time) + " wieder Sitzung.\n" \ "Liebe Alle,\n\n"
"du hast noch bis morgen Zeit, weitere Themen auf die Agenda zu schreiben: " \ "wir haben am " + str(date) + " um " + str(time) + " wieder Sitzung.\n"
+ settings.HOST_NAME + '/posts/' + str(slug) + ".\n\n" \ "du hast noch bis morgen Zeit, weitere Themen auf die Agenda zu schreiben: "
+ settings.HOST_NAME
+ "/posts/"
+ str(slug)
+ ".\n\n"
"LG deine FET" "LG deine FET"
)
send_mail( send_mail(
subject = 'Test - Agenda der FET Sitzung von ' + str(date), subject="Test - Agenda der FET Sitzung von " + str(date),
message = msg, message=msg,
from_email = 'patrick@fet.at', from_email="patrick@fet.at",
recipient_list = ['all@fet.at', ], recipient_list=[
"all@fet.at",
],
) )

View File

@@ -5,23 +5,32 @@ from django.utils import timezone
class PostManager(models.Manager): class PostManager(models.Manager):
def get_queryset(self): def get_queryset(self):
return super().get_queryset().order_by('-public_date') return super().get_queryset().order_by("-public_date")
def get_visible_articles(self): def get_visible_articles(self):
return self.get_queryset().filter(is_hidden=False) return self.get_queryset().filter(is_hidden=False)
def all_post_with_date(self): def all_post_with_date(self):
return self.get_queryset().filter(Q(event_start__isnull=False) & Q(event_end__isnull=False)).order_by('-event_start') return (
self.get_queryset()
.filter(Q(event_start__isnull=False) & Q(event_end__isnull=False))
.order_by("-event_start")
)
class ArticleManager(models.Manager): 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( return (
Q(post_type='E') super()
| Q(post_type='N') .get_queryset()
).order_by('-public_date') .filter(Q(post_type="E") | Q(post_type="N"))
.order_by("-public_date")
)
def get_visible_articles(self): def get_visible_articles(self):
return self.get_queryset().filter(is_hidden=False) return self.get_queryset().filter(is_hidden=False)
@@ -34,8 +43,9 @@ class NewsManager(models.Manager):
""" """
Provide a query set only for "News" Provide a query set only for "News"
""" """
def get_queryset(self): def get_queryset(self):
return super().get_queryset().filter(post_type='N').order_by('-public_date') return super().get_queryset().filter(post_type="N").order_by("-public_date")
def get_visible_articles(self): def get_visible_articles(self):
return self.get_queryset().filter(is_hidden=False) return self.get_queryset().filter(is_hidden=False)
@@ -45,12 +55,17 @@ class AllEventManager(models.Manager):
""" """
Provide a query set for all events ("Event" and "Fet Meeting") Provide a query set for all events ("Event" and "Fet Meeting")
""" """
def get_queryset(self): def get_queryset(self):
return super().get_queryset().filter(Q(post_type='E') | Q(post_type='F')) return super().get_queryset().filter(Q(post_type="E") | Q(post_type="F"))
def get_five_events(self): def get_five_events(self):
date_today = timezone.now() date_today = timezone.now()
return self.get_queryset().filter(event_start__gt=date_today).order_by('event_start')[:5] return (
self.get_queryset()
.filter(event_start__gt=date_today)
.order_by("event_start")[:5]
)
class EventManager(models.Manager): class EventManager(models.Manager):
@@ -58,32 +73,50 @@ 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(post_type='E') return super().get_queryset().filter(post_type="E")
def get_future_events(self): def get_future_events(self):
date_today = timezone.now() date_today = timezone.now()
return self.get_queryset().filter(event_start__gt=date_today).order_by('event_start') return (
self.get_queryset()
.filter(event_start__gt=date_today)
.order_by("event_start")
)
def get_past_events(self): def get_past_events(self):
date_today = timezone.now() date_today = timezone.now()
return self.get_queryset().filter(event_start__lt=date_today).order_by('-event_start') return (
self.get_queryset()
.filter(event_start__lt=date_today)
.order_by("-event_start")
)
class FetMeetingManager(models.Manager): class FetMeetingManager(models.Manager):
""" """
Provide a query set only for "Fet Meeting" Provide a query set only for "Fet Meeting"
""" """
def get_queryset(self): def get_queryset(self):
return super().get_queryset().filter(post_type='F') return super().get_queryset().filter(post_type="F")
def _get_future_events(self): def _get_future_events(self):
date_today = timezone.now() date_today = timezone.now()
return self.get_queryset().filter(event_start__gt=date_today).order_by('event_start') return (
self.get_queryset()
.filter(event_start__gt=date_today)
.order_by("event_start")
)
def _get_past_events(self): def _get_past_events(self):
date_today = timezone.now() date_today = timezone.now()
return self.get_queryset().filter(event_start__lt=date_today).order_by('-event_start') return (
self.get_queryset()
.filter(event_start__lt=date_today)
.order_by("-event_start")
)
def get_meetings(self): def get_meetings(self):
meetings = [] meetings = []

View File

@@ -133,6 +133,7 @@ class Post(models.Model):
) )
html = None html = None
return html return html
@property @property
def protocol_html(self): def protocol_html(self):
"Protocol HTML from Etherpad Pad" "Protocol HTML from Etherpad Pad"
@@ -196,7 +197,7 @@ class Post(models.Model):
def get_agenda_key(self): def get_agenda_key(self):
"""Create a Etherpad Id for the Pad associated to this post. """Create a Etherpad Id for the Pad associated to this post.
Creates the pad if it doesn't exist""" Creates the pad if it doesn't exist"""
if not self.slug: if not self.slug:
return None return None
return create_pad_for_post(self.slug, typ="agenda") return create_pad_for_post(self.slug, typ="agenda")
@@ -255,9 +256,10 @@ class Post(models.Model):
def clean(self): def clean(self):
if self.event_end and self.event_end < self.event_start: if self.event_end and self.event_end < self.event_start:
raise ValidationError(_("Das Ende des Events liegt vor dem Beginn.")) raise ValidationError(_("Das Ende des Events liegt vor dem Beginn."))
if self.event_start and self.post_type not in ['E','F']: if self.event_start and self.post_type not in ["E", "F"]:
raise ValidationError("Für diesen Post Typ ist kein Event Start zulässig") raise ValidationError("Für diesen Post Typ ist kein Event Start zulässig")
super().clean() super().clean()
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
# save the post with some defaults # save the post with some defaults
if not self.public_date: if not self.public_date:
@@ -307,9 +309,9 @@ class Event(Post):
verbose_name = "Event" verbose_name = "Event"
verbose_name_plural = "Events" verbose_name_plural = "Events"
def __init__(self,*args,**kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args,**kwargs) super().__init__(*args, **kwargs)
self.post_type='E' self.post_type = "E"
def clean(self): def clean(self):
if not self.event_start: if not self.event_start:
@@ -334,9 +336,9 @@ class FetMeeting(Event):
verbose_name = "Fet Sitzung" verbose_name = "Fet Sitzung"
verbose_name_plural = "Fet Sitzungen" verbose_name_plural = "Fet Sitzungen"
def __init__(self,*args,**kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args,**kwargs) super().__init__(*args, **kwargs)
self.post_type='F' self.post_type = "F"
def __get_slug(self): def __get_slug(self):
slug = slugify(self.event_start.date()) + "-" + slugify("Fachschaftssitzung") slug = slugify(self.event_start.date()) + "-" + slugify("Fachschaftssitzung")
@@ -349,34 +351,33 @@ class FetMeeting(Event):
return slug return slug
# def __get_agenda_key(self): # def __get_agenda_key(self):
# if not self.slug: # if not self.slug:
# return None## # return None##
# #
# try: # try:
# agenda_key = createPadifNotExists(self.slug + "-agenda") # agenda_key = createPadifNotExists(self.slug + "-agenda")
# except Exception as error: # except Exception as error:
# raise ValidationError( # raise ValidationError(
# _("Die Agenda konnte nicht erstellt werden. Error: %(error)s"), # _("Die Agenda konnte nicht erstellt werden. Error: %(error)s"),
# params={"error": str(error)}, # params={"error": str(error)},
# ) from error # ) from error
# #
# return agenda_key # return agenda_key
# def __get_protocol_key(self):
# if not self.slug:
# return None#
#
# try:
# protocol_key = createPadifNotExists(self.slug + "-protocol")
# except URLError as error:
# raise ValidationError(
# _("Das Protokoll konnte nicht erstellt werden. Error: %(error)s"),
# params={"error": str(error)},
# ) from error#
#
# return protocol_key
# def __get_protocol_key(self):
# if not self.slug:
# return None#
#
# try:
# protocol_key = createPadifNotExists(self.slug + "-protocol")
# except URLError as error:
# raise ValidationError(
# _("Das Protokoll konnte nicht erstellt werden. Error: %(error)s"),
# params={"error": str(error)},
# ) from error#
#
# return protocol_key
def clean(self): def clean(self):
super().clean() super().clean()

View File

@@ -5,33 +5,34 @@ from rest_framework import serializers
class PostSerializer(serializers.HyperlinkedModelSerializer): class PostSerializer(serializers.HyperlinkedModelSerializer):
agenda_html = serializers.CharField(required=False) agenda_html = serializers.CharField(required=False)
tag_string = serializers.CharField(required=False,read_only=True) tag_string = serializers.CharField(required=False, read_only=True)
imageurl = serializers.CharField(required=False,read_only=True) imageurl = serializers.CharField(required=False, read_only=True)
class Meta: class Meta:
model = Post model = Post
fields = [ fields = [
'slug', "slug",
'title', "title",
'subtitle', "subtitle",
'body', "body",
'url', "url",
'post_type', "post_type",
'public_date', "public_date",
'legacy_id', "legacy_id",
'image', "image",
'event_start', "event_start",
'event_end', "event_end",
'is_hidden', "is_hidden",
'agenda_html', "agenda_html",
'protocol_html', "protocol_html",
'has_agenda', "has_agenda",
'has_protocol', "has_protocol",
'tag_string', "tag_string",
'imageurl' "imageurl"
# 'author', # 'author',
] ]
extra_kwargs={ extra_kwargs = {
'agenda_html': {"required": False}, "agenda_html": {"required": False},
'protocol_html': {"required": False} "protocol_html": {"required": False},
} }

View File

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

View File

@@ -27,7 +27,7 @@ def index(request):
"Index von aktuellen Posts" "Index von aktuellen Posts"
posts = deque(Post.objects.get_visible_articles().order_by("-public_date")) posts = deque(Post.objects.get_visible_articles().order_by("-public_date"))
taglist = map(lambda post : post.tags, posts) taglist = map(lambda post: post.tags, posts)
return render(request, "posts/index.html", {"posts": posts, "tags_list": taglist}) return render(request, "posts/index.html", {"posts": posts, "tags_list": taglist})
@@ -48,7 +48,6 @@ def tags(request, tag=""):
posts = deque(Post.objects.get_visible_articles().filter(tags__name=tag)) posts = deque(Post.objects.get_visible_articles().filter(tags__name=tag))
featured_post = Post.objects.get_visible_articles().filter(slug=tag).first() featured_post = Post.objects.get_visible_articles().filter(slug=tag).first()
job_members = JobMember.active_member.get_all_by_slug(slug=tag) job_members = JobMember.active_member.get_all_by_slug(slug=tag)
author_image = None author_image = None
@@ -86,25 +85,21 @@ def show(request, id=None):
ep_agenda_link = "#" ep_agenda_link = "#"
ep_protocol_link = "#" ep_protocol_link = "#"
if p.has_agenda:# and p.agenda_key: if p.has_agenda: # and p.agenda_key:
try: try:
ep_agenda_link = get_pad_link(p.agenda_key) ep_agenda_link = get_pad_link(p.agenda_key)
except Exception as e: except Exception as e:
logger.error( logger.error(
"Can't get the agenda link from '%s'. Error: %s", "Can't get the agenda link from '%s'. Error: %s", p.agenda_key, e
p.agenda_key,
e
) )
ep_agenda_link = "#" ep_agenda_link = "#"
if p.has_protocol:# and p.protocol_key: if p.has_protocol: # and p.protocol_key:
try: try:
ep_protocol_link = get_pad_link(p.protocol_key) ep_protocol_link = get_pad_link(p.protocol_key)
except Exception as e: except Exception as e:
logger.error( logger.error(
"Can't get the protocol link from '%s. Error: %s", "Can't get the protocol link from '%s. Error: %s", p.protocol_key, e
p.protocol_key, e
) )
ep_protocol_link = "#" ep_protocol_link = "#"
@@ -125,8 +120,7 @@ def show(request, id=None):
try: try:
response = add_ep_cookie(request, response) response = add_ep_cookie(request, response)
except Exception as e: except Exception as e:
logger.info( logger.info("Etherpad Server doesn't work. Error: %s", e)
"Etherpad Server doesn't work. Error: %s", e)
return response return response

View File

@@ -8,23 +8,33 @@ class TaskAdmin(admin.ModelAdmin):
form = TaskAdminForm form = TaskAdminForm
model = Task model = Task
fieldsets = ( fieldsets = (
(None, { (
'fields': ( None,
'title', {
'task_list', "fields": (
'assigned_to', "title",
'due_date', "task_list",
'completed', "assigned_to",
'completed_date', "due_date",
'note', "completed",
'priority', "completed_date",
) "note",
}), "priority",
)
},
),
) )
list_display = ['title', 'task_list', 'assigned_to', 'due_date', 'completed', 'priority'] list_display = [
list_filter = ('task_list', ) "title",
search_fields = ('title', ) "task_list",
"assigned_to",
"due_date",
"completed",
"priority",
]
list_filter = ("task_list",)
search_fields = ("title",)
def save_model(self, request, obj, form, change): def save_model(self, request, obj, form, change):
obj.created_by = request.user obj.created_by = request.user

View File

@@ -2,4 +2,4 @@ from django.apps import AppConfig
class TasksConfig(AppConfig): class TasksConfig(AppConfig):
name = 'tasks' name = "tasks"

View File

@@ -7,29 +7,31 @@ from .models import Task, TaskList
class DateInput(forms.DateInput): class DateInput(forms.DateInput):
input_type = 'date' input_type = "date"
class TaskAdminForm(forms.ModelForm): class TaskAdminForm(forms.ModelForm):
class Meta: class Meta:
model = Task model = Task
fields = '__all__' fields = "__all__"
labels = { labels = {
'title': _('Titel'), "title": _("Titel"),
'task_list': _('Aufgabenbereich'), "task_list": _("Aufgabenbereich"),
'due_date': _('Fälligkeit'), "due_date": _("Fälligkeit"),
'completed': _('Abgeschlossen'), "completed": _("Abgeschlossen"),
'completed_date': _('Datum der Fertigstellung'), "completed_date": _("Datum der Fertigstellung"),
'assigned_to': _('Zuweisen an'), "assigned_to": _("Zuweisen an"),
'note': _('Notizen'), "note": _("Notizen"),
'priority': _('Priorität'), "priority": _("Priorität"),
} }
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
self.fields['assigned_to'].empty_label = "Alle" self.fields["assigned_to"].empty_label = "Alle"
self.fields['assigned_to'].queryset = self.fields['assigned_to'].queryset.order_by('username') self.fields["assigned_to"].queryset = self.fields[
"assigned_to"
].queryset.order_by("username")
class TaskForm(forms.ModelForm): class TaskForm(forms.ModelForm):
@@ -37,39 +39,41 @@ class TaskForm(forms.ModelForm):
model = Task model = Task
fields = [ fields = [
'title', "title",
'task_list', "task_list",
'due_date', "due_date",
'assigned_to', "assigned_to",
] ]
labels = { labels = {
'title': _('Titel des Tasks'), "title": _("Titel des Tasks"),
'task_list': _('Task-Gruppe'), "task_list": _("Task-Gruppe"),
'due_date': _('Fälligkeitsdatum'), "due_date": _("Fälligkeitsdatum"),
'assigned_to': _('Zuweisen an'), "assigned_to": _("Zuweisen an"),
} }
widgets = { widgets = {
'due_date': DateInput( "due_date": DateInput(
format=('%d-%m-%Y'), format=("%d-%m-%Y"),
) )
} }
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
self.fields['assigned_to'].empty_label = "Alle" self.fields["assigned_to"].empty_label = "Alle"
self.fields['assigned_to'].queryset = self.fields['assigned_to'].queryset.order_by('username') self.fields["assigned_to"].queryset = self.fields[
"assigned_to"
].queryset.order_by("username")
class TaskListForm(forms.ModelForm): class TaskListForm(forms.ModelForm):
users = forms.ModelMultipleChoiceField( users = forms.ModelMultipleChoiceField(
label="Benutzer", label="Benutzer",
help_text="Es können nur die Benutzer ausgewählt werden, die sich auf der Homepage angemeldet haben.", help_text="Es können nur die Benutzer ausgewählt werden, die sich auf der Homepage angemeldet haben.",
queryset=User.objects.all().order_by('username'), queryset=User.objects.all().order_by("username"),
widget=FilteredSelectMultiple("User", is_stacked=False) widget=FilteredSelectMultiple("User", is_stacked=False),
) )
class Meta: class Meta:
model = TaskList model = TaskList
fields = '__all__' fields = "__all__"

View File

@@ -7,7 +7,7 @@ from django.utils import timezone
class TaskQuerySet(models.QuerySet): class TaskQuerySet(models.QuerySet):
def get_ordered(self): def get_ordered(self):
return self.order_by('task_list') return self.order_by("task_list")
class TaskManager(models.Manager): class TaskManager(models.Manager):
@@ -16,7 +16,11 @@ class TaskManager(models.Manager):
qs = self.get_queryset().get_ordered().filter(assigned_to__id=user) qs = self.get_queryset().get_ordered().filter(assigned_to__id=user)
if all_tasks: if all_tasks:
qs_tmp = self.get_queryset().get_ordered().filter(Q(assigned_to=None) & Q(task_list__users__id__exact=user)) qs_tmp = (
self.get_queryset()
.get_ordered()
.filter(Q(assigned_to=None) & Q(task_list__users__id__exact=user))
)
qs = (qs | qs_tmp).distinct() qs = (qs | qs_tmp).distinct()
if not completed: if not completed:
@@ -49,7 +53,9 @@ class TaskList(models.Model):
class Task(models.Model): class Task(models.Model):
title = models.CharField(verbose_name="Titel", max_length=140) title = models.CharField(verbose_name="Titel", max_length=140)
task_list = models.ForeignKey(TaskList, verbose_name="Aufgabenbereich", on_delete=models.CASCADE, null=True) task_list = models.ForeignKey(
TaskList, verbose_name="Aufgabenbereich", on_delete=models.CASCADE, null=True
)
created_date = models.DateTimeField(auto_now_add=True) created_date = models.DateTimeField(auto_now_add=True)
due_date = models.DateField(verbose_name="Fälligkeit", blank=True, null=True) due_date = models.DateField(verbose_name="Fälligkeit", blank=True, null=True)
@@ -72,7 +78,9 @@ class Task(models.Model):
) )
note = models.TextField(verbose_name="Notizen", blank=True, null=True) note = models.TextField(verbose_name="Notizen", blank=True, null=True)
priority = models.PositiveIntegerField(verbose_name="Priorität", blank=True, null=True) priority = models.PositiveIntegerField(
verbose_name="Priorität", blank=True, null=True
)
objects = models.Manager() objects = models.Manager()
taskmanager = TaskManager() taskmanager = TaskManager()

View File

@@ -4,5 +4,5 @@ from . import views
urlpatterns = [ urlpatterns = [
path('', views.index, name='tasks'), path("", views.index, name="tasks"),
] ]

View File

@@ -17,8 +17,8 @@ def index(request):
show_tasklist = None show_tasklist = None
show_all_tasks = True show_all_tasks = True
if request.method == 'POST': if request.method == "POST":
if 'btn_input' in request.POST: if "btn_input" in request.POST:
form = TaskForm(request.POST) form = TaskForm(request.POST)
if form.is_valid(): if form.is_valid():
@@ -29,13 +29,18 @@ def index(request):
task.created_by = request.user task.created_by = request.user
task.save() task.save()
else: else:
messages.info(request, "User '{}' ist nicht in der Liste von Task-Gruppe '{}'.".format(task.assigned_to, task.task_list.name)) messages.info(
request,
"User '{}' ist nicht in der Liste von Task-Gruppe '{}'.".format(
task.assigned_to, task.task_list.name
),
)
else: else:
task.created_by = request.user task.created_by = request.user
task.save() task.save()
elif 'btn_checkbox' in request.POST: elif "btn_checkbox" in request.POST:
for task_id in request.POST.getlist('checkbox'): for task_id in request.POST.getlist("checkbox"):
task = Task.objects.get(id=task_id) task = Task.objects.get(id=task_id)
if not task.completed: if not task.completed:
@@ -43,27 +48,31 @@ def index(request):
task.completed_date = timezone.now().date() task.completed_date = timezone.now().date()
task.save() task.save()
elif 'btn_user' in request.POST: elif "btn_user" in request.POST:
if request.POST['action'] == 'show_incompleted': if request.POST["action"] == "show_incompleted":
current_action = False current_action = False
else: else:
current_action = True current_action = True
if request.POST['tasklist'] != 'all': if request.POST["tasklist"] != "all":
show_tasklist = TaskList.objects.filter(id=request.POST['tasklist']).first() show_tasklist = TaskList.objects.filter(
id=request.POST["tasklist"]
).first()
if request.POST['tasks'] == 'all': if request.POST["tasks"] == "all":
show_all_tasks = True show_all_tasks = True
else: else:
show_all_tasks = False show_all_tasks = False
form = TaskForm() form = TaskForm()
tasks = deque(Task.taskmanager.get_tasks( tasks = deque(
user=current_user, Task.taskmanager.get_tasks(
completed=current_action, user=current_user,
task_list=show_tasklist, completed=current_action,
all_tasks=show_all_tasks task_list=show_tasklist,
)) all_tasks=show_all_tasks,
)
)
tasklists = deque(TaskList.objects.all()) tasklists = deque(TaskList.objects.all())
context = { context = {
@@ -74,4 +83,4 @@ def index(request):
"current_action": current_action, "current_action": current_action,
} }
return render(request, 'tasks/index.html', context) return render(request, "tasks/index.html", context)