seperate teilnehmerlisten into notizlisten and freizeiten, add migration from old teilnehmerlisten to both new versions

v1-0-stable
Christian Merten 5 years ago
parent bf719601a7
commit 56696edb32

@ -23,7 +23,7 @@ class Message(models.Model):
to_groups = models.ManyToManyField('members.Group', to_groups = models.ManyToManyField('members.Group',
verbose_name=_('to group'), verbose_name=_('to group'),
blank=True) blank=True)
to_memberlist = models.ForeignKey('members.MemberList', to_memberlist = models.ForeignKey('members.Freizeit',
verbose_name=_('to member list'), verbose_name=_('to member list'),
blank=True, blank=True,
null=True) null=True)

@ -9,15 +9,16 @@ import unicodedata
from django.http import HttpResponse, HttpResponseRedirect from django.http import HttpResponse, HttpResponseRedirect
from wsgiref.util import FileWrapper from wsgiref.util import FileWrapper
from django import forms from django import forms
from django.contrib import admin from django.contrib import admin, messages
from django.contrib.admin import DateFieldListFilter from django.contrib.admin import DateFieldListFilter
from django.contrib.contenttypes.admin import GenericTabularInline
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.db.models import TextField, ManyToManyField, ForeignKey from django.db.models import TextField, ManyToManyField, ForeignKey
from django.forms import Textarea, RadioSelect, TypedChoiceField from django.forms import Textarea, RadioSelect, TypedChoiceField
from django.shortcuts import render from django.shortcuts import render
from .models import (Member, Group, MemberList, MemberOnList, Klettertreff, from .models import (Member, Group, Freizeit, MemberNoteList, NewMemberOnList, Klettertreff,
KlettertreffAttendee, ActivityCategory) KlettertreffAttendee, ActivityCategory, OldMemberOnList, MemberList)
from django.conf import settings from django.conf import settings
#from easy_select2 import apply_select2 #from easy_select2 import apply_select2
@ -103,28 +104,28 @@ class ActivityCategoryAdmin(admin.ModelAdmin):
fields = ['name', 'description'] fields = ['name', 'description']
class MemberListAdminForm(forms.ModelForm): class FreizeitAdminForm(forms.ModelForm):
difficulty = TypedChoiceField(MemberList.difficulty_choices, difficulty = TypedChoiceField(Freizeit.difficulty_choices,
#widget=RadioSelect, #widget=RadioSelect,
coerce=int, coerce=int,
label=_('Difficulty')) label=_('Difficulty'))
tour_type = TypedChoiceField(MemberList.tour_type_choices, tour_type = TypedChoiceField(Freizeit.tour_type_choices,
#widget=RadioSelect, #widget=RadioSelect,
coerce=int, coerce=int,
label=_('Tour type')) label=_('Tour type'))
class Meta: class Meta:
model = MemberList model = Freizeit
exclude = ['add_member'] exclude = ['add_member']
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(MemberListAdminForm, self).__init__(*args, **kwargs) super(FreizeitAdminForm, self).__init__(*args, **kwargs)
self.fields['jugendleiter'].queryset = Member.objects.filter(group__name='Jugendleiter') self.fields['jugendleiter'].queryset = Member.objects.filter(group__name='Jugendleiter')
#self.fields['add_member'].queryset = Member.objects.filter(prename__startswith='F') #self.fields['add_member'].queryset = Member.objects.filter(prename__startswith='F')
class MemberOnListInline(admin.TabularInline): class MemberOnListInline(GenericTabularInline):
model = MemberOnList model = NewMemberOnList
extra = 0 extra = 0
#formfield_overrides = { #formfield_overrides = {
# TextField: {'widget': Textarea(attrs={'rows': 1, # TextField: {'widget': Textarea(attrs={'rows': 1,
@ -134,9 +135,144 @@ class MemberOnListInline(admin.TabularInline):
#} #}
class OldMemberOnListInline(admin.TabularInline):
model = OldMemberOnList
extra = 0
class MemberNoteListAdmin(admin.ModelAdmin):
inlines = [MemberOnListInline]
list_display = ['__str__']
search_fields = ('name',)
actions = ['generate_summary']
def generate_summary(self, request, queryset):
"""Generates a pdf summary of the given NoteMemberLists
"""
for memberlist in queryset:
# unique filename
filename = memberlist.title + "_notes_" + datetime.today().strftime("%d_%m_%Y")
filename = filename.replace(' ', '_').replace('&', '')
# drop umlauts, accents etc.
filename = unicodedata.normalize('NFKD', filename).\
encode('ASCII', 'ignore').decode()
filename_tex = filename + '.tex'
filename_pdf = filename + '.pdf'
# generate table
table = ""
for memberonlist in memberlist.membersonlist.all():
m = memberonlist.member
comment = ". ".join(c for c
in (m.comments,
memberonlist.comments) if
c).replace("..", ".")
line = '{0} {1} & {2} \\\\'.format(
esc_ampersand(m.prename), esc_ampersand(m.lastname),
esc_ampersand(comment) or "---")
table += esc_underscore(line)
# copy template
shutil.copy(media_path('memberlistnote_template.tex'),
media_path(filename_tex))
# read in template
with open(media_path(filename_tex), 'r', encoding='utf-8') as f:
template_content = f.read()
# adapt template
title = esc_all(memberlist.title)
template_content = template_content.replace('MEMBERLIST-TITLE', title)
template_content = template_content.replace('MEMBERLIST-DATE',
datetime.today().strftime('%d.%m.%Y'))
template_content = template_content.replace('TABLE', table)
# write adapted template to file
with open(media_path(filename_tex), 'w', encoding='utf-8') as f:
f.write(template_content)
# compile using pdflatex
oldwd = os.getcwd()
os.chdir(media_dir())
subprocess.call(['pdflatex', filename_tex])
time.sleep(1)
# do some cleanup
for f in glob.glob('*.log'):
os.remove(f)
for f in glob.glob('*.aux'):
os.remove(f)
os.remove(filename_tex)
os.chdir(oldwd)
# provide the user with the resulting pdf file
with open(media_path(filename_pdf), 'rb') as pdf:
response = HttpResponse(FileWrapper(pdf))
response['Content-Type'] = 'application/pdf'
response['Content-Disposition'] = 'attachment; filename=' + filename_pdf
return response
generate_summary.short_description = "PDF Übersicht erstellen"
class MemberListAdmin(admin.ModelAdmin): class MemberListAdmin(admin.ModelAdmin):
inlines = [OldMemberOnListInline]
form = FreizeitAdminForm
list_display = ['__str__', 'date']
search_fields = ('name',)
actions = ['migrate_to_freizeit', 'migrate_to_notelist']
#formfield_overrides = {
# ManyToManyField: {'widget': forms.CheckboxSelectMultiple},
# ForeignKey: {'widget': apply_select2(forms.Select)}
#}
class Media:
css = {'all': ('admin/css/tabular_hide_original.css',)}
def __init__(self, *args, **kwargs):
super(MemberListAdmin, self).__init__(*args, **kwargs)
def migrate_to_freizeit(self, request, queryset):
"""Creates 'Freizeiten' from the given memberlists """
for memberlist in queryset:
freizeit = Freizeit(name=memberlist.name,
place=memberlist.place,
destination=memberlist.destination,
date=memberlist.date,
end=memberlist.end,
tour_type=memberlist.tour_type,
difficulty=memberlist.difficulty)
freizeit.save()
freizeit.jugendleiter = memberlist.jugendleiter.all()
freizeit.groups = memberlist.groups.all()
freizeit.activity = memberlist.activity.all()
for memberonlist in memberlist.oldmemberonlist_set.all():
newonlist = NewMemberOnList(member=memberonlist.member,
comments=memberonlist.comments,
memberlist=freizeit)
newonlist.save()
messages.info(request, "Freizeit(en) erfolgreich erstellt.")
migrate_to_freizeit.short_description = "Aus Teilnehmerliste(n) Freizeit(en) erstellen"
def migrate_to_notelist(self, request, queryset):
"""Creates 'MemberNoteList' from the given memberlists """
for memberlist in queryset:
notelist = MemberNoteList(title=memberlist.name,
date=memberlist.date)
notelist.save()
for memberonlist in memberlist.oldmemberonlist_set.all():
newonlist = NewMemberOnList(member=memberonlist.member,
comments=memberonlist.comments,
memberlist=notelist)
newonlist.save()
messages.info(request, "Teilnehmerlist(en) erfolgreich erstellt.")
migrate_to_notelist.short_description = "Aus Teilnehmerliste(n) Notizliste erstellen"
class FreizeitAdmin(admin.ModelAdmin):
inlines = [MemberOnListInline] inlines = [MemberOnListInline]
form = MemberListAdminForm form = FreizeitAdminForm
list_display = ['__str__', 'date'] list_display = ['__str__', 'date']
search_fields = ('name',) search_fields = ('name',)
actions = ['convert_to_pdf', 'generate_notes'] actions = ['convert_to_pdf', 'generate_notes']
@ -149,7 +285,7 @@ class MemberListAdmin(admin.ModelAdmin):
css = {'all': ('admin/css/tabular_hide_original.css',)} css = {'all': ('admin/css/tabular_hide_original.css',)}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(MemberListAdmin, self).__init__(*args, **kwargs) super(FreizeitAdmin, self).__init__(*args, **kwargs)
def convert_to_pdf(self, request, queryset): def convert_to_pdf(self, request, queryset):
"""Converts a member list to pdf. """Converts a member list to pdf.
@ -167,11 +303,11 @@ class MemberListAdmin(admin.ModelAdmin):
# open temporary file for table # open temporary file for table
with open(media_path(filename_table), 'w+', encoding='utf-8') as f: with open(media_path(filename_table), 'w+', encoding='utf-8') as f:
if memberlist.memberonlist_set.count() == 0: if memberlist.membersonlist.count() == 0:
f.write('{0} & {1} & {2} & {3} \\\\ \n'.format( f.write('{0} & {1} & {2} & {3} \\\\ \n'.format(
'keine Teilnehmer', '-', '-', '-' 'keine Teilnehmer', '-', '-', '-'
)) ))
for memberonlist in memberlist.memberonlist_set.all(): for memberonlist in memberlist.membersonlist.all():
# write table of members in latex compatible format # write table of members in latex compatible format
member = memberonlist.member member = memberonlist.member
# use parents phone number if available # use parents phone number if available
@ -278,7 +414,7 @@ class MemberListAdmin(admin.ModelAdmin):
table = "" table = ""
activities = [a.name for a in memberlist.activity.all()] activities = [a.name for a in memberlist.activity.all()]
skills = {a: [] for a in activities} skills = {a: [] for a in activities}
for memberonlist in memberlist.memberonlist_set.all(): for memberonlist in memberlist.membersonlist.all():
m = memberonlist.member m = memberonlist.member
qualities = [] qualities = []
for activity, value in m.get_skills().items(): for activity, value in m.get_skills().items():
@ -440,6 +576,8 @@ class KlettertreffAdmin(admin.ModelAdmin):
admin.site.register(Member, MemberAdmin) admin.site.register(Member, MemberAdmin)
admin.site.register(Group, GroupAdmin) admin.site.register(Group, GroupAdmin)
admin.site.register(Freizeit, FreizeitAdmin)
admin.site.register(MemberNoteList, MemberNoteListAdmin)
admin.site.register(MemberList, MemberListAdmin) admin.site.register(MemberList, MemberListAdmin)
admin.site.register(Klettertreff, KlettertreffAdmin) admin.site.register(Klettertreff, KlettertreffAdmin)
admin.site.register(ActivityCategory, ActivityCategoryAdmin) admin.site.register(ActivityCategory, ActivityCategoryAdmin)

@ -4,6 +4,8 @@ from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils import timezone from django.utils import timezone
from django.urls import reverse from django.urls import reverse
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
from django.contrib.contenttypes.models import ContentType
from utils import RestrictedFileField from utils import RestrictedFileField
import os import os
@ -160,14 +162,14 @@ class Member(models.Model):
skills = {} skills = {}
for kind in ActivityCategory.objects.all(): for kind in ActivityCategory.objects.all():
lists = MemberList.objects.filter(activity=kind, lists = MemberList.objects.filter(activity=kind,
memberonlist__member=self) oldmemberonlist__member=self)
skills[kind.name] = sum([l.difficulty * 3 for l in lists skills[kind.name] = sum([l.difficulty * 3 for l in lists
if l.date < datetime.now().date()]) if l.date < datetime.now().date()])
return skills return skills
def get_activities(self): def get_activities(self):
# get activity overview # get activity overview
return MemberList.objects.filter(memberonlist__member=self) return MemberList.objects.filter(oldmemberonlist__member=self)
class MemberList(models.Model): class MemberList(models.Model):
@ -214,7 +216,7 @@ class MemberList(models.Model):
return reverse('admin:members_memberlist_change', args=[str(self.id)]) return reverse('admin:members_memberlist_change', args=[str(self.id)])
class MemberOnList(models.Model): class OldMemberOnList(models.Model):
""" """
Connects members to a list of members. Connects members to a list of members.
""" """
@ -230,6 +232,87 @@ class MemberOnList(models.Model):
verbose_name_plural = _('Members') verbose_name_plural = _('Members')
class NewMemberOnList(models.Model):
"""
Connects members to a list of members.
"""
member = models.ForeignKey(Member, verbose_name=_('Member'))
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE,
default=ContentType('members', 'Freizeit').pk)
object_id = models.PositiveIntegerField()
memberlist = GenericForeignKey('content_type', 'object_id')
comments = models.TextField(_('Comment'), default='', blank=True)
def __str__(self):
return str(self.member)
class Meta:
verbose_name = _('Member')
verbose_name_plural = _('Members')
class Freizeit(models.Model):
"""Lets the user create a 'Freizeit' and generate a members overview in pdf format. """
name = models.CharField(verbose_name=_('Activity'), default='',
max_length=50)
place = models.CharField(verbose_name=_('Place'), default='', max_length=50)
destination = models.CharField(verbose_name=_('Destination (optional)'),
default='', max_length=50, blank=True)
date = models.DateField(default=datetime.today, verbose_name=_('Date'))
end = models.DateField(verbose_name=_('End (optional)'), blank=True, default=datetime.today)
# comment = models.TextField(_('Comments'), default='', blank=True)
groups = models.ManyToManyField(Group, verbose_name=_('Groups'))
jugendleiter = models.ManyToManyField(Member)
tour_type_choices = ((GEMEINSCHAFTS_TOUR, 'Gemeinschaftstour'),
(FUEHRUNGS_TOUR, 'Führungstour'),
(AUSBILDUNGS_TOUR, 'Ausbildung'))
# verbose_name is overriden by form, label is set in admin.py
tour_type = models.IntegerField(choices=tour_type_choices)
activity = models.ManyToManyField(ActivityCategory, default=None,
verbose_name=_('Categories'))
difficulty_choices = [(1, _('easy')), (2, _('medium')), (3, _('hard'))]
# verbose_name is overriden by form, label is set in admin.py
difficulty = models.IntegerField(choices=difficulty_choices)
membersonlist = GenericRelation(NewMemberOnList)
def __str__(self):
"""String represenation"""
return self.name
class Meta:
verbose_name = "Freizeit"
verbose_name_plural = "Freizeiten"
def get_tour_type(self):
if self.tour_type == FUEHRUNGS_TOUR:
return "Führungstour"
elif self.tour_type == AUSBILDUNGS_TOUR:
return "Ausbildung"
else:
return "Gemeinschaftstour"
def get_absolute_url(self):
return reverse('admin:members_memberlist_change', args=[str(self.id)])
class MemberNoteList(models.Model):
"""
A member list with a title and a bunch of members to take some notes.
"""
title = models.CharField(verbose_name=_('Title'), default='', max_length=50)
date = models.DateField(default=datetime.today, verbose_name=_('Date'), null=True, blank=True)
membersonlist = GenericRelation(NewMemberOnList)
def __str__(self):
"""String represenation"""
return self.title
class Meta:
verbose_name = "Notizliste"
verbose_name_plural = "Notizlisten"
class Klettertreff(models.Model): class Klettertreff(models.Model):
""" This model represents a Klettertreff event. """ This model represents a Klettertreff event.

Loading…
Cancel
Save