merge settings.py
This commit is contained in:
2
deployment/dev_nginx/Dockerfile
Normal file
2
deployment/dev_nginx/Dockerfile
Normal file
@@ -0,0 +1,2 @@
|
||||
from nginx:alpine
|
||||
copy nginxdev.conf /etc/nginx/conf.d/default.conf
|
||||
3
deployment/dev_nginx/build_and_push
Executable file
3
deployment/dev_nginx/build_and_push
Executable file
@@ -0,0 +1,3 @@
|
||||
cp ../nginxdev.conf .
|
||||
docker build . -t docker.triton2.fet.at/nginxdev-fet2020:latest
|
||||
docker image push docker.triton2.fet.at/nginxdev-fet2020:latest
|
||||
67
deployment/dev_nginx/nginxdev.conf
Normal file
67
deployment/dev_nginx/nginxdev.conf
Normal file
@@ -0,0 +1,67 @@
|
||||
server {
|
||||
listen 8080;
|
||||
error_log /var/log/nginx/error.log notice;
|
||||
rewrite_log on;
|
||||
resolver 127.0.0.11 valid=30s;
|
||||
set $theia theia;
|
||||
set $flaskfetfotos "flaskfetfotos:8080";
|
||||
set $etherpad "etherpad:9001";
|
||||
location /fotos {
|
||||
proxy_ssl_server_name on;
|
||||
proxy_ssl_verify off;
|
||||
|
||||
proxy_pass http://$flaskfetfotos;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
# proxy_set_header REMOTE-USER $http_REMOTE_USER;
|
||||
# proxy_set_header X-Forwarded-User $http_REMOTE_USER;
|
||||
# proxy_set_header x-forwarded-user $http_REMOTE_USER;
|
||||
proxy_set_header Connection "upgrade";
|
||||
|
||||
|
||||
}
|
||||
|
||||
location /etherpad {
|
||||
|
||||
rewrite /etherpad/(.*) /$1 break;
|
||||
rewrite ^/etherpad$ /etherpad/ permanent;
|
||||
|
||||
proxy_pass http://$etherpad;
|
||||
proxy_redirect / /etherpad/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_buffering off;
|
||||
|
||||
}
|
||||
location /dev {
|
||||
rewrite_log on;
|
||||
rewrite /dev/(.*) /$1 break;
|
||||
rewrite ^/dev$ /dev/ permanent;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header Proxy "";
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "Upgrade";
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarde-Proto $scheme;
|
||||
|
||||
|
||||
proxy_buffering off;
|
||||
proxy_pass http://$theia:3000;
|
||||
}
|
||||
|
||||
location / {
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header Proxy "";
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "Upgrade";
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarde-Proto $scheme;
|
||||
|
||||
|
||||
proxy_buffering off;
|
||||
|
||||
proxy_pass http://$theia:8000;
|
||||
|
||||
}
|
||||
}
|
||||
5
deployment/dev_theia/Dockerfile
Normal file
5
deployment/dev_theia/Dockerfile
Normal file
@@ -0,0 +1,5 @@
|
||||
from theiaide/theia-python:latest
|
||||
run apt-get update && apt-get -y install libgs-dev
|
||||
COPY ./requirements.txt .
|
||||
run pip3 install --upgrade pip && pip3 install -r requirements.txt && pip3 install pytest pylint bandit flake8 black pytest-django six pytest-mock
|
||||
ENTRYPOINT node /home/theia/src-gen/backend/main.js /home/project/.theia-workspace --hostname=0.0.0.0
|
||||
3
deployment/dev_theia/build_and_push
Executable file
3
deployment/dev_theia/build_and_push
Executable file
@@ -0,0 +1,3 @@
|
||||
cp ../../fet2020/requirements.txt .
|
||||
docker build . -t docker.triton2.fet.at/theia-fet2020:latest
|
||||
docker image push docker.triton2.fet.at/theia-fet2020:latest
|
||||
16
deployment/dev_theia/requirements.txt
Normal file
16
deployment/dev_theia/requirements.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
django==3.1.4
|
||||
django-ckeditor==6.0.0
|
||||
django-crontab==0.7.1
|
||||
django-environ==0.4.5
|
||||
django-filter==2.4.0
|
||||
django-static-jquery-ui==1.12.1.1
|
||||
django-softhyphen==1.1.0
|
||||
django-taggit==1.3.0
|
||||
djangorestframework==3.12.2
|
||||
configparser==5.0.1
|
||||
docutils==0.16
|
||||
easy-thumbnails==2.7.1
|
||||
etherpad-lite==0.5
|
||||
ghostscript==0.6
|
||||
ldap3==2.8.1
|
||||
mysqlclient==2.0.1
|
||||
@@ -1,4 +1,4 @@
|
||||
version: "3"
|
||||
version: "2"
|
||||
services:
|
||||
flaskfetfotos:
|
||||
image: flask-fet-fotos
|
||||
@@ -7,27 +7,16 @@ services:
|
||||
FLASK_APP: main.py
|
||||
pages_root: /app/data
|
||||
volumes:
|
||||
- /mnt/fotos/www:/app/data
|
||||
mysql:
|
||||
image: jbergstroem/mariadb-alpine
|
||||
environment:
|
||||
SKIP_INNODB: "yes"
|
||||
MYSQL_DATABASE: fet2020db
|
||||
MYSQL_USER: user
|
||||
MYSQL_PASSWORD: hgu
|
||||
MYSQL_COLLATION: utf8_general_ci
|
||||
MYSQL_CHARSET: utf8
|
||||
volumes:
|
||||
- mysql-volume:/var/lib/mysql
|
||||
- foto-data:/app/data
|
||||
etherpadsql:
|
||||
image: jbergstroem/mariadb-alpine
|
||||
image: mariadb
|
||||
environment:
|
||||
SKIP_INNODB: "no"
|
||||
MYSQL_DATABASE: etherpaddb
|
||||
MYSQL_USER: user
|
||||
MYSQL_PASSWORD: hgu
|
||||
MYSQL_COLLATION: utf8_general_ci
|
||||
MYSQL_CHARSET: utf8
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
|
||||
volumes:
|
||||
- ep-mysql-volume:/var/lib/mysql
|
||||
etherpad:
|
||||
@@ -40,38 +29,14 @@ services:
|
||||
DB_USER: user
|
||||
DB_PASS: hgu
|
||||
DB_CHARSET: utf8
|
||||
#ADMIN_PASSWORD: "AndiS"
|
||||
#REQUIRE_AUTHENTICATION: "false"
|
||||
TRUST_PROXY: "true"
|
||||
REQUIRE_SESSION: "true"
|
||||
#LOGLEVEL: "DEBUG"
|
||||
REQUIRE_SESSION: "true"
|
||||
depends_on:
|
||||
- etherpadsql
|
||||
volumes:
|
||||
- ./etherpad/APIKEY.txt:/opt/etherpad-lite/APIKEY.txt
|
||||
# restart: always
|
||||
# fet2020:
|
||||
# image: fet2020django
|
||||
# build: .
|
||||
# environment:
|
||||
# HOST_NAME: andis.2020.fet.at
|
||||
# DEBUG: "False"
|
||||
# SECRET_KEY: arguiq3ebhnjo
|
||||
# MYSQL_USER: user
|
||||
# MYSQL_PASSWORD: hgu
|
||||
# MYSQL_PORT: 3306
|
||||
# depends_on:
|
||||
# - mysql
|
||||
# ports:
|
||||
# - "8106:8080"
|
||||
# volumes:
|
||||
# - ./fet2020:/app
|
||||
# - ./assets:/app/assets
|
||||
# - ./etherpad:/app/etherpad
|
||||
# - ./deployment/nginx.conf:/etc/nginx/conf.d/fet2020.conf
|
||||
# restart: always
|
||||
theia:
|
||||
image: theiaide/theia-python:latest
|
||||
image: docker.triton2.fet.at/theia-fet2020:latest
|
||||
volumes:
|
||||
- .:/home/project
|
||||
- ./etherpad/APIKEY.txt:/srv/etherpad/APIKEY.txt
|
||||
@@ -83,4 +48,6 @@ services:
|
||||
- "8106:8080"
|
||||
volumes:
|
||||
ep-mysql-volume:
|
||||
mysql-volume:
|
||||
driver: local
|
||||
foto-data:
|
||||
driver: local
|
||||
53
docker-compose.dev.yml
Normal file
53
docker-compose.dev.yml
Normal file
@@ -0,0 +1,53 @@
|
||||
version: "2"
|
||||
services:
|
||||
flaskfetfotos:
|
||||
image: docker.triton2.fet.at/flask-fet-fotos:latest
|
||||
environment:
|
||||
FLASK_DEBUG: 0
|
||||
FLASK_APP: main.py
|
||||
pages_root: /app/data
|
||||
etherpadsql:
|
||||
image: mariadb
|
||||
environment:
|
||||
MYSQL_DATABASE: etherpaddb
|
||||
MYSQL_USER: user
|
||||
MYSQL_PASSWORD: hgu
|
||||
MYSQL_COLLATION: utf8_general_ci
|
||||
MYSQL_CHARSET: utf8
|
||||
volumes:
|
||||
- ep-mysql:/var/lib/mysql
|
||||
etherpad:
|
||||
image: etherpad/etherpad
|
||||
environment:
|
||||
DB_TYPE: mysql
|
||||
DB_HOST: etherpadsql
|
||||
DB_PORT: 3306
|
||||
DB_NAME: etherpaddb
|
||||
DB_USER: user
|
||||
DB_PASS: hgu
|
||||
DB_CHARSET: utf8
|
||||
TRUST_PROXY: "true"
|
||||
REQUIRE_SESSION: "true"
|
||||
depends_on:
|
||||
- etherpadsql
|
||||
volumes:
|
||||
- /srv/etherpad/APIKEY.txt:/opt/etherpad-lite/APIKEY.txt
|
||||
theia:
|
||||
image: docker.triton2.fet.at/theia-fet2020:latest
|
||||
volumes:
|
||||
- dev_data:/home/project
|
||||
- /srv/etherpad/APIKEY.txt:/srv/etherpad/APIKEY.txt
|
||||
- theia_usr:/usr/local
|
||||
environment:
|
||||
HOST_NAME: andis.triton2.fet.at
|
||||
nginx:
|
||||
image: docker.triton2.fet.at/nginxdev-fet2020:latest
|
||||
ports:
|
||||
- "8106:8080"
|
||||
volumes:
|
||||
ep-mysql:
|
||||
driver: local
|
||||
theia_usr:
|
||||
driver: local
|
||||
dev_data:
|
||||
driver: local
|
||||
@@ -2,4 +2,4 @@ from django.apps import AppConfig
|
||||
|
||||
|
||||
class AuthenticationsConfig(AppConfig):
|
||||
name = 'authentications'
|
||||
name = "authentications"
|
||||
|
||||
@@ -11,25 +11,25 @@ def authentication(username, password):
|
||||
return None
|
||||
|
||||
# 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)
|
||||
|
||||
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)
|
||||
|
||||
has_user = False
|
||||
|
||||
try:
|
||||
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):
|
||||
if ("DN: uid=" + str(username.lower())) in str(user):
|
||||
has_user = True
|
||||
except LDAPBindError as e:
|
||||
logger.info('Username does not exist. Error: {}'.format(e))
|
||||
logger.info("Username does not exist. Error: {}".format(e))
|
||||
username = None
|
||||
except Exception as e:
|
||||
logger.info('Connection to server lost. Error: {}'.format(e))
|
||||
logger.info("Connection to server lost. Error: {}".format(e))
|
||||
username = None
|
||||
|
||||
if not has_user:
|
||||
|
||||
@@ -4,7 +4,7 @@ from django.shortcuts import redirect
|
||||
def unauthenticated_user(view_func):
|
||||
def wrapper_func(request, *args, **kwargs):
|
||||
if request.user.is_authenticated:
|
||||
return redirect('home')
|
||||
return redirect("home")
|
||||
else:
|
||||
return view_func(request, *args, **kwargs)
|
||||
|
||||
@@ -16,7 +16,7 @@ def authenticated_user(view_func):
|
||||
if request.user.is_authenticated:
|
||||
return view_func(request, *args, **kwargs)
|
||||
else:
|
||||
return redirect('login')
|
||||
return redirect("login")
|
||||
|
||||
return wrapper_func
|
||||
|
||||
|
||||
@@ -3,4 +3,4 @@ from django import forms
|
||||
|
||||
class LoginForm(forms.Form):
|
||||
username = forms.CharField()
|
||||
password = forms.CharField(label='Passwort', widget=forms.PasswordInput())
|
||||
password = forms.CharField(label="Passwort", widget=forms.PasswordInput())
|
||||
|
||||
@@ -3,6 +3,6 @@ from . import views
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path('login/', views.loginPage, name="login"),
|
||||
path('logout/', views.logoutUser, name="logout"),
|
||||
path("login/", views.loginPage, name="login"),
|
||||
path("logout/", views.logoutUser, name="logout"),
|
||||
]
|
||||
|
||||
@@ -12,9 +12,9 @@ from .forms import LoginForm
|
||||
|
||||
@unauthenticated_user
|
||||
def loginPage(request):
|
||||
if request.method == 'POST':
|
||||
username = request.POST.get('username')
|
||||
password = request.POST.get('password')
|
||||
if request.method == "POST":
|
||||
username = request.POST.get("username")
|
||||
password = request.POST.get("password")
|
||||
|
||||
auth_user = authentication(username, password)
|
||||
|
||||
@@ -25,23 +25,27 @@ def loginPage(request):
|
||||
user = User.objects.create_user(auth_user.lower())
|
||||
|
||||
login(request, user)
|
||||
return redirect('home')
|
||||
|
||||
try:
|
||||
return redirect(request.GET.get("next"))
|
||||
except:
|
||||
return redirect("home")
|
||||
else:
|
||||
messages.info(request, 'username or password is incorrect')
|
||||
messages.info(request, "username or password is incorrect")
|
||||
|
||||
form = LoginForm()
|
||||
|
||||
context = {
|
||||
"form": form,
|
||||
}
|
||||
return render(request, 'authentications/login.html', context)
|
||||
return render(request, "authentications/login.html", context)
|
||||
|
||||
|
||||
@authenticated_user
|
||||
def logoutUser(request):
|
||||
logout(request)
|
||||
|
||||
response = redirect('home')
|
||||
response = redirect("home")
|
||||
response = del_ep_cookie(request, response)
|
||||
|
||||
return response
|
||||
|
||||
@@ -8,7 +8,7 @@ class JobPostingAdmin(admin.ModelAdmin):
|
||||
form = JobPostingForm
|
||||
model = JobPosting
|
||||
|
||||
list_display = ['companyName', 'jobName', 'salary', 'publishDate']
|
||||
list_display = ["companyName", "jobName", "salary", "publishDate"]
|
||||
|
||||
|
||||
admin.site.register(JobPosting, JobPostingAdmin)
|
||||
|
||||
@@ -2,4 +2,4 @@ from django.apps import AppConfig
|
||||
|
||||
|
||||
class BlackboardConfig(AppConfig):
|
||||
name = 'blackboard'
|
||||
name = "blackboard"
|
||||
|
||||
@@ -7,19 +7,17 @@ from .models import JobPosting
|
||||
class JobPostingForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = JobPosting
|
||||
fields = ['companyName', 'jobName', 'salary', 'pdfLocation', 'publishDate']
|
||||
fields = ["companyName", "jobName", "salary", "pdfLocation", "publishDate"]
|
||||
|
||||
labels = {
|
||||
'companyName': _("Firmenname"),
|
||||
'jobName': _("Berufsbezeichnung"),
|
||||
'salary': _("Gehalt"),
|
||||
'pdfLocation': _("Stellenausschreibung"),
|
||||
'publishDate': _("Veröffentlichung"),
|
||||
"companyName": _("Firmenname"),
|
||||
"jobName": _("Berufsbezeichnung"),
|
||||
"salary": _("Gehalt"),
|
||||
"pdfLocation": _("Stellenausschreibung"),
|
||||
"publishDate": _("Veröffentlichung"),
|
||||
}
|
||||
|
||||
help_texts = {
|
||||
'pdfLocation': _(
|
||||
"Verwendbare Formate: PDF"
|
||||
),
|
||||
'salary': _("in Euro angeben"),
|
||||
"pdfLocation": _("Verwendbare Formate: PDF"),
|
||||
"salary": _("in Euro angeben"),
|
||||
}
|
||||
|
||||
@@ -11,16 +11,23 @@ from os.path import splitext, basename
|
||||
import ghostscript
|
||||
|
||||
import logging
|
||||
logger = logging.getLogger('blackboard')
|
||||
|
||||
logger = logging.getLogger("blackboard")
|
||||
|
||||
|
||||
class JobPosting(models.Model):
|
||||
companyName = models.CharField(verbose_name="Firmenname", max_length=128)
|
||||
jobName = models.CharField(verbose_name="Berufsbezeichnung", max_length=128)
|
||||
salary = models.PositiveSmallIntegerField(verbose_name="Gehalt", )
|
||||
pdfLocation = models.FileField(verbose_name="Stellenausschreibung", upload_to='uploads/blackboard/pdf/')
|
||||
salary = models.PositiveSmallIntegerField(
|
||||
verbose_name="Gehalt",
|
||||
)
|
||||
pdfLocation = models.FileField(
|
||||
verbose_name="Stellenausschreibung", upload_to="uploads/blackboard/pdf/"
|
||||
)
|
||||
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
|
||||
all_jobPosting = models.Manager()
|
||||
@@ -40,7 +47,7 @@ class JobPosting(models.Model):
|
||||
"-dDEVICEWIDTHPOINTS=600",
|
||||
"-dDEVICEHEIGHTPOINTS=800",
|
||||
"-sOutputFile=" + jpeg_output_path,
|
||||
pdf_input_path
|
||||
pdf_input_path,
|
||||
]
|
||||
|
||||
encoding = locale.getpreferredencoding()
|
||||
@@ -54,14 +61,18 @@ class JobPosting(models.Model):
|
||||
if not os.path.exists(settings.MEDIA_ROOT + "uploads/blackboard/thumb/"):
|
||||
os.makedirs(settings.MEDIA_ROOT + "uploads/blackboard/thumb/")
|
||||
|
||||
pdf_thumb_location_full = settings.MEDIA_ROOT \
|
||||
+ "uploads/blackboard/thumb/" \
|
||||
+ splitext(basename(self.pdfLocation.name))[0] \
|
||||
pdf_thumb_location_full = (
|
||||
settings.MEDIA_ROOT
|
||||
+ "uploads/blackboard/thumb/"
|
||||
+ splitext(basename(self.pdfLocation.name))[0]
|
||||
+ ".jpg"
|
||||
)
|
||||
|
||||
self.pdf_thumb_location = "/files/uploads/blackboard/thumb/" \
|
||||
+ splitext(basename(self.pdfLocation.name))[0] \
|
||||
self.pdf_thumb_location = (
|
||||
"/files/uploads/blackboard/thumb/"
|
||||
+ splitext(basename(self.pdfLocation.name))[0]
|
||||
+ ".jpg"
|
||||
)
|
||||
|
||||
self.pdf2jpeg(self.pdfLocation.path, pdf_thumb_location_full)
|
||||
logger.info("SavenThumbAs: " + self.pdf_thumb_location)
|
||||
@@ -70,7 +81,7 @@ class JobPosting(models.Model):
|
||||
def clean(self):
|
||||
count = 0
|
||||
for i in self.pdfLocation.name:
|
||||
if i == '.':
|
||||
if i == ".":
|
||||
count = count + 1
|
||||
if count > 1: # if more than one dot in filename
|
||||
raise ValidationError(_('Keine Dateien mit >1 Punkten im Namen erlaubt.'))
|
||||
raise ValidationError(_("Keine Dateien mit >1 Punkten im Namen erlaubt."))
|
||||
|
||||
@@ -4,5 +4,5 @@ from . import views
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path('', views.index, name='blackboard'),
|
||||
path("", views.index, name="blackboard"),
|
||||
]
|
||||
|
||||
@@ -10,8 +10,8 @@ from posts.models import Post
|
||||
def index(request):
|
||||
job_postings_cutoff = timezone.now().date() - timedelta(30) # 30days from now
|
||||
job_postings = JobPosting.all_jobPosting.filter(publishDate__gt=job_postings_cutoff)
|
||||
bb_info = Post.objects.filter(slug='blackboard').first()
|
||||
bb_empty = Post.objects.filter(slug='blackboard-empty').first()
|
||||
bb_info = Post.objects.filter(slug="blackboard").first()
|
||||
bb_empty = Post.objects.filter(slug="blackboard-empty").first()
|
||||
|
||||
context = {
|
||||
"job_postings": job_postings,
|
||||
@@ -19,4 +19,4 @@ def index(request):
|
||||
"bb_empty": bb_empty,
|
||||
}
|
||||
|
||||
return render(request, 'blackboard/index.html', context)
|
||||
return render(request, "blackboard/index.html", context)
|
||||
|
||||
@@ -6,6 +6,7 @@ import urllib.parse
|
||||
from etherpad_lite import EtherpadLiteClient, EtherpadException
|
||||
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
SERVER_URL = settings.ETHERPAD_CLIENT["exturl"]
|
||||
@@ -20,9 +21,11 @@ def get_ep_client():
|
||||
apikey = f.read()
|
||||
apikey = apikey.rstrip()
|
||||
epc = EtherpadLiteClient(
|
||||
base_params={'apikey': apikey, },
|
||||
base_params={
|
||||
"apikey": apikey,
|
||||
},
|
||||
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")
|
||||
except Exception as e:
|
||||
@@ -62,7 +65,9 @@ def createPadifNotExists(padID):
|
||||
# Pad doesn't exist
|
||||
if not __checkPadExists(padID=padID):
|
||||
try:
|
||||
epc.createGroupPad(groupID=group["groupID"], padName=padID, text="helloworld")
|
||||
epc.createGroupPad(
|
||||
groupID=group["groupID"], padName=padID, text="helloworld"
|
||||
)
|
||||
except EtherpadException as e:
|
||||
logger.info("Can't create Pad '{}'. EtherpadException: {}".format(padID, e))
|
||||
return None
|
||||
@@ -81,7 +86,9 @@ def getPadHTML(padID):
|
||||
try:
|
||||
text = epc.getHTML(padID=group["groupID"] + "$" + padID)["html"]
|
||||
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
|
||||
except Exception as e:
|
||||
raise e
|
||||
@@ -107,4 +114,6 @@ def get_pad_link(padID):
|
||||
if not epc or not group:
|
||||
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)
|
||||
)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
# from django.contrib.admin.apps import AdminConfig
|
||||
|
||||
|
||||
class DocumentsConfig(AppConfig):
|
||||
name = 'documents'
|
||||
name = "documents"
|
||||
|
||||
@@ -11,22 +11,21 @@ def __get_ep_sessionid(request):
|
||||
return None, None
|
||||
|
||||
author = epc.createAuthorIfNotExistsFor(
|
||||
name=str(request.user),
|
||||
authorMapper=str(request.user)
|
||||
)['authorID']
|
||||
name=str(request.user), authorMapper=str(request.user)
|
||||
)["authorID"]
|
||||
|
||||
expires = datetime.utcnow() + timedelta(hours=3)
|
||||
try:
|
||||
result = epc.createSession(
|
||||
groupID=str(group['groupID']),
|
||||
groupID=str(group["groupID"]),
|
||||
authorID=str(author),
|
||||
validUntil=str(int(expires.timestamp()))
|
||||
validUntil=str(int(expires.timestamp())),
|
||||
)
|
||||
except Exception as e:
|
||||
raise e
|
||||
return None, None
|
||||
|
||||
return result['sessionID'], expires
|
||||
return result["sessionID"], expires
|
||||
|
||||
|
||||
def add_ep_cookie(request, response):
|
||||
@@ -34,32 +33,19 @@ def add_ep_cookie(request, response):
|
||||
|
||||
if ep_sessid:
|
||||
response.set_cookie(
|
||||
"sessionID",
|
||||
ep_sessid,
|
||||
expires=expires,
|
||||
domain=".2020.fet.at",
|
||||
path="/"
|
||||
)
|
||||
response.set_cookie(
|
||||
"sessionID",
|
||||
ep_sessid,
|
||||
expires=expires,
|
||||
path="/etherpad"
|
||||
"sessionID", ep_sessid, expires=expires, domain=".2020.fet.at", path="/"
|
||||
)
|
||||
response.set_cookie("sessionID", ep_sessid, expires=expires, path="/etherpad")
|
||||
return response
|
||||
|
||||
|
||||
def del_ep_cookie(request, response):
|
||||
|
||||
if 'sessionID' in request.COOKIES:
|
||||
ep_sessionID = request.COOKIES['sessionID']
|
||||
if "sessionID" in request.COOKIES:
|
||||
ep_sessionID = request.COOKIES["sessionID"]
|
||||
|
||||
epc, group = get_ep_client()
|
||||
epc.deleteSession(sessionID=ep_sessionID)
|
||||
|
||||
response.delete_cookie(
|
||||
"sessionID",
|
||||
domain=".2020.fet.at",
|
||||
path="/"
|
||||
)
|
||||
response.delete_cookie("sessionID", domain=".2020.fet.at", path="/")
|
||||
return response
|
||||
|
||||
@@ -2,6 +2,6 @@ import os
|
||||
|
||||
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()
|
||||
|
||||
@@ -11,23 +11,23 @@ env = environ.Env(
|
||||
MYSQL_USER=(str),
|
||||
MYSQL_PASSWORD=(str),
|
||||
HOST_NAME=(str, "localhost"),
|
||||
ETHERPAD_PORT=(str,"9001"),
|
||||
ETHERPAD_HOST=(str,"etherpad2.2020.fet.at")
|
||||
ETHERPAD_PORT=(str, "9001"),
|
||||
ETHERPAD_HOST=(str, "etherpad2.2020.fet.at"),
|
||||
)
|
||||
|
||||
# Prints and logs are written to console
|
||||
# TODO: Change before release
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': False,
|
||||
'handlers': {
|
||||
'console': {
|
||||
'class': 'logging.StreamHandler',
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False,
|
||||
"handlers": {
|
||||
"console": {
|
||||
"class": "logging.StreamHandler",
|
||||
},
|
||||
},
|
||||
'root': {
|
||||
'handlers': ['console'],
|
||||
'level': 'DEBUG',
|
||||
"root": {
|
||||
"handlers": ["console"],
|
||||
"level": "DEBUG",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -41,108 +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/
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = env('DEBUG')
|
||||
DEBUG = env("DEBUG")
|
||||
if DEBUG:
|
||||
# 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:
|
||||
SECRET_KEY = env('SECRET_KEY')
|
||||
SECRET_KEY = env("SECRET_KEY")
|
||||
|
||||
|
||||
ALLOWED_HOSTS = ["127.0.0.1", env('HOST_NAME'), "2020.fet.at"]
|
||||
|
||||
HOST_NAME = env('HOST_NAME')
|
||||
HOST_NAME = env("HOST_NAME")
|
||||
|
||||
|
||||
DATA_UPLOAD_MAX_MEMORY_SIZE = 1024 * 1024 * 1024
|
||||
# Application definition
|
||||
CKEDITOR_UPLOAD_PATH = 'upload'
|
||||
CKEDITOR_UPLOAD_PATH = "upload"
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'django.contrib.admin',
|
||||
'django.contrib.admindocs',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'taggit',
|
||||
'ckeditor',
|
||||
'ckeditor_uploader',
|
||||
'easy_thumbnails',
|
||||
'rest_framework',
|
||||
'softhyphen',
|
||||
'django_crontab',
|
||||
'django_filters',
|
||||
'django_static_jquery_ui',
|
||||
'posts.apps.PostsConfig',
|
||||
'members.apps.MembersConfig',
|
||||
'documents.apps.DocumentsConfig',
|
||||
'blackboard.apps.BlackboardConfig',
|
||||
'tasks.apps.TasksConfig',
|
||||
"django.contrib.admin",
|
||||
"django.contrib.admindocs",
|
||||
"django.contrib.auth",
|
||||
"django.contrib.contenttypes",
|
||||
"django.contrib.sessions",
|
||||
"django.contrib.messages",
|
||||
"django.contrib.staticfiles",
|
||||
"taggit",
|
||||
"ckeditor",
|
||||
"ckeditor_uploader",
|
||||
"easy_thumbnails",
|
||||
"rest_framework",
|
||||
"softhyphen",
|
||||
"django_crontab",
|
||||
"django_filters",
|
||||
"django_static_jquery_ui",
|
||||
"posts.apps.PostsConfig",
|
||||
"members.apps.MembersConfig",
|
||||
"documents.apps.DocumentsConfig",
|
||||
"blackboard.apps.BlackboardConfig",
|
||||
"tasks.apps.TasksConfig",
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.locale.LocaleMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'fet2020.middleware.FETHeaderMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
"django.middleware.security.SecurityMiddleware",
|
||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||
"django.middleware.locale.LocaleMiddleware",
|
||||
"django.middleware.common.CommonMiddleware",
|
||||
"django.middleware.csrf.CsrfViewMiddleware",
|
||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||
"fet2020.middleware.FETHeaderMiddleware",
|
||||
"django.contrib.messages.middleware.MessageMiddleware",
|
||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'fet2020.urls'
|
||||
ROOT_URLCONF = "fet2020.urls"
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [
|
||||
os.path.join(BASE_DIR, 'templates'),
|
||||
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||
"DIRS": [
|
||||
os.path.join(BASE_DIR, "templates"),
|
||||
],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.template.context_processors.debug',
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
'django.template.context_processors.i18n',
|
||||
"APP_DIRS": True,
|
||||
"OPTIONS": {
|
||||
"context_processors": [
|
||||
"django.template.context_processors.debug",
|
||||
"django.template.context_processors.request",
|
||||
"django.contrib.auth.context_processors.auth",
|
||||
"django.contrib.messages.context_processors.messages",
|
||||
"django.template.context_processors.i18n",
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 'fet2020.wsgi.application'
|
||||
WSGI_APPLICATION = "fet2020.wsgi.application"
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
|
||||
if DEBUG:
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.sqlite3",
|
||||
"NAME": os.path.join(BASE_DIR, "db.sqlite3"),
|
||||
}
|
||||
}
|
||||
else:
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.mysql',
|
||||
'NAME': env('MYSQL_DATABASE'),
|
||||
'USER': env('MYSQL_USER'),
|
||||
'PASSWORD': env('MYSQL_PASSWORD'),
|
||||
'HOST': env('MYSQL_HOST'),
|
||||
'PORT': env('MYSQL_PORT')
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.mysql",
|
||||
"NAME": env("MYSQL_DATABASE"),
|
||||
"USER": env("MYSQL_USER"),
|
||||
"PASSWORD": env("MYSQL_PASSWORD"),
|
||||
"HOST": env("MYSQL_HOST"),
|
||||
"PORT": env("MYSQL_PORT"),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AUTHENTICATION_BACKENDS = [
|
||||
# 'django.contrib.auth.backends.RemoteUserBackend',
|
||||
'django.contrib.auth.backends.ModelBackend',
|
||||
"django.contrib.auth.backends.ModelBackend",
|
||||
]
|
||||
|
||||
# Password validation
|
||||
@@ -150,16 +149,16 @@ AUTHENTICATION_BACKENDS = [
|
||||
|
||||
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",
|
||||
},
|
||||
]
|
||||
|
||||
@@ -167,9 +166,9 @@ AUTH_PASSWORD_VALIDATORS = [
|
||||
# Internationalization
|
||||
# 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
|
||||
|
||||
@@ -177,32 +176,32 @@ USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
LOCALE_PATHS = [os.path.join(BASE_DIR, 'locale')]
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/3.0/howto/static-files/
|
||||
|
||||
STATIC_URL = '/assets/'
|
||||
STATIC_URL = "/assets/"
|
||||
|
||||
STATICFILES_DIRS = [
|
||||
os.path.join(BASE_DIR, "static")
|
||||
]
|
||||
STATIC_ROOT = 'assets/'
|
||||
MEDIA_ROOT = os.path.join(BASE_DIR, 'files/')
|
||||
MEDIA_URL = '/files/'
|
||||
STATICFILES_DIRS = [os.path.join(BASE_DIR, "static")]
|
||||
STATIC_ROOT = "assets/"
|
||||
MEDIA_ROOT = os.path.join(BASE_DIR, "files/")
|
||||
MEDIA_URL = "/files/"
|
||||
|
||||
TAGGIT_FORCE_LOWERCASE = True
|
||||
|
||||
CKEDITOR_CONFIGS = {
|
||||
'default': {
|
||||
'stylesSet': [
|
||||
"default": {
|
||||
"stylesSet": [
|
||||
{
|
||||
"name": 'Überschrift 2',
|
||||
"element": 'h2',
|
||||
"name": "Überschrift 2",
|
||||
"element": "h2",
|
||||
"attributes": {},
|
||||
},
|
||||
{
|
||||
"name": 'Code',
|
||||
"element": 'code',
|
||||
"name": "Code",
|
||||
"element": "code",
|
||||
"attributes": {"class": "code-block"},
|
||||
},
|
||||
],
|
||||
@@ -211,41 +210,41 @@ CKEDITOR_CONFIGS = {
|
||||
|
||||
# THUMBNAIL
|
||||
THUMBNAIL_ALIASES = {
|
||||
'': {
|
||||
'avatar': {'size': (50, 50), 'crop': True},
|
||||
'thumb': {'size': (150, 150), 'crop': True},
|
||||
"": {
|
||||
"avatar": {"size": (50, 50), "crop": True},
|
||||
"thumb": {"size": (150, 150), "crop": True},
|
||||
},
|
||||
}
|
||||
|
||||
# ETHERPAD CLIENT
|
||||
if DEBUG:
|
||||
ETHERPAD_CLIENT = {
|
||||
'url': "http://etherpad:"+env('ETHERPAD_PORT'),
|
||||
'exturl': env('ETHERPAD_HOST'),
|
||||
'apikey': "/srv/etherpad/APIKEY.txt"
|
||||
"url": "http://etherpad:" + env("ETHERPAD_PORT"),
|
||||
"exturl": env("ETHERPAD_HOST"),
|
||||
"apikey": "/srv/etherpad/APIKEY.txt",
|
||||
}
|
||||
else:
|
||||
ETHERPAD_CLIENT = {
|
||||
'url': "http://etherpad:"+env('ETHERPAD_PORT'),
|
||||
'exturl': urljoin('https://' + env('HOST_NAME'),"etherpad/"),
|
||||
'apikey': "/app/etherpad/APIKEY.txt"
|
||||
"url": "http://etherpad:" + env("ETHERPAD_PORT"),
|
||||
"exturl": urljoin("https://" + env("HOST_NAME"), "etherpad/"),
|
||||
"apikey": "/app/etherpad/APIKEY.txt",
|
||||
}
|
||||
|
||||
# REST FRAMEWORK
|
||||
REST_FRAMEWORK={
|
||||
'DEFAULT_PERMISSION_CLASSES_CLASSES':[
|
||||
'rest_framework.permissions.AllowAny',
|
||||
REST_FRAMEWORK = {
|
||||
"DEFAULT_PERMISSION_CLASSES_CLASSES": [
|
||||
"rest_framework.permissions.AllowAny",
|
||||
],
|
||||
'DEFAULT_AUTHENTICATION_CLASSES':()
|
||||
"DEFAULT_AUTHENTICATION_CLASSES": (),
|
||||
}
|
||||
|
||||
# DJANGO MAIL
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
||||
EMAIL_HOST = 'buran.htu.tuwien.ac.at'
|
||||
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
|
||||
EMAIL_HOST = "buran.htu.tuwien.ac.at"
|
||||
EMAIL_PORT = 587
|
||||
EMAIL_USE_TLS = True
|
||||
|
||||
# CRON JOBS
|
||||
CRONJOBS = [
|
||||
('0 16 * * *', 'posts.cronjobs.check_to_send_agenda_mail'),
|
||||
("0 16 * * *", "posts.cronjobs.check_to_send_agenda_mail"),
|
||||
]
|
||||
|
||||
@@ -4,31 +4,36 @@ from django.conf.urls.static import static
|
||||
from django.conf import settings
|
||||
from django.views.generic import RedirectView
|
||||
from . import views
|
||||
from posts.views import PostViewSet
|
||||
from posts.viewsets import PostViewSet
|
||||
from members.urls import member_urlpatterns, jobs_urlpatterns
|
||||
from members.views import MemberViewSet, JobViewSet, JobGroupViewSet, JobMemberViewSet
|
||||
from members.viewsets import (
|
||||
MemberViewSet,
|
||||
JobViewSet,
|
||||
JobGroupViewSet,
|
||||
JobMemberViewSet,
|
||||
)
|
||||
from rest_framework import routers
|
||||
|
||||
router = routers.DefaultRouter()
|
||||
router.register(r'posts', PostViewSet)
|
||||
router.register(r'members', MemberViewSet)
|
||||
router.register(r'jobgroups', JobGroupViewSet)
|
||||
router.register(r'jobs', JobViewSet)
|
||||
router.register(r'jobmembers', JobMemberViewSet)
|
||||
router.register(r"posts", PostViewSet)
|
||||
router.register(r"members", MemberViewSet)
|
||||
router.register(r"jobgroups", JobGroupViewSet)
|
||||
router.register(r"jobs", JobViewSet)
|
||||
router.register(r"jobmembers", JobMemberViewSet)
|
||||
|
||||
urlpatterns = [
|
||||
path('posts/', include('posts.urls')),
|
||||
path('admin/doc/', include('django.contrib.admindocs.urls')),
|
||||
path('admin/login/', RedirectView.as_view(pattern_name='login')),
|
||||
path('admin/', admin.site.urls),
|
||||
path('auth/', include('authentications.urls')),
|
||||
path('', views.index, name='home'),
|
||||
path('index.html', views.index, name='home'),
|
||||
path('ckeditor/', include('ckeditor_uploader.urls')),
|
||||
path('api/', include(router.urls)),
|
||||
path('members/', include('members.urls'), name='members'),
|
||||
path('jobs/', include(jobs_urlpatterns), name='jobs'),
|
||||
path('member/', include(member_urlpatterns), name='member'),
|
||||
path('blackboard/', include('blackboard.urls'), name='blackboard'),
|
||||
path('tasks/', include('tasks.urls'), name='tasks'),
|
||||
path("posts/", include("posts.urls")),
|
||||
path("admin/doc/", include("django.contrib.admindocs.urls")),
|
||||
path("admin/login/", RedirectView.as_view(pattern_name="login")),
|
||||
path("admin/", admin.site.urls),
|
||||
path("auth/", include("authentications.urls")),
|
||||
path("", views.index, name="home"),
|
||||
path("index.html", views.index, name="home"),
|
||||
path("ckeditor/", include("ckeditor_uploader.urls")),
|
||||
path("api/", include(router.urls)),
|
||||
path("members/", include("members.urls"), name="members"),
|
||||
path("jobs/", include(jobs_urlpatterns), name="jobs"),
|
||||
path("member/", include(member_urlpatterns), name="member"),
|
||||
path("blackboard/", include("blackboard.urls"), name="blackboard"),
|
||||
path("tasks/", include("tasks.urls"), name="tasks"),
|
||||
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from django.shortcuts import render
|
||||
|
||||
# from django.http import HttpResponse
|
||||
from collections import deque
|
||||
from posts.models import Post, FetMeeting, Event
|
||||
@@ -34,12 +35,12 @@ def index(request):
|
||||
featured_meeting = FetMeeting.objects.get_meetings()
|
||||
|
||||
context = {
|
||||
'posts': deque(list(posts)[:5]),
|
||||
'events': Event.all_events.get_five_events(),
|
||||
'featured_post': featured_post,
|
||||
'featured_event': featured_event,
|
||||
'featured_meeting': featured_meeting,
|
||||
'tags_list': " ".join(t)
|
||||
"posts": deque(list(posts)[:5]),
|
||||
"events": Event.all_events.get_five_events(),
|
||||
"featured_post": featured_post,
|
||||
"featured_event": featured_event,
|
||||
"featured_meeting": featured_meeting,
|
||||
"tags_list": " ".join(t),
|
||||
}
|
||||
|
||||
return render(request, 'home.html', context)
|
||||
return render(request, "home.html", context)
|
||||
|
||||
@@ -2,6 +2,6 @@ import os
|
||||
|
||||
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()
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
python manage.py makemigrations && python manage.py makemigrations posts members blackboard\
|
||||
&& python manage.py migrate
|
||||
python3 manage.py makemigrations && python3 manage.py makemigrations posts members blackboard\
|
||||
&& python3 manage.py migrate
|
||||
|
||||
BIN
fet2020/locale/de/LC_MESSAGES/django.mo
Normal file
BIN
fet2020/locale/de/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
346
fet2020/locale/de/LC_MESSAGES/django.po
Normal file
346
fet2020/locale/de/LC_MESSAGES/django.po
Normal 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"
|
||||
@@ -6,13 +6,13 @@ from .forms import MemberForm, JobForm, JobGroupForm
|
||||
|
||||
|
||||
class MemberRoleFilter(admin.SimpleListFilter):
|
||||
title = _('Rolle')
|
||||
parameter_name = 'role'
|
||||
title = _("Rolle")
|
||||
parameter_name = "role"
|
||||
|
||||
def lookups(self, request, model_admin):
|
||||
return (
|
||||
('A', _('Aktiv')),
|
||||
('P', _('Pension')),
|
||||
("A", _("Aktiv")),
|
||||
("P", _("Pension")),
|
||||
)
|
||||
|
||||
def queryset(self, request, queryset):
|
||||
@@ -55,40 +55,53 @@ class MemberAdmin(admin.ModelAdmin):
|
||||
form = MemberForm
|
||||
model = Member
|
||||
fieldsets = (
|
||||
(None, {
|
||||
'fields': (
|
||||
('firstname', 'surname',),
|
||||
'nickname',
|
||||
'username',
|
||||
'mailaccount',
|
||||
'role',
|
||||
'description',
|
||||
'image',
|
||||
'birthday',
|
||||
'phone',
|
||||
'address',
|
||||
)
|
||||
}),
|
||||
(
|
||||
None,
|
||||
{
|
||||
"fields": (
|
||||
(
|
||||
"firstname",
|
||||
"surname",
|
||||
),
|
||||
"nickname",
|
||||
"username",
|
||||
"mailaccount",
|
||||
"role",
|
||||
"description",
|
||||
"image",
|
||||
"birthday",
|
||||
"phone",
|
||||
"address",
|
||||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
inlines = (JobOverviewInline,)
|
||||
|
||||
list_display = ['nickname', 'firstname', 'surname', 'mailaccount', 'role']
|
||||
ordering = ['firstname', ]
|
||||
search_fields = ['firstname', 'surname', 'nickname', 'mailaccount']
|
||||
list_display = ["nickname", "firstname", "surname", "mailaccount", "role"]
|
||||
ordering = [
|
||||
"firstname",
|
||||
]
|
||||
search_fields = ["firstname", "surname", "nickname", "mailaccount"]
|
||||
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['help_text'] = "Fette Schriften sind Pflichtfelder."
|
||||
extra_context["help_text"] = "Fette Schriften sind Pflichtfelder."
|
||||
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['help_text'] = "Fette Schriften sind Pflichtfelder."
|
||||
extra_context["help_text"] = "Fette Schriften sind Pflichtfelder."
|
||||
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):
|
||||
@@ -101,22 +114,33 @@ class JobAdmin(admin.ModelAdmin):
|
||||
model = Job
|
||||
inlines = (ActiveMemberInline, InactiveMemberInline)
|
||||
|
||||
list_display = ['name', ]
|
||||
ordering = ['name', ]
|
||||
search_fields = ['name', ]
|
||||
list_display = [
|
||||
"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['help_text'] = "Fette Schriften sind Pflichtfelder."
|
||||
extra_context["help_text"] = "Fette Schriften sind Pflichtfelder."
|
||||
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['help_text'] = "Fette Schriften sind Pflichfelder."
|
||||
extra_context["help_text"] = "Fette Schriften sind Pflichfelder."
|
||||
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):
|
||||
@@ -127,24 +151,36 @@ class JobAdmin(admin.ModelAdmin):
|
||||
class JobGroupAdmin(admin.ModelAdmin):
|
||||
form = JobGroupForm
|
||||
model = JobGroup
|
||||
inlines = (JobInline, )
|
||||
inlines = (JobInline,)
|
||||
|
||||
list_display = ['name', 'is_pinned', ]
|
||||
ordering = ['name', ]
|
||||
search_fields = ['name', ]
|
||||
list_display = [
|
||||
"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['help_text'] = "Fette Schriften sind Pflichtfelder."
|
||||
extra_context["help_text"] = "Fette Schriften sind Pflichtfelder."
|
||||
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['help_text'] = "Fette Schriften sind Pflichfelder."
|
||||
extra_context["help_text"] = "Fette Schriften sind Pflichfelder."
|
||||
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):
|
||||
|
||||
@@ -2,4 +2,4 @@ from django.apps import AppConfig
|
||||
|
||||
|
||||
class MembersConfig(AppConfig):
|
||||
name = 'members'
|
||||
name = "members"
|
||||
|
||||
@@ -10,56 +10,68 @@ class MemberForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Member
|
||||
fields = [
|
||||
'firstname', 'surname', 'nickname', 'username', 'mailaccount', 'role', 'description',
|
||||
'image', 'birthday', 'phone', 'address',
|
||||
"firstname",
|
||||
"surname",
|
||||
"nickname",
|
||||
"username",
|
||||
"mailaccount",
|
||||
"role",
|
||||
"description",
|
||||
"image",
|
||||
"birthday",
|
||||
"phone",
|
||||
"address",
|
||||
]
|
||||
|
||||
widgets = {
|
||||
'description': CKEditorUploadingWidget(config_name='default')
|
||||
}
|
||||
widgets = {"description": CKEditorUploadingWidget(config_name="default")}
|
||||
|
||||
labels = {
|
||||
'description': _("Beschreibung zu der Person"),
|
||||
'image': _("Porträt"),
|
||||
'birthday': _("Geburtstag"),
|
||||
'phone': _("Telefonnummer"),
|
||||
'address': _("Wohnadresse"),
|
||||
"description": _("Beschreibung zu der Person"),
|
||||
"image": _("Porträt"),
|
||||
"birthday": _("Geburtstag"),
|
||||
"phone": _("Telefonnummer"),
|
||||
"address": _("Wohnadresse"),
|
||||
}
|
||||
|
||||
help_texts = {
|
||||
'image': _(
|
||||
"Mindestgröße: 150*150 px, Verwendbare Formate: ..."
|
||||
),
|
||||
'mailaccount': _(
|
||||
"Die Mailadresse mit '@fet.at' angeben."
|
||||
),
|
||||
"image": _("Mindestgröße: 150*150 px, Verwendbare Formate: ..."),
|
||||
"mailaccount": _("Die Mailadresse mit '@fet.at' angeben."),
|
||||
}
|
||||
|
||||
|
||||
class JobForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Job
|
||||
fields = ['name', 'shortterm', 'slug', 'job_group',]
|
||||
fields = [
|
||||
"name",
|
||||
"shortterm",
|
||||
"slug",
|
||||
"job_group",
|
||||
]
|
||||
|
||||
labels = {
|
||||
'shortterm': _("Kürzel der Tätigkeit"),
|
||||
'job_group': _("Tätigkeitsbereich"),
|
||||
"shortterm": _("Kürzel der Tätigkeit"),
|
||||
"job_group": _("Tätigkeitsbereich"),
|
||||
}
|
||||
|
||||
|
||||
class JobGroupForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = JobGroup
|
||||
fields = ['name', 'shortterm', 'slug', 'description', 'is_pinned',]
|
||||
fields = [
|
||||
"name",
|
||||
"shortterm",
|
||||
"slug",
|
||||
"description",
|
||||
"is_pinned",
|
||||
]
|
||||
|
||||
widgets = {
|
||||
'description': CKEditorUploadingWidget(config_name='default')
|
||||
}
|
||||
widgets = {"description": CKEditorUploadingWidget(config_name="default")}
|
||||
|
||||
labels = {
|
||||
'shortterm': _("Kürzel des Tätigkeitsbereichs"),
|
||||
'description': _("Beschreibung des Tätigkeitsbereichs"),
|
||||
'is_pinned': _(
|
||||
"shortterm": _("Kürzel des Tätigkeitsbereichs"),
|
||||
"description": _("Beschreibung des Tätigkeitsbereichs"),
|
||||
"is_pinned": _(
|
||||
"Dieser Tätigkeitsbereich soll im Fachschaftsbereich angeheftet werden, damit es sofort ersichtlich ist."
|
||||
),
|
||||
}
|
||||
|
||||
@@ -10,15 +10,20 @@ from easy_thumbnails.fields import ThumbnailerImageField
|
||||
|
||||
|
||||
class ActiveJobMemberManager(models.Manager):
|
||||
'''
|
||||
"""
|
||||
return a list of active member, and members who are still working
|
||||
'''
|
||||
"""
|
||||
|
||||
def get_all_by_slug(self, slug):
|
||||
return self.get_queryset().filter(job__job_group__slug=slug).order_by('job__slug', 'job_role', 'member__firstname')
|
||||
return (
|
||||
self.get_queryset()
|
||||
.filter(job__job_group__slug=slug)
|
||||
.order_by("job__slug", "job_role", "member__firstname")
|
||||
)
|
||||
|
||||
def get_queryset(self):
|
||||
date_today = timezone.now().date()
|
||||
qs = super().get_queryset().order_by('member__firstname')
|
||||
qs = super().get_queryset().order_by("member__firstname")
|
||||
|
||||
return qs.filter(
|
||||
Q(member__role=Member.MemberRole.ACTIVE)
|
||||
@@ -27,15 +32,20 @@ class ActiveJobMemberManager(models.Manager):
|
||||
|
||||
|
||||
class InactiveJobMemberManager(models.Manager):
|
||||
'''
|
||||
"""
|
||||
return a list of inactive member
|
||||
'''
|
||||
"""
|
||||
|
||||
def get_all_by_slug(self, slug):
|
||||
return self.get_queryset().filter(job__job_group__slug=slug).order_by('job__slug', 'job_role', 'member__firstname')
|
||||
return (
|
||||
self.get_queryset()
|
||||
.filter(job__job_group__slug=slug)
|
||||
.order_by("job__slug", "job_role", "member__firstname")
|
||||
)
|
||||
|
||||
def get_queryset(self):
|
||||
date_today = timezone.now().date()
|
||||
qs = super().get_queryset().order_by('member__firstname')
|
||||
qs = super().get_queryset().order_by("member__firstname")
|
||||
|
||||
return qs.filter(
|
||||
Q(member__role=Member.MemberRole.PENSION)
|
||||
@@ -45,7 +55,7 @@ class InactiveJobMemberManager(models.Manager):
|
||||
|
||||
class JobMemberManager(models.Manager):
|
||||
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))
|
||||
|
||||
@@ -82,19 +92,19 @@ class JobGroupManager(models.Manager):
|
||||
|
||||
class MemberManager(models.Manager):
|
||||
def get_queryset(self):
|
||||
return super().get_queryset().order_by('firstname')
|
||||
return super().get_queryset().order_by("firstname")
|
||||
|
||||
|
||||
class Member(models.Model):
|
||||
firstname = models.CharField("Vorname", max_length=128)
|
||||
surname = models.CharField("Nachname", max_length=128)
|
||||
nickname = models.CharField("Spitzname", max_length=128)
|
||||
nickname = models.CharField("Spitzname", max_length=128)
|
||||
username = models.CharField("Benutzername", blank=True, max_length=128)
|
||||
mailaccount = models.CharField("Mailadresse", unique=True, max_length=128)
|
||||
|
||||
class MemberRole(models.TextChoices):
|
||||
ACTIVE = 'A', _('Active')
|
||||
PENSION = 'P', _('Pension')
|
||||
ACTIVE = "A", _("Active")
|
||||
PENSION = "P", _("Pension")
|
||||
|
||||
role = models.CharField(
|
||||
"Rolle",
|
||||
@@ -104,14 +114,16 @@ class Member(models.Model):
|
||||
)
|
||||
|
||||
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)
|
||||
|
||||
phone_error_msg = _((
|
||||
"Phone number must be entered in the format: +999999999'. Up to 15 digits allowed."
|
||||
))
|
||||
phone_regex = RegexValidator(regex=r'^\+?1?\d{9,15}$', message=phone_error_msg)
|
||||
phone_error_msg = _(
|
||||
(
|
||||
"Phone number must be entered in the format: +999999999'. Up to 15 digits allowed."
|
||||
)
|
||||
)
|
||||
phone_regex = RegexValidator(regex=r"^\+?1?\d{9,15}$", message=phone_error_msg)
|
||||
phone = models.CharField(validators=[phone_regex], max_length=17, blank=True)
|
||||
|
||||
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:
|
||||
raise ValidationError(
|
||||
_("Das Bild ist zu klein. (Höhe: {}, Breite: {})").format(
|
||||
self.image.height,
|
||||
self.image.width
|
||||
self.image.height, self.image.width
|
||||
)
|
||||
)
|
||||
|
||||
if not "@fet.at" in self.mailaccount:
|
||||
raise ValidationError(
|
||||
_("In der Mailadresse fehlt die Domäne.")
|
||||
)
|
||||
raise ValidationError(_("In der Mailadresse fehlt die Domäne."))
|
||||
|
||||
def __str__(self):
|
||||
return self.firstname + " " + self.surname
|
||||
@@ -198,7 +207,7 @@ class Job(models.Model):
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.slug:
|
||||
self.slug = slugify(self.shortterm)
|
||||
#if type(self.job_group) = str:
|
||||
# if type(self.job_group) = str:
|
||||
# self.job_group=JobGroup.objects.filter(slug=self.job)
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
@@ -218,18 +227,20 @@ class JobMember(models.Model):
|
||||
verbose_name="Tätigkeit",
|
||||
)
|
||||
|
||||
job_start = models.DateField('Job Start')
|
||||
job_end = models.DateField('Job Ende', null=True, blank=True)
|
||||
job_start = models.DateField("Job Start")
|
||||
job_end = models.DateField("Job Ende", null=True, blank=True)
|
||||
|
||||
class JobRole(models.TextChoices):
|
||||
PRESIDENT = ('10', _('VorsitzendeR'))
|
||||
VICE_PRESIDENT = ('20', _('stv VorsitzendeR'))
|
||||
SECOND_VICE_PRESIDENT = ('30', _('2. stv VorsitzendeR'))
|
||||
PERSON_RESPONSIBLE = ('40', _('VerantwortlicheR'))
|
||||
MEMBER = ('50', _('Mitglied'))
|
||||
SUBSTITUTE_MEMBER = ('60', _('Ersatzmitglied'))
|
||||
PRESIDENT = ("10", _("VorsitzendeR"))
|
||||
VICE_PRESIDENT = ("20", _("stv VorsitzendeR"))
|
||||
SECOND_VICE_PRESIDENT = ("30", _("2. stv VorsitzendeR"))
|
||||
PERSON_RESPONSIBLE = ("40", _("VerantwortlicheR"))
|
||||
MEMBER = ("50", _("Mitglied"))
|
||||
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()
|
||||
members = JobMemberManager()
|
||||
|
||||
@@ -4,65 +4,50 @@ from rest_framework import serializers
|
||||
|
||||
|
||||
class MemberSerializer(serializers.HyperlinkedModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = Member
|
||||
fields = ['id',
|
||||
'firstname',
|
||||
'surname',
|
||||
'nickname',
|
||||
'mailaccount',
|
||||
'role',
|
||||
'description',
|
||||
'image',
|
||||
'birthday',
|
||||
fields = [
|
||||
"id",
|
||||
"firstname",
|
||||
"surname",
|
||||
"nickname",
|
||||
"mailaccount",
|
||||
"role",
|
||||
"description",
|
||||
"image",
|
||||
"birthday",
|
||||
]
|
||||
|
||||
|
||||
class JobGroupSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = JobGroup
|
||||
fields = [
|
||||
'id',
|
||||
'name',
|
||||
'shortterm',
|
||||
'slug'
|
||||
]
|
||||
fields = ["id", "name", "shortterm", "slug"]
|
||||
|
||||
|
||||
class JobSerializer(serializers.HyperlinkedModelSerializer):
|
||||
#job_group = JobGroupSerializer()
|
||||
# job_group = JobGroupSerializer()
|
||||
job_group = serializers.SlugRelatedField(
|
||||
slug_field='slug',queryset = JobGroup.objects
|
||||
)
|
||||
slug_field="slug", queryset=JobGroup.objects
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Job
|
||||
fields = [
|
||||
'id',
|
||||
'name',
|
||||
'shortterm',
|
||||
'job_group',
|
||||
'slug'
|
||||
]
|
||||
fields = ["id", "name", "shortterm", "job_group", "slug"]
|
||||
|
||||
|
||||
class JobMemberSerializer(serializers.HyperlinkedModelSerializer):
|
||||
#member = MemberSerializer()
|
||||
#job = JobSerializer()
|
||||
job = serializers.SlugRelatedField(
|
||||
slug_field='slug',queryset = Job.objects
|
||||
)
|
||||
member= serializers.SlugRelatedField(
|
||||
slug_field='mailaccount',queryset = Member.objects
|
||||
)
|
||||
# member = MemberSerializer()
|
||||
# job = JobSerializer()
|
||||
job = serializers.SlugRelatedField(slug_field="slug", queryset=Job.objects)
|
||||
member = serializers.SlugRelatedField(
|
||||
slug_field="mailaccount", queryset=Member.objects
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = JobMember
|
||||
fields = [
|
||||
'id',
|
||||
'job_start',
|
||||
'job_end',
|
||||
'member',
|
||||
'job',
|
||||
'job_role'
|
||||
]
|
||||
fields = ["id", "job_start", "job_end", "member", "job", "job_role"]
|
||||
|
||||
|
||||
# def create(self, validated_data):
|
||||
# member_data = validated_data.pop('member')
|
||||
|
||||
@@ -4,14 +4,14 @@ from . import views
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path('', views.index, name='members'),
|
||||
path('<str:filter>', views.members_view),
|
||||
path("", views.index, name="members"),
|
||||
path("<str:filter>", views.members_view),
|
||||
]
|
||||
|
||||
member_urlpatterns = [
|
||||
path('<str:member_id>', views.profile_view, name='member'),
|
||||
path("<str:member_id>", views.profile_view, name="member"),
|
||||
]
|
||||
|
||||
jobs_urlpatterns = [
|
||||
path('<str:slug>', views.jobs_view, name='jobs'),
|
||||
path("<str:slug>", views.jobs_view, name="jobs"),
|
||||
]
|
||||
|
||||
@@ -2,15 +2,12 @@ from django.http import Http404
|
||||
from django.shortcuts import render
|
||||
|
||||
from collections import deque
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
|
||||
from .models import Member, JobMember, JobGroup, Job
|
||||
from .serializers import MemberSerializer, JobSerializer, JobGroupSerializer, JobMemberSerializer
|
||||
|
||||
from rest_framework import viewsets
|
||||
#from rest_framework import permissions
|
||||
from posts.models import Post
|
||||
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -45,20 +42,25 @@ def index(request):
|
||||
pinned_job_groups, unpinned_job_groups = __get_job_groups()
|
||||
members = deque(Member.all_members.all())
|
||||
|
||||
fs_info = Post.objects.filter(slug="fachschaft-info").first()
|
||||
|
||||
context = {
|
||||
"pinned_job_groups": pinned_job_groups,
|
||||
"unpinned_job_groups": unpinned_job_groups,
|
||||
"members": members,
|
||||
"fs_info": fs_info,
|
||||
}
|
||||
|
||||
return render(request, 'members/index.html', context)
|
||||
return render(request, "members/index.html", context)
|
||||
|
||||
|
||||
def jobs_view(request, slug=None):
|
||||
pinned_job_groups, unpinned_job_groups = __get_job_groups()
|
||||
|
||||
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:
|
||||
logger.info("Wrong job '{}'".format(slug))
|
||||
raise Http404("wrong job")
|
||||
@@ -72,7 +74,7 @@ def jobs_view(request, slug=None):
|
||||
"job_members": job_members,
|
||||
}
|
||||
|
||||
return render(request, 'members/index.html', context)
|
||||
return render(request, "members/index.html", context)
|
||||
|
||||
|
||||
def members_view(request, filter=None):
|
||||
@@ -84,13 +86,16 @@ def members_view(request, filter=None):
|
||||
logger.info("Wrong member role '{}'".format(filter))
|
||||
raise Http404("no member role")
|
||||
|
||||
fs_info = Post.objects.filter(slug="fachschaft-info").first()
|
||||
|
||||
context = {
|
||||
"pinned_job_groups": pinned_job_groups,
|
||||
"unpinned_job_groups": unpinned_job_groups,
|
||||
"members": members,
|
||||
"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):
|
||||
@@ -110,53 +115,4 @@ def profile_view(request, member_id=None):
|
||||
"jobs": jobs,
|
||||
}
|
||||
|
||||
return render(request, 'members/member.html', context)
|
||||
|
||||
|
||||
class MemberViewSet(viewsets.ModelViewSet):
|
||||
"""
|
||||
API endpoint that allows users to be viewed or edited.
|
||||
"""
|
||||
queryset = Member.all_members.order_by('nickname')
|
||||
serializer_class = MemberSerializer
|
||||
|
||||
#permission_classes = [permissions.IsAuthenticated]
|
||||
filter_backends = [DjangoFilterBackend]
|
||||
filterset_fields = ['nickname','mailaccount']
|
||||
# lookup_field = 'name'
|
||||
|
||||
def pre_save(self, obj):
|
||||
obj.image = self.request.FILES.get('image')
|
||||
|
||||
|
||||
class JobGroupViewSet(viewsets.ModelViewSet):
|
||||
"""
|
||||
API endpoint that allows users to be viewed or edited.
|
||||
"""
|
||||
queryset = JobGroup.all_jobgroups.all()
|
||||
serializer_class = JobGroupSerializer
|
||||
|
||||
filter_backends = [DjangoFilterBackend]
|
||||
filterset_fields = ['name','slug']
|
||||
#lookup_field = 'name'
|
||||
# lookup_field = 'name'
|
||||
|
||||
class JobViewSet(viewsets.ModelViewSet):
|
||||
"""
|
||||
API endpoint that allows users to be viewed or edited.
|
||||
"""
|
||||
queryset = Job.objects.all()
|
||||
serializer_class = JobSerializer
|
||||
filter_backends = [DjangoFilterBackend]
|
||||
filterset_fields = ['name','slug']
|
||||
#lookup_field = 'slug'
|
||||
|
||||
class JobMemberViewSet(viewsets.ModelViewSet):
|
||||
"""
|
||||
API endpoint that allows users to be viewed or edited.
|
||||
"""
|
||||
queryset = JobMember.objects.all()
|
||||
serializer_class = JobMemberSerializer
|
||||
filter_backends = [DjangoFilterBackend]
|
||||
filterset_fields = ['member','job','job_role','job_start']
|
||||
#lookup_field = 'nickname'
|
||||
return render(request, "members/member.html", context)
|
||||
|
||||
64
fet2020/members/viewsets.py
Normal file
64
fet2020/members/viewsets.py
Normal file
@@ -0,0 +1,64 @@
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from rest_framework import viewsets
|
||||
|
||||
from .models import Member, JobMember, JobGroup, Job
|
||||
from .serializers import (
|
||||
MemberSerializer,
|
||||
JobSerializer,
|
||||
JobGroupSerializer,
|
||||
JobMemberSerializer,
|
||||
)
|
||||
|
||||
|
||||
class MemberViewSet(viewsets.ModelViewSet):
|
||||
"""
|
||||
API endpoint that allows users to be viewed or edited.
|
||||
"""
|
||||
|
||||
queryset = Member.all_members.order_by("nickname")
|
||||
serializer_class = MemberSerializer
|
||||
|
||||
# permission_classes = [permissions.IsAuthenticated]
|
||||
filter_backends = [DjangoFilterBackend]
|
||||
filterset_fields = ["nickname", "mailaccount"]
|
||||
# lookup_field = 'name'
|
||||
|
||||
def pre_save(self, obj):
|
||||
obj.image = self.request.FILES.get("image")
|
||||
|
||||
|
||||
class JobGroupViewSet(viewsets.ModelViewSet):
|
||||
"""
|
||||
API endpoint that allows users to be viewed or edited.
|
||||
"""
|
||||
|
||||
queryset = JobGroup.all_jobgroups.all()
|
||||
serializer_class = JobGroupSerializer
|
||||
|
||||
filter_backends = [DjangoFilterBackend]
|
||||
filterset_fields = ["name", "slug"]
|
||||
# lookup_field = 'name'
|
||||
|
||||
|
||||
class JobViewSet(viewsets.ModelViewSet):
|
||||
"""
|
||||
API endpoint that allows users to be viewed or edited.
|
||||
"""
|
||||
|
||||
queryset = Job.objects.all()
|
||||
serializer_class = JobSerializer
|
||||
filter_backends = [DjangoFilterBackend]
|
||||
filterset_fields = ["name", "slug"]
|
||||
# lookup_field = 'slug'
|
||||
|
||||
|
||||
class JobMemberViewSet(viewsets.ModelViewSet):
|
||||
"""
|
||||
API endpoint that allows users to be viewed or edited.
|
||||
"""
|
||||
|
||||
queryset = JobMember.objects.all()
|
||||
serializer_class = JobMemberSerializer
|
||||
filter_backends = [DjangoFilterBackend]
|
||||
filterset_fields = ["member", "job", "job_role", "job_start"]
|
||||
# lookup_field = 'nickname'
|
||||
@@ -13,7 +13,7 @@ admin.site.unregister(taggit.models.Tag)
|
||||
|
||||
|
||||
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
|
||||
agenda_key = None
|
||||
@@ -24,7 +24,7 @@ def make_fetmeeting(self, request, queryset):
|
||||
except Exception as e:
|
||||
self.message_user(
|
||||
request,
|
||||
_('Das Agenda konnte nicht erstellt werden. Error: %s') % str(e),
|
||||
_("Das Agenda konnte nicht erstellt werden. Error: %s") % str(e),
|
||||
messages.ERROR,
|
||||
)
|
||||
failed = True
|
||||
@@ -34,14 +34,14 @@ def make_fetmeeting(self, request, queryset):
|
||||
except Exception as e:
|
||||
self.message_user(
|
||||
request,
|
||||
_('Das Protokoll konnte nicht erstellt werden. Error: %s') % str(e),
|
||||
_("Das Protokoll konnte nicht erstellt werden. Error: %s") % str(e),
|
||||
messages.ERROR,
|
||||
)
|
||||
failed = True
|
||||
|
||||
if not failed:
|
||||
queryset.update(
|
||||
post_type='F',
|
||||
post_type="F",
|
||||
has_agenda=True,
|
||||
has_protocol=True,
|
||||
agenda_key=agenda_key,
|
||||
@@ -49,7 +49,8 @@ def make_fetmeeting(self, request, queryset):
|
||||
)
|
||||
self.message_user(
|
||||
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,
|
||||
)
|
||||
|
||||
@@ -60,22 +61,27 @@ make_fetmeeting.short_description = "In eine Fachschaftssitzung konvertieren"
|
||||
class PostAdmin(admin.ModelAdmin):
|
||||
form = PostForm
|
||||
model = Post
|
||||
list_filter = ['is_pinned', 'is_hidden']
|
||||
list_display = ['title', 'slug', 'public_date', 'is_pinned', 'is_hidden']
|
||||
ordering = ['is_hidden', '-public_date']
|
||||
list_filter = ["is_pinned", "is_hidden"]
|
||||
list_display = ["title", "slug", "public_date", "is_pinned", "is_hidden"]
|
||||
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['help_text'] = "Fette Schriften sind Pflichtfelder."
|
||||
extra_context["help_text"] = "Fette Schriften sind Pflichtfelder."
|
||||
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['help_text'] = "Fette Schriften sind Pflichtfelder."
|
||||
extra_context["help_text"] = "Fette Schriften sind Pflichtfelder."
|
||||
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):
|
||||
@@ -98,9 +104,9 @@ class PostAdmin(admin.ModelAdmin):
|
||||
class EventAdmin(PostAdmin):
|
||||
form = EventForm
|
||||
model = Event
|
||||
list_filter = ['is_pinned']
|
||||
list_display = ['title', 'slug', 'event_start', 'public_date', 'is_pinned']
|
||||
ordering = ['-event_start']
|
||||
list_filter = ["is_pinned"]
|
||||
list_display = ["title", "slug", "event_start", "public_date", "is_pinned"]
|
||||
ordering = ["-event_start"]
|
||||
actions = [make_fetmeeting]
|
||||
|
||||
|
||||
@@ -113,7 +119,7 @@ class FetMeetingAdmin(EventAdmin):
|
||||
form = FetMeetingForm
|
||||
model = FetMeeting
|
||||
list_filter = []
|
||||
list_display = ['title', 'slug', 'event_start', 'public_date']
|
||||
list_display = ["title", "slug", "event_start", "public_date"]
|
||||
actions = []
|
||||
|
||||
|
||||
|
||||
@@ -2,4 +2,4 @@ from django.apps import AppConfig
|
||||
|
||||
|
||||
class PostsConfig(AppConfig):
|
||||
name = 'posts'
|
||||
name = "posts"
|
||||
|
||||
@@ -10,14 +10,23 @@ from .models import Post, Event, News, FetMeeting
|
||||
class PostForm(forms.ModelForm):
|
||||
class Meta:
|
||||
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:
|
||||
js = (
|
||||
'js/auto_slug.js', # automatic slag completion via ajax
|
||||
'js/tag_completion.js', # to get a list for tag autocompletion via ajax
|
||||
"js/auto_slug.js", # automatic slag completion via ajax
|
||||
"js/tag_completion.js", # to get a list for tag autocompletion via ajax
|
||||
)
|
||||
|
||||
|
||||
@@ -25,106 +34,124 @@ class NewsForm(PostForm):
|
||||
class Meta:
|
||||
model = News
|
||||
fields = [
|
||||
'title', 'subtitle', 'tags', 'image', 'body', 'slug', 'author', 'public_date',
|
||||
'is_pinned', 'is_hidden',
|
||||
"title",
|
||||
"subtitle",
|
||||
"tags",
|
||||
"image",
|
||||
"body",
|
||||
"slug",
|
||||
"author",
|
||||
"public_date",
|
||||
"is_pinned",
|
||||
"is_hidden",
|
||||
]
|
||||
|
||||
labels = {
|
||||
'title': _("Titel"),
|
||||
'subtitle': _("Untertitel"),
|
||||
'image': _("Hintergrundbild"),
|
||||
'body': _("Text"),
|
||||
'author': _("Autor"),
|
||||
'public_date': _("Veröffentlichung"),
|
||||
'is_pinned': _("Post anheften"),
|
||||
'is_hidden': _("Post verstecken"),
|
||||
"title": _("Titel"),
|
||||
"subtitle": _("Untertitel"),
|
||||
"image": _("Hintergrundbild"),
|
||||
"body": _("Text"),
|
||||
"author": _("Autor"),
|
||||
"public_date": _("Veröffentlichung"),
|
||||
"is_pinned": _("Post anheften"),
|
||||
"is_hidden": _("Post verstecken"),
|
||||
}
|
||||
|
||||
help_texts = {
|
||||
'tags': _(
|
||||
"tags": _(
|
||||
"Die Hashtags ohne '#' eintragen, und mit Komma kann man mehrere Tags anfügen."
|
||||
),
|
||||
'image': _(
|
||||
"Verwendbare Formate: ..."
|
||||
),
|
||||
'is_pinned': _(
|
||||
"image": _("Verwendbare Formate: ..."),
|
||||
"is_pinned": _(
|
||||
"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."
|
||||
),
|
||||
}
|
||||
|
||||
widgets = {'body': CKEditorUploadingWidget(config_name='default')}
|
||||
widgets = {"body": CKEditorUploadingWidget(config_name="default")}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
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 Meta:
|
||||
model = Event
|
||||
fields = [
|
||||
'title', 'subtitle', 'tags', 'image', 'body', 'event_start', 'event_end',
|
||||
'event_place', 'slug', 'author', 'public_date', 'is_pinned',
|
||||
"title",
|
||||
"subtitle",
|
||||
"tags",
|
||||
"image",
|
||||
"body",
|
||||
"event_start",
|
||||
"event_end",
|
||||
"event_place",
|
||||
"slug",
|
||||
"author",
|
||||
"public_date",
|
||||
"is_pinned",
|
||||
]
|
||||
|
||||
labels = {
|
||||
'title': _("Titel"),
|
||||
'subtitle': _("Untertitel"),
|
||||
'image': _("Hintergrundbild"),
|
||||
'body': _("Text"),
|
||||
'event_start': _("Start des Events"),
|
||||
'event_end': _("Ende des Events"),
|
||||
'event_place': _("Ort des Events"),
|
||||
'author': _("Autor"),
|
||||
'public_date': _("Veröffentlichung"),
|
||||
'is_pinned': _("Event anheften"),
|
||||
"title": _("Titel"),
|
||||
"subtitle": _("Untertitel"),
|
||||
"image": _("Hintergrundbild"),
|
||||
"body": _("Text"),
|
||||
"event_start": _("Start des Events"),
|
||||
"event_end": _("Ende des Events"),
|
||||
"event_place": _("Ort des Events"),
|
||||
"author": _("Autor"),
|
||||
"public_date": _("Veröffentlichung"),
|
||||
"is_pinned": _("Event anheften"),
|
||||
}
|
||||
|
||||
help_texts = {
|
||||
'tags': _(
|
||||
"tags": _(
|
||||
"Die Hashtags ohne '#' eintragen, und mit Komma kann man mehrere Tags anfügen."
|
||||
),
|
||||
'image': _(
|
||||
"Verwendbare Formate: "
|
||||
),
|
||||
'is_pinned': _(
|
||||
"image": _("Verwendbare Formate: "),
|
||||
"is_pinned": _(
|
||||
"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):
|
||||
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_end'].required = False
|
||||
self.fields["event_start"].required = True
|
||||
self.fields["event_end"].required = False
|
||||
|
||||
if 'event_place' in self.fields:
|
||||
self.fields['event_place'].required = True
|
||||
if "event_place" in self.fields:
|
||||
self.fields["event_place"].required = True
|
||||
|
||||
|
||||
class FetMeetingForm(PostForm):
|
||||
# agenda_html = forms.CharField(widget = forms.TextInput())
|
||||
class Meta:
|
||||
model = FetMeeting
|
||||
fields = ['event_start', 'event_end', 'tags']#, 'has_agenda', 'has_protocol']
|
||||
fields = ["event_start", "event_end", "tags"] # , 'has_agenda', 'has_protocol']
|
||||
|
||||
labels = {
|
||||
'event_start': _("Start der Sitzung"),
|
||||
'event_end': _("Ende der Sitzung")#,
|
||||
# 'has_agenda': _("Agenda"),
|
||||
# 'has_protocol': _("Protokoll"),
|
||||
"event_start": _("Start der Sitzung"),
|
||||
"event_end": _("Ende der Sitzung") # ,
|
||||
# 'has_agenda': _("Agenda"),
|
||||
# 'has_protocol': _("Protokoll"),
|
||||
}
|
||||
|
||||
help_texts = {
|
||||
'tags': _(
|
||||
"tags": _(
|
||||
"Die Hashtags ohne '#' eintragen, und mit Komma kann man mehrere Tags anfügen."
|
||||
)#,
|
||||
) # ,
|
||||
#'has_agenda': _("Agenda zur Sitzung hinzufügen."),
|
||||
#'has_protocol': _("Protokoll zur Sitzung hinzufügen."),
|
||||
}
|
||||
@@ -132,13 +159,13 @@ class FetMeetingForm(PostForm):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs) # to get the self.fields set
|
||||
|
||||
self.fields['event_start'].required = True
|
||||
self.fields['event_end'].required = False
|
||||
self.fields["event_start"].required = True
|
||||
self.fields["event_end"].required = False
|
||||
|
||||
#self.fields['has_agenda'].initial = True
|
||||
#self.fields['has_protocol'].initial = True
|
||||
# self.fields['has_agenda'].initial = True
|
||||
# self.fields['has_protocol'].initial = True
|
||||
|
||||
tags = []
|
||||
tags.append(Tag())
|
||||
tags[0].name = "fachschaft"
|
||||
self.fields['tags'].initial = tags
|
||||
self.fields["tags"].initial = tags
|
||||
|
||||
@@ -3,15 +3,22 @@ from django.core.mail import send_mail
|
||||
|
||||
|
||||
def send_agenda_mail(date, time, slug):
|
||||
msg = "Liebe Alle,\n\n" \
|
||||
"wir haben am " + str(date) + " um " + str(time) + " wieder Sitzung.\n" \
|
||||
"du hast noch bis morgen Zeit, weitere Themen auf die Agenda zu schreiben: " \
|
||||
+ settings.HOST_NAME + '/posts/' + str(slug) + ".\n\n" \
|
||||
msg = (
|
||||
"Liebe Alle,\n\n"
|
||||
"wir haben am " + str(date) + " um " + str(time) + " wieder Sitzung.\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"
|
||||
)
|
||||
|
||||
send_mail(
|
||||
subject = 'Test - Agenda der FET Sitzung von ' + str(date),
|
||||
message = msg,
|
||||
from_email = 'patrick@fet.at',
|
||||
recipient_list = ['all@fet.at', ],
|
||||
subject="Test - Agenda der FET Sitzung von " + str(date),
|
||||
message=msg,
|
||||
from_email="patrick@fet.at",
|
||||
recipient_list=[
|
||||
"all@fet.at",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -5,23 +5,32 @@ from django.utils import timezone
|
||||
|
||||
class PostManager(models.Manager):
|
||||
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):
|
||||
return self.get_queryset().filter(is_hidden=False)
|
||||
|
||||
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):
|
||||
"""
|
||||
Provide a query set only for "Article"
|
||||
regular fet meetings should not be contained in the news stream
|
||||
"""
|
||||
|
||||
def get_queryset(self):
|
||||
return super().get_queryset().filter(
|
||||
Q(post_type='E')
|
||||
| Q(post_type='N')
|
||||
).order_by('-public_date')
|
||||
return (
|
||||
super()
|
||||
.get_queryset()
|
||||
.filter(Q(post_type="E") | Q(post_type="N"))
|
||||
.order_by("-public_date")
|
||||
)
|
||||
|
||||
def get_visible_articles(self):
|
||||
return self.get_queryset().filter(is_hidden=False)
|
||||
@@ -34,8 +43,9 @@ class NewsManager(models.Manager):
|
||||
"""
|
||||
Provide a query set only for "News"
|
||||
"""
|
||||
|
||||
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):
|
||||
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")
|
||||
"""
|
||||
|
||||
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):
|
||||
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):
|
||||
@@ -58,32 +73,50 @@ class EventManager(models.Manager):
|
||||
Provide a query set only for "Events"
|
||||
regular fet meetings should not be contained in the news stream
|
||||
"""
|
||||
|
||||
def get_queryset(self):
|
||||
return super().get_queryset().filter(post_type='E')
|
||||
return super().get_queryset().filter(post_type="E")
|
||||
|
||||
def get_future_events(self):
|
||||
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):
|
||||
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):
|
||||
"""
|
||||
Provide a query set only for "Fet Meeting"
|
||||
"""
|
||||
|
||||
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):
|
||||
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):
|
||||
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):
|
||||
meetings = []
|
||||
|
||||
@@ -133,6 +133,7 @@ class Post(models.Model):
|
||||
)
|
||||
html = None
|
||||
return html
|
||||
|
||||
@property
|
||||
def protocol_html(self):
|
||||
"Protocol HTML from Etherpad Pad"
|
||||
@@ -196,7 +197,7 @@ class Post(models.Model):
|
||||
|
||||
def get_agenda_key(self):
|
||||
"""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:
|
||||
return None
|
||||
return create_pad_for_post(self.slug, typ="agenda")
|
||||
@@ -255,9 +256,10 @@ class Post(models.Model):
|
||||
def clean(self):
|
||||
if self.event_end and self.event_end < self.event_start:
|
||||
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")
|
||||
super().clean()
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
# save the post with some defaults
|
||||
if not self.public_date:
|
||||
@@ -307,9 +309,9 @@ class Event(Post):
|
||||
verbose_name = "Event"
|
||||
verbose_name_plural = "Events"
|
||||
|
||||
def __init__(self,*args,**kwargs):
|
||||
super().__init__(*args,**kwargs)
|
||||
self.post_type='E'
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.post_type = "E"
|
||||
|
||||
def clean(self):
|
||||
if not self.event_start:
|
||||
@@ -334,10 +336,10 @@ class FetMeeting(Event):
|
||||
verbose_name = "Fet Sitzung"
|
||||
verbose_name_plural = "Fet Sitzungen"
|
||||
|
||||
def __init__(self,*args,**kwargs):
|
||||
super().__init__(*args,**kwargs)
|
||||
self.post_type='F'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.post_type = "F"
|
||||
|
||||
def __get_slug(self):
|
||||
slug = slugify(self.event_start.date()) + "-" + slugify("Fachschaftssitzung")
|
||||
|
||||
@@ -349,48 +351,47 @@ class FetMeeting(Event):
|
||||
|
||||
return slug
|
||||
|
||||
# def __get_agenda_key(self):
|
||||
# if not self.slug:
|
||||
# return None##
|
||||
#
|
||||
# try:
|
||||
# agenda_key = createPadifNotExists(self.slug + "-agenda")
|
||||
# except Exception as error:
|
||||
# raise ValidationError(
|
||||
# _("Die Agenda konnte nicht erstellt werden. Error: %(error)s"),
|
||||
# params={"error": str(error)},
|
||||
# ) from error
|
||||
#
|
||||
# return agenda_key
|
||||
# def __get_agenda_key(self):
|
||||
# if not self.slug:
|
||||
# return None##
|
||||
#
|
||||
# try:
|
||||
# agenda_key = createPadifNotExists(self.slug + "-agenda")
|
||||
# except Exception as error:
|
||||
# raise ValidationError(
|
||||
# _("Die Agenda konnte nicht erstellt werden. Error: %(error)s"),
|
||||
# params={"error": str(error)},
|
||||
# ) from error
|
||||
#
|
||||
# return agenda_key
|
||||
|
||||
# def __get_protocol_key(self):
|
||||
# if not self.slug:
|
||||
# return None#
|
||||
#
|
||||
# try:
|
||||
# protocol_key = createPadifNotExists(self.slug + "-protocol")
|
||||
# except URLError as error:
|
||||
# raise ValidationError(
|
||||
# _("Das Protokoll konnte nicht erstellt werden. Error: %(error)s"),
|
||||
# params={"error": str(error)},
|
||||
# ) from error#
|
||||
#
|
||||
# return protocol_key
|
||||
|
||||
# def __get_protocol_key(self):
|
||||
# if not self.slug:
|
||||
# return None#
|
||||
#
|
||||
# try:
|
||||
# protocol_key = createPadifNotExists(self.slug + "-protocol")
|
||||
# except URLError as error:
|
||||
# raise ValidationError(
|
||||
# _("Das Protokoll konnte nicht erstellt werden. Error: %(error)s"),
|
||||
# params={"error": str(error)},
|
||||
# ) from error#
|
||||
#
|
||||
# return protocol_key
|
||||
|
||||
|
||||
def clean(self):
|
||||
super().clean()
|
||||
if not self.slug:
|
||||
self.slug = self.__get_slug()
|
||||
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.title = "Fachschaftssitzung"
|
||||
if not self.slug:
|
||||
self.slug = self.__get_slug()
|
||||
|
||||
|
||||
self.has_agenda = True
|
||||
self.has_protocol = True
|
||||
|
||||
|
||||
self.agenda_key = self.get_agenda_key()
|
||||
self.protocol_key = self.get_protocol_key()
|
||||
|
||||
|
||||
@@ -5,33 +5,34 @@ from rest_framework import serializers
|
||||
|
||||
class PostSerializer(serializers.HyperlinkedModelSerializer):
|
||||
agenda_html = serializers.CharField(required=False)
|
||||
tag_string = serializers.CharField(required=False,read_only=True)
|
||||
imageurl = serializers.CharField(required=False,read_only=True)
|
||||
tag_string = serializers.CharField(required=False, read_only=True)
|
||||
imageurl = serializers.CharField(required=False, read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Post
|
||||
fields = [
|
||||
'slug',
|
||||
'title',
|
||||
'subtitle',
|
||||
'body',
|
||||
'url',
|
||||
'post_type',
|
||||
'public_date',
|
||||
'legacy_id',
|
||||
'image',
|
||||
'event_start',
|
||||
'event_end',
|
||||
'is_hidden',
|
||||
'agenda_html',
|
||||
'protocol_html',
|
||||
'has_agenda',
|
||||
'has_protocol',
|
||||
'tag_string',
|
||||
'imageurl'
|
||||
"slug",
|
||||
"title",
|
||||
"subtitle",
|
||||
"body",
|
||||
"url",
|
||||
"post_type",
|
||||
"public_date",
|
||||
"legacy_id",
|
||||
"image",
|
||||
"event_start",
|
||||
"event_end",
|
||||
"is_hidden",
|
||||
"agenda_html",
|
||||
"protocol_html",
|
||||
"has_agenda",
|
||||
"has_protocol",
|
||||
"tag_string",
|
||||
"imageurl"
|
||||
# 'author',
|
||||
]
|
||||
|
||||
extra_kwargs={
|
||||
'agenda_html': {"required": False},
|
||||
'protocol_html': {"required": False}
|
||||
extra_kwargs = {
|
||||
"agenda_html": {"required": False},
|
||||
"protocol_html": {"required": False},
|
||||
}
|
||||
|
||||
@@ -3,10 +3,10 @@ from . import views
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path('func/tag_complete', views.tag_complete),
|
||||
path('func/slug_calc', views.slug_calc),
|
||||
path('t/<str:tag>', views.tags, name='posts.tags'),
|
||||
path('', views.index, name='posts.index'),
|
||||
path('fet_calendar.ics', views.calendar, name='posts.calendar'),
|
||||
path('<str:id>', views.show, name='posts.show'),
|
||||
path("func/tag_complete", views.tag_complete),
|
||||
path("func/slug_calc", views.slug_calc),
|
||||
path("t/<str:tag>", views.tags, name="posts.tags"),
|
||||
path("", views.index, name="posts.index"),
|
||||
path("fet_calendar.ics", views.calendar, name="posts.calendar"),
|
||||
path("<str:id>", views.show, name="posts.show"),
|
||||
]
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
from collections import deque
|
||||
import logging
|
||||
from rest_framework import viewsets
|
||||
from taggit.models import Tag
|
||||
|
||||
from django.shortcuts import render
|
||||
from django.http import HttpResponse, JsonResponse, HttpResponseServerError
|
||||
from django.utils.text import slugify
|
||||
from django.utils import timezone
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
|
||||
from documents.api import get_pad_link
|
||||
from documents.etherpadlib import add_ep_cookie
|
||||
@@ -15,7 +13,8 @@ from members.models import Member, JobMember
|
||||
|
||||
|
||||
from .models import Post, FetMeeting
|
||||
from .serializers import PostSerializer
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -28,7 +27,7 @@ def index(request):
|
||||
"Index von aktuellen Posts"
|
||||
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})
|
||||
|
||||
@@ -36,7 +35,7 @@ def index(request):
|
||||
def calendar(request):
|
||||
"Kalender Ansicht ICS zur Verknüpfung mit Outlook"
|
||||
events = deque(Post.objects.all_post_with_date().all())
|
||||
|
||||
|
||||
return render(
|
||||
request,
|
||||
"posts/fet_calendar.ics",
|
||||
@@ -49,7 +48,6 @@ def tags(request, tag=""):
|
||||
posts = deque(Post.objects.get_visible_articles().filter(tags__name=tag))
|
||||
featured_post = Post.objects.get_visible_articles().filter(slug=tag).first()
|
||||
|
||||
|
||||
job_members = JobMember.active_member.get_all_by_slug(slug=tag)
|
||||
|
||||
author_image = None
|
||||
@@ -87,25 +85,21 @@ def show(request, id=None):
|
||||
ep_agenda_link = "#"
|
||||
ep_protocol_link = "#"
|
||||
|
||||
if p.has_agenda:# and p.agenda_key:
|
||||
if p.has_agenda: # and p.agenda_key:
|
||||
try:
|
||||
ep_agenda_link = get_pad_link(p.agenda_key)
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
"Can't get the agenda link from '%s'. Error: %s",
|
||||
p.agenda_key,
|
||||
e
|
||||
"Can't get the agenda link from '%s'. Error: %s", p.agenda_key, e
|
||||
)
|
||||
ep_agenda_link = "#"
|
||||
|
||||
if p.has_protocol:# and p.protocol_key:
|
||||
if p.has_protocol: # and p.protocol_key:
|
||||
try:
|
||||
ep_protocol_link = get_pad_link(p.protocol_key)
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
"Can't get the protocol link from '%s. Error: %s",
|
||||
p.protocol_key, e
|
||||
|
||||
"Can't get the protocol link from '%s. Error: %s", p.protocol_key, e
|
||||
)
|
||||
ep_protocol_link = "#"
|
||||
|
||||
@@ -126,8 +120,7 @@ def show(request, id=None):
|
||||
try:
|
||||
response = add_ep_cookie(request, response)
|
||||
except Exception as e:
|
||||
logger.info(
|
||||
"Etherpad Server doesn't work. Error: %s", e)
|
||||
logger.info("Etherpad Server doesn't work. Error: %s", e)
|
||||
|
||||
return response
|
||||
|
||||
@@ -196,19 +189,3 @@ def get_next_dict(post=None):
|
||||
break
|
||||
|
||||
return d
|
||||
|
||||
|
||||
class PostViewSet(viewsets.ModelViewSet):
|
||||
"""
|
||||
API endpoint that allows users to be viewed or edited.
|
||||
"""
|
||||
|
||||
queryset = Post.objects.all().order_by("-public_date")
|
||||
serializer_class = PostSerializer
|
||||
# permission_classes = [permissions.IsAuthenticated]
|
||||
filter_backends = [DjangoFilterBackend]
|
||||
filterset_fields = ["legacy_id", "slug", "legacy_rubrik_id"]
|
||||
lookup_field = "slug"
|
||||
|
||||
def pre_save(self, obj):
|
||||
obj.image = self.request.FILES.get("image")
|
||||
|
||||
21
fet2020/posts/viewsets.py
Normal file
21
fet2020/posts/viewsets.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from rest_framework import viewsets
|
||||
|
||||
from .models import Post, FetMeeting
|
||||
from .serializers import PostSerializer
|
||||
|
||||
|
||||
class PostViewSet(viewsets.ModelViewSet):
|
||||
"""
|
||||
API endpoint that allows users to be viewed or edited.
|
||||
"""
|
||||
|
||||
queryset = Post.objects.all().order_by("-public_date")
|
||||
serializer_class = PostSerializer
|
||||
# permission_classes = [permissions.IsAuthenticated]
|
||||
filter_backends = [DjangoFilterBackend]
|
||||
filterset_fields = ["legacy_id", "slug", "legacy_rubrik_id"]
|
||||
lookup_field = "slug"
|
||||
|
||||
def pre_save(self, obj):
|
||||
obj.image = self.request.FILES.get("image")
|
||||
@@ -1,4 +1,4 @@
|
||||
django==3.1.4
|
||||
django==3.1.5
|
||||
django-ckeditor==6.0.0
|
||||
django-crontab==0.7.1
|
||||
django-environ==0.4.5
|
||||
|
||||
18
fet2020/static/fet.css
Normal file
18
fet2020/static/fet.css
Normal file
@@ -0,0 +1,18 @@
|
||||
body {
|
||||
min-height:100%;
|
||||
position:relative;
|
||||
}
|
||||
img.logo {
|
||||
height:40px;
|
||||
width:40px;
|
||||
}
|
||||
|
||||
div.footer {
|
||||
height: 100%;
|
||||
}
|
||||
.footer a {
|
||||
color: white;
|
||||
}
|
||||
.footer a i {
|
||||
font-size:30px;
|
||||
}
|
||||
@@ -8,23 +8,33 @@ class TaskAdmin(admin.ModelAdmin):
|
||||
form = TaskAdminForm
|
||||
model = Task
|
||||
fieldsets = (
|
||||
(None, {
|
||||
'fields': (
|
||||
'title',
|
||||
'task_list',
|
||||
'assigned_to',
|
||||
'due_date',
|
||||
'completed',
|
||||
'completed_date',
|
||||
'note',
|
||||
'priority',
|
||||
)
|
||||
}),
|
||||
(
|
||||
None,
|
||||
{
|
||||
"fields": (
|
||||
"title",
|
||||
"task_list",
|
||||
"assigned_to",
|
||||
"due_date",
|
||||
"completed",
|
||||
"completed_date",
|
||||
"note",
|
||||
"priority",
|
||||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
list_display = ['title', 'task_list', 'assigned_to', 'due_date', 'completed', 'priority']
|
||||
list_filter = ('task_list', )
|
||||
search_fields = ('title', )
|
||||
list_display = [
|
||||
"title",
|
||||
"task_list",
|
||||
"assigned_to",
|
||||
"due_date",
|
||||
"completed",
|
||||
"priority",
|
||||
]
|
||||
list_filter = ("task_list",)
|
||||
search_fields = ("title",)
|
||||
|
||||
def save_model(self, request, obj, form, change):
|
||||
obj.created_by = request.user
|
||||
|
||||
@@ -2,4 +2,4 @@ from django.apps import AppConfig
|
||||
|
||||
|
||||
class TasksConfig(AppConfig):
|
||||
name = 'tasks'
|
||||
name = "tasks"
|
||||
|
||||
@@ -7,29 +7,31 @@ from .models import Task, TaskList
|
||||
|
||||
|
||||
class DateInput(forms.DateInput):
|
||||
input_type = 'date'
|
||||
input_type = "date"
|
||||
|
||||
|
||||
class TaskAdminForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Task
|
||||
fields = '__all__'
|
||||
fields = "__all__"
|
||||
|
||||
labels = {
|
||||
'title': _('Titel'),
|
||||
'task_list': _('Aufgabenbereich'),
|
||||
'due_date': _('Fälligkeit'),
|
||||
'completed': _('Abgeschlossen'),
|
||||
'completed_date': _('Datum der Fertigstellung'),
|
||||
'assigned_to': _('Zuweisen an'),
|
||||
'note': _('Notizen'),
|
||||
'priority': _('Priorität'),
|
||||
"title": _("Titel"),
|
||||
"task_list": _("Aufgabenbereich"),
|
||||
"due_date": _("Fälligkeit"),
|
||||
"completed": _("Abgeschlossen"),
|
||||
"completed_date": _("Datum der Fertigstellung"),
|
||||
"assigned_to": _("Zuweisen an"),
|
||||
"note": _("Notizen"),
|
||||
"priority": _("Priorität"),
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs) # to get the self.fields set
|
||||
self.fields['assigned_to'].empty_label = "Alle"
|
||||
self.fields['assigned_to'].queryset = self.fields['assigned_to'].queryset.order_by('username')
|
||||
self.fields["assigned_to"].empty_label = "Alle"
|
||||
self.fields["assigned_to"].queryset = self.fields[
|
||||
"assigned_to"
|
||||
].queryset.order_by("username")
|
||||
|
||||
|
||||
class TaskForm(forms.ModelForm):
|
||||
@@ -37,39 +39,41 @@ class TaskForm(forms.ModelForm):
|
||||
model = Task
|
||||
|
||||
fields = [
|
||||
'title',
|
||||
'task_list',
|
||||
'due_date',
|
||||
'assigned_to',
|
||||
"title",
|
||||
"task_list",
|
||||
"due_date",
|
||||
"assigned_to",
|
||||
]
|
||||
|
||||
labels = {
|
||||
'title': _('Titel des Tasks'),
|
||||
'task_list': _('Task-Gruppe'),
|
||||
'due_date': _('Fälligkeitsdatum'),
|
||||
'assigned_to': _('Zuweisen an'),
|
||||
"title": _("Titel des Tasks"),
|
||||
"task_list": _("Task-Gruppe"),
|
||||
"due_date": _("Fälligkeitsdatum"),
|
||||
"assigned_to": _("Zuweisen an"),
|
||||
}
|
||||
|
||||
widgets = {
|
||||
'due_date': DateInput(
|
||||
format=('%d-%m-%Y'),
|
||||
"due_date": DateInput(
|
||||
format=("%d-%m-%Y"),
|
||||
)
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs) # to get the self.fields set
|
||||
self.fields['assigned_to'].empty_label = "Alle"
|
||||
self.fields['assigned_to'].queryset = self.fields['assigned_to'].queryset.order_by('username')
|
||||
self.fields["assigned_to"].empty_label = "Alle"
|
||||
self.fields["assigned_to"].queryset = self.fields[
|
||||
"assigned_to"
|
||||
].queryset.order_by("username")
|
||||
|
||||
|
||||
class TaskListForm(forms.ModelForm):
|
||||
users = forms.ModelMultipleChoiceField(
|
||||
label="Benutzer",
|
||||
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'),
|
||||
widget=FilteredSelectMultiple("User", is_stacked=False)
|
||||
queryset=User.objects.all().order_by("username"),
|
||||
widget=FilteredSelectMultiple("User", is_stacked=False),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = TaskList
|
||||
fields = '__all__'
|
||||
fields = "__all__"
|
||||
|
||||
@@ -7,7 +7,7 @@ from django.utils import timezone
|
||||
|
||||
class TaskQuerySet(models.QuerySet):
|
||||
def get_ordered(self):
|
||||
return self.order_by('task_list')
|
||||
return self.order_by("task_list")
|
||||
|
||||
|
||||
class TaskManager(models.Manager):
|
||||
@@ -16,7 +16,11 @@ class TaskManager(models.Manager):
|
||||
qs = self.get_queryset().get_ordered().filter(assigned_to__id=user)
|
||||
|
||||
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()
|
||||
|
||||
if not completed:
|
||||
@@ -24,7 +28,7 @@ class TaskManager(models.Manager):
|
||||
|
||||
if task_list:
|
||||
qs = qs.filter(task_list=task_list)
|
||||
|
||||
|
||||
return qs
|
||||
|
||||
def get_queryset(self):
|
||||
@@ -49,7 +53,9 @@ class TaskList(models.Model):
|
||||
|
||||
class Task(models.Model):
|
||||
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)
|
||||
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)
|
||||
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()
|
||||
taskmanager = TaskManager()
|
||||
|
||||
@@ -4,5 +4,5 @@ from . import views
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path('', views.index, name='tasks'),
|
||||
path("", views.index, name="tasks"),
|
||||
]
|
||||
|
||||
@@ -17,8 +17,8 @@ def index(request):
|
||||
show_tasklist = None
|
||||
show_all_tasks = True
|
||||
|
||||
if request.method == 'POST':
|
||||
if 'btn_input' in request.POST:
|
||||
if request.method == "POST":
|
||||
if "btn_input" in request.POST:
|
||||
form = TaskForm(request.POST)
|
||||
|
||||
if form.is_valid():
|
||||
@@ -29,13 +29,18 @@ def index(request):
|
||||
task.created_by = request.user
|
||||
task.save()
|
||||
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:
|
||||
task.created_by = request.user
|
||||
task.save()
|
||||
|
||||
elif 'btn_checkbox' in request.POST:
|
||||
for task_id in request.POST.getlist('checkbox'):
|
||||
elif "btn_checkbox" in request.POST:
|
||||
for task_id in request.POST.getlist("checkbox"):
|
||||
task = Task.objects.get(id=task_id)
|
||||
|
||||
if not task.completed:
|
||||
@@ -43,27 +48,31 @@ def index(request):
|
||||
task.completed_date = timezone.now().date()
|
||||
task.save()
|
||||
|
||||
elif 'btn_user' in request.POST:
|
||||
if request.POST['action'] == 'show_incompleted':
|
||||
elif "btn_user" in request.POST:
|
||||
if request.POST["action"] == "show_incompleted":
|
||||
current_action = False
|
||||
else:
|
||||
current_action = True
|
||||
|
||||
if request.POST['tasklist'] != 'all':
|
||||
show_tasklist = TaskList.objects.filter(id=request.POST['tasklist']).first()
|
||||
if request.POST["tasklist"] != "all":
|
||||
show_tasklist = TaskList.objects.filter(
|
||||
id=request.POST["tasklist"]
|
||||
).first()
|
||||
|
||||
if request.POST['tasks'] == 'all':
|
||||
if request.POST["tasks"] == "all":
|
||||
show_all_tasks = True
|
||||
else:
|
||||
show_all_tasks = False
|
||||
|
||||
form = TaskForm()
|
||||
tasks = deque(Task.taskmanager.get_tasks(
|
||||
user=current_user,
|
||||
completed=current_action,
|
||||
task_list=show_tasklist,
|
||||
all_tasks=show_all_tasks
|
||||
))
|
||||
tasks = deque(
|
||||
Task.taskmanager.get_tasks(
|
||||
user=current_user,
|
||||
completed=current_action,
|
||||
task_list=show_tasklist,
|
||||
all_tasks=show_all_tasks,
|
||||
)
|
||||
)
|
||||
tasklists = deque(TaskList.objects.all())
|
||||
|
||||
context = {
|
||||
@@ -74,4 +83,4 @@ def index(request):
|
||||
"current_action": current_action,
|
||||
}
|
||||
|
||||
return render(request, 'tasks/index.html', context)
|
||||
return render(request, "tasks/index.html", context)
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
{% for post in events %}
|
||||
{% include 'posts/partials/_date_box.html' %}
|
||||
{% endfor %}
|
||||
<a href="{% url 'posts.calendar' %}">ICS Kalendar</a>
|
||||
FET-Kalender abonnieren: <a href="{% url 'posts.calendar' %}">ICS Kalender</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -8,11 +8,12 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>FET</title>
|
||||
<link rel="stylesheet" href="{% static 'app.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'fet.css' %}">
|
||||
<script src="https://kit.fontawesome.com/dbe3c89a9d.js" crossorigin="anonymous"></script>
|
||||
{% block extraheader %}
|
||||
{% endblock %}
|
||||
</head>
|
||||
<body style="min-height:100%; position:relative">
|
||||
<body style="">
|
||||
|
||||
<style>
|
||||
footer {
|
||||
@@ -28,7 +29,7 @@ footer {
|
||||
|
||||
<div class="title-bar-left">
|
||||
<a href="{% url 'home' %}">
|
||||
<img style="height:40px; width:40px" src="/assets/img/logo2014_64.png"/>
|
||||
<img class="logo" src="/assets/img/logo2014_64.png"/>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -43,26 +44,26 @@ footer {
|
||||
|
||||
<div class="top-bar-left show-for-large">
|
||||
<a href="{% url 'home' %}">
|
||||
<img style="height:40px; width:40px" src="/assets/img/logo2014_64.png"/>
|
||||
<img class="logo" src="/assets/img/logo2014_64.png"/>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="top-bar-right">
|
||||
<ul class="dropdown vertical medium-horizontal menu" data-responsive-menu="drilldown medium-dropdown" data-animate-heigt="true">
|
||||
{% if request.user.is_authenticated %}
|
||||
<li><a role="menuitem" style="color: black; background: lightgrey">Hallo {{request.user.username}}</a></li>
|
||||
<li><a role="menuitem" style="color: black; background: lightgrey">Hallo {{ request.user.username }}</a></li>
|
||||
<li><a href="/admin" style="background: lightgrey;">Admin</a></li>
|
||||
<li><a href="{%url 'tasks'%}" style="background: lightgrey;">Tasks</a></li>
|
||||
<li><a href="{% url 'tasks' %}" style="background: lightgrey;">Tasks</a></li>
|
||||
{% endif %}
|
||||
<li><a href="{% url 'posts.index' %}">Aktuelles</a></li>
|
||||
<!-- show active members first -->
|
||||
<li><a href="{% url 'members'%}A">Fachschaft</a></li>
|
||||
<li><a href="{% url 'members' %}A">Fachschaft</a></li>
|
||||
<li><a href="/fotos/">Fotos</a></li>
|
||||
<li><a href="/blackboard">Blackboard</a></li>
|
||||
{% if request.user.is_authenticated %}
|
||||
<li><a href="{%url 'logout'%}">Logout</a></li>
|
||||
<li><a href="{% url 'logout' %}">Logout</a></li>
|
||||
{% else %}
|
||||
<li><a href="{%url 'login'%}">Login</a></li>
|
||||
<li><a href="{% url 'login' %}?next={{ request.path }}">Login</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
@@ -76,17 +77,17 @@ footer {
|
||||
<div class="grid-container">
|
||||
<div class="grid-x padding-top-1 padding-bottom-1">
|
||||
<div class="cell medium-6 large-9">
|
||||
<div class="grid-y" style="height: 100%;">
|
||||
<div class="grid-y" style="height: 100%;" class="footer">
|
||||
|
||||
<div class="cell small-6 medium-9 large-9">
|
||||
<a href="{% url 'posts.show' 'impressum' %}" style="color: white">Impressum</a>
|
||||
<a href="{% url 'posts.show' 'impressum' %}" >Impressum</a>
|
||||
</div>
|
||||
|
||||
<div class="cell small-6 medium-3 large-3 padding-bottom-2">
|
||||
<a href="https://www.facebook.com/FachschaftET"><i class="fab fa-facebook-square" style="font-size:30px; color: white;"></i></a>
|
||||
<a href="https://www.instagram.com/fet_tuwien/"><i class="fab fa-instagram-square" style="font-size:30px; color: white;"></i></a>
|
||||
<a href="https://discord.gg/7qRuuMA"><i class="fab fa-discord" style="font-size:30px; color: white;"></i></a>
|
||||
<a href="https://t.me/FETInfo"><i class="fab fa-telegram" style="font-size:30px; color: white;"></i></a>
|
||||
<a href="https://www.facebook.com/FachschaftET"><i class="fab fa-facebook-square" style="font-size:30px; color: white;"></i>Facebook</a>
|
||||
<a href="https://www.instagram.com/fet_tuwien/"><i class="fab fa-instagram-square" style="font-size:30px; color: white;"></i>Instagram</a>
|
||||
<a href="https://discord.gg/7qRuuMA"><i class="fab fa-discord" style="font-size:30px; color: white;"></i>Discord</a>
|
||||
<a href="https://t.me/FETInfo"><i class="fab fa-telegram" style="font-size:30px; color: white;"></i>Telegram</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -62,7 +62,9 @@
|
||||
{% if members %}
|
||||
<div class="grid-x">
|
||||
<div class="cell padding-top-1 padding-left-1 padding-right-1" style="background-color: white; text-align: justify;">
|
||||
Die Fachschaft Elektrotechnik (kurz: FET), ist die offizielle Vertretung aller Studierenden auf der Fakultät für Elektrotechnik und Informationstechnik. Ehrenamtliche engagierte Studierende unterstützen dich in Anliegen und Fragen zum und rund ums Studium. Wir vertreten eure Interessen in den offiziellen Gremien der Universität und arbeiten an Studienplänen mit. Außerdem bieten wir ein Rahmenprogramm zum Studium in Form von Veranstaltungen und Festln. Wir freuen uns über Feedback und Anregungen, insbesondere von jenen, die gleich Nägel mit Köpfen machen und unser Team verstärken wollen oder ihre Themen und Meinungen in eine unserer Sitzungen einbringen möchten.
|
||||
{% if fs_info %}
|
||||
{{ fs_info.body|safe }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ UID:{{event.id}}
|
||||
ORGANIZER;CN="Fachschaft Elektrotechnik":MAILTO:service@fet.at
|
||||
LOCATION:Vienna
|
||||
SUMMARY:{{ event.title }}
|
||||
DESCRIPTION: {{ request.scheme }}://{{ request.get_host }}{{ event.url }} {{ even.title }}</a>
|
||||
DESCRIPTION:{{ request.scheme }}://{{ request.get_host }}{{ event.url }} {{ even.title }}
|
||||
CLASS:PUBLIC
|
||||
DTSTART;TZID=Europe/Vienna:{{ event.event_start|date:'Ymd' }}T{{ event.event_start|time:'His' }}
|
||||
DTEND;TZID=Europe/Vienna:{{ event.event_end|date:'Ymd' }}T{{ event.event_end|time:'His' }}
|
||||
|
||||
Reference in New Issue
Block a user