not exist. * Changes in the KyuDanRanking View to be more stable if we get bogus kwargs.
405 lines
16 KiB
Python
405 lines
16 KiB
Python
# -*- encoding: utf-8 -*-
|
|
from datetime import date
|
|
|
|
import django.forms
|
|
import django.http
|
|
from django.contrib import auth
|
|
from django.contrib.auth.mixins import LoginRequiredMixin, \
|
|
PermissionRequiredMixin
|
|
from django.contrib.messages.views import SuccessMessageMixin
|
|
from django.urls import reverse
|
|
from django.utils.translation import ugettext as _
|
|
from django.views import generic
|
|
|
|
from events.mixins import EventDetailMixin
|
|
from kasu import xlsx
|
|
from . import forms, models
|
|
from .mixins import MahjongMixin
|
|
|
|
DEFAULT_KYU_DAN_ORDER = '-score'
|
|
KYU_DAN_ORDER = { # map sort URL args to Django ORM order_by args
|
|
'+full_name': ('user__last_name', 'user__first_name'),
|
|
'-full_name': ('-user__last_name', '-user__first_name'),
|
|
'+hanchan_count': ('hanchan_count',),
|
|
'-hanchan_count': ('-hanchan_count',),
|
|
'+rank': ('-kyu', 'dan'),
|
|
'-rank': ('-dan', 'kyu'),
|
|
'+score': ('dan_points', '-dan', 'kyu_points'),
|
|
'-score': ('-dan_points', 'dan', '-kyu_points'),
|
|
'+username': ('user__username',),
|
|
'-username': ('-user__username',)
|
|
}
|
|
|
|
|
|
class DeleteHanchan(EventDetailMixin, PermissionRequiredMixin,
|
|
generic.DeleteView):
|
|
"""Deletes a Hanchan if confimration has been answerd with 'yes'."""
|
|
form_class = forms.HanchanForm
|
|
model = models.Hanchan
|
|
permission_required = 'mahjong_ranking.delete_hanchan'
|
|
pk_url_kwarg = 'hanchan'
|
|
|
|
def get_success_url(self):
|
|
"""
|
|
Return to the HachanList of the event form the deleted hanchan.
|
|
:return: URL of the EventHanchanList for the event
|
|
"""
|
|
return reverse('event-hanchan-list',
|
|
kwargs={'event': self.object.event.pk})
|
|
|
|
|
|
class HanchanForm(SuccessMessageMixin, EventDetailMixin,
|
|
PermissionRequiredMixin, generic.UpdateView):
|
|
"""
|
|
A Form to add a new or edit an existing Hanchan.
|
|
"""
|
|
form_class = forms.HanchanForm
|
|
model = models.Hanchan
|
|
permission_required = 'mahjong_ranking.add_hanchan'
|
|
|
|
def get_form_class(self):
|
|
"""
|
|
Users with hanchan edit persmission can also un-/confirm hanchans.
|
|
:return: forms.HanchanForm, or forms.HanchanAdminForm
|
|
"""
|
|
return forms.HanchanAdminForm if self.request.user.has_perm(
|
|
'mahjong_ranking.change_hanchan') else forms.HanchanForm
|
|
|
|
def get_object(self, queryset=None):
|
|
"""
|
|
load the hanchan form the db, or create a new one with the event set.
|
|
Also sets the event attribute.
|
|
:param queryset:
|
|
:return: models.Hanchan object
|
|
"""
|
|
if self.kwargs.get('hanchan') and self.request.user.has_perm(
|
|
'mahjong_ranking.change_hanchan'):
|
|
hanchan = self.model.objects.get(id=self.kwargs['hanchan'])
|
|
self.event = hanchan.event
|
|
elif self.kwargs.get('event'):
|
|
self.event = models.Event.objects.get(id=self.kwargs['event'])
|
|
hanchan = models.Hanchan(
|
|
event=self.event,
|
|
start=self.event.start
|
|
)
|
|
return hanchan
|
|
|
|
def get_success_url(self):
|
|
"""
|
|
Adding a new Hanchan redirect to create_hanchan form.
|
|
Editing an exiting one: redierect to the Hanchanevent.
|
|
"""
|
|
if self.kwargs.get('hanchan'):
|
|
return self.object.get_absolute_url()
|
|
else:
|
|
return reverse('add-hanchan-form', kwargs={'event': self.event.pk})
|
|
|
|
def get_success_message(self, cleaned_data):
|
|
"""
|
|
Get the right sucsess message for the django notification subsystem.
|
|
:param cleaned_data:
|
|
:return: Sucsess message
|
|
"""
|
|
if self.kwargs.get('hanchan'):
|
|
return _('%s has been updated successfully.') % self.object
|
|
else:
|
|
return _(
|
|
'%s has been added successfully. You can now add a new '
|
|
'one.') % self.object
|
|
|
|
|
|
class EventHanchanForm(EventDetailMixin, PermissionRequiredMixin,
|
|
generic.TemplateView):
|
|
"""Display a Formset to add and Edit Hanchans of the specific Event."""
|
|
permission_required = 'mahjong_ranking.edit_hanchan'
|
|
template_name = 'mahjong_ranking/eventhanchan_form.html'
|
|
model=models.Hanchan
|
|
|
|
def get_context_data(self, **kwargs):
|
|
self.event = models.Event.objects.get(pk=self.kwargs['event'])
|
|
context = super(EventHanchanForm, self).get_context_data()
|
|
context['formset'] = self.formset
|
|
return context
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
self.get_queryset()
|
|
self.formset = forms.HanchanFormset(
|
|
instance=self.event,
|
|
initial=[{'start': self.event.start}]
|
|
)
|
|
context = self.get_context_data(**kwargs)
|
|
return self.render_to_response(context)
|
|
|
|
def post(self, request, *args, **kwargs):
|
|
print("ICH WURDE GEPOSTET!!!!")
|
|
self.get_queryset()
|
|
self.formset = forms.HanchanFormset(
|
|
self.request.POST,
|
|
self.request.FILES,
|
|
instance=self.event,
|
|
initial=[{'start': self.event.start}]
|
|
)
|
|
if self.formset.is_valid():
|
|
self.formset.save()
|
|
return django.http.HttpResponseRedirect(
|
|
reverse('event-hanchan-form', kwargs={'event': self.event.pk})
|
|
)
|
|
context = self.get_context_data(**kwargs)
|
|
return self.render_to_response(context)
|
|
|
|
|
|
|
|
class EventHanchanList(EventDetailMixin, generic.ListView):
|
|
"List all hanchans played on a given event."
|
|
model = models.Hanchan
|
|
template_name = 'mahjong_ranking/eventhanchan_list.html'
|
|
|
|
|
|
class EventRankingList(EventDetailMixin, generic.ListView):
|
|
"""Display the event ranking for the given event."""
|
|
model = models.EventRanking
|
|
|
|
|
|
class KyuDanRankingList(MahjongMixin, generic.ListView):
|
|
"""List all Players with an Kyu or Dan score. """
|
|
order_by = None
|
|
paginate_by = 25
|
|
|
|
def dispatch(self, request, *args, **kwargs):
|
|
"""Set the order_by settings, revert to default_order if necessary."""
|
|
if kwargs.get('order_by') in KYU_DAN_ORDER.keys():
|
|
self.order_by = KYU_DAN_ORDER[kwargs.get('order_by')]
|
|
else:
|
|
self.order_by = KYU_DAN_ORDER[DEFAULT_KYU_DAN_ORDER]
|
|
return super(KyuDanRankingList, self).dispatch(request, *args, **kwargs)
|
|
|
|
def get_queryset(self):
|
|
queryset = models.KyuDanRanking.objects.filter(
|
|
hanchan_count__gt=0).order_by(*self.order_by)
|
|
return queryset.select_related()
|
|
|
|
|
|
class SeasonRankingList(MahjongMixin, generic.ListView):
|
|
model = models.SeasonRanking
|
|
paginate_by = 25
|
|
season = None
|
|
|
|
def get_queryset(self):
|
|
self.season = int(self.kwargs.get('season', date.today().year))
|
|
queryset = self.model.objects.filter(
|
|
season=self.season,
|
|
placement__isnull=False
|
|
)
|
|
return queryset.select_related()
|
|
|
|
|
|
class PlayerScore(LoginRequiredMixin, generic.ListView):
|
|
paginate_by = 25
|
|
user = auth.get_user_model()
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
user_model = auth.get_user_model()
|
|
try:
|
|
self.user = user_model.objects.get(
|
|
username=self.kwargs.get('username'))
|
|
except user_model.DoesNotExist:
|
|
raise django.http.Http404(
|
|
_("No user found matching the name {}").format(
|
|
self.kwargs.get('username')))
|
|
print(request.GET)
|
|
if request.GET.get('download') == 'xlsx':
|
|
return self.get_xlsx(request, *args, **kwargs)
|
|
return super(PlayerScore, self).get(request, *args, **kwargs)
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = generic.ListView.get_context_data(self, **kwargs)
|
|
context['membership'] = self.user
|
|
try:
|
|
context['kyu_dan_ranking'] = models.KyuDanRanking.objects.get(
|
|
user=self.user)
|
|
except models.KyuDanRanking.DoesNotExist:
|
|
context['ranking'] = None
|
|
try:
|
|
context['ladder_ranking'] = models.SeasonRanking.objects.get(
|
|
user=self.user,
|
|
season=date.today().year)
|
|
except models.SeasonRanking.DoesNotExist:
|
|
context['ladder_ranking'] = models.SeasonRanking(user=self.user)
|
|
return context
|
|
|
|
def get_xlsx(self, request, *args, **kwargs):
|
|
self.object_list = self.get_queryset()
|
|
response = django.http.HttpResponse(
|
|
content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
|
|
response['Content-Disposition'] = 'attachment; ' \
|
|
'filename="{xlsx_filename}"'.format(
|
|
xlsx_filename=self.xlsx_filename)
|
|
xlxs_workbook = xlsx.Workbook()
|
|
xlxs_workbook.generate_sheet(
|
|
title=self.xlsx_filename.split('.')[0],
|
|
columns_settings=self.xlsx_columns,
|
|
object_list=self.object_list
|
|
)
|
|
xlxs_workbook.save(response)
|
|
return response
|
|
|
|
|
|
class PlayerDanScore(PlayerScore):
|
|
template_name = 'mahjong_ranking/player_dan_score.html'
|
|
|
|
def get_queryset(self):
|
|
self.kyu_dan_ranking = models.KyuDanRanking.objects.get(user=self.user)
|
|
return models.Hanchan.objects.dan_hanchans(
|
|
user=self.user,
|
|
since=self.kyu_dan_ranking.legacy_date)
|
|
|
|
@property
|
|
def xlsx_columns(self):
|
|
return (
|
|
{'col': 'A', 'title': 'Beginn', 'attr': 'start',
|
|
'style': 'Date Time',
|
|
'width': 14, 'footer': self.kyu_dan_ranking.legacy_date},
|
|
{'col': 'B', 'title': 'Termin', 'attr': 'event.name',
|
|
'style': 'Content', 'width': 16},
|
|
{'col': 'C', 'title': 'Platzierung', 'attr': 'placement',
|
|
'style': 'Integer', 'width': 11},
|
|
{'col': 'D', 'title': 'Spieler 1', 'attr': 'player1.username',
|
|
'style': 'Content', 'width': 16},
|
|
{'col': 'E', 'title': 'Punkte', 'attr': 'player1_game_score',
|
|
'style': 'Integer', 'width': 8},
|
|
{'col': 'F', 'title': 'Spieler 2', 'attr': 'player2.username',
|
|
'style': 'Content', 'width': 16},
|
|
{'col': 'G', 'title': 'Punkte', 'attr': 'player2_game_score',
|
|
'style': 'Integer', 'width': 8},
|
|
{'col': 'H', 'title': 'Spieler 3', 'attr': 'player3.username',
|
|
'style': 'Content', 'width': 16},
|
|
{'col': 'I', 'title': 'Punkte', 'attr': 'player3_game_score',
|
|
'style': 'Integer', 'width': 8},
|
|
{'col': 'J', 'title': 'Spieler 4', 'attr': 'player4.username',
|
|
'style': 'Content', 'width': 16},
|
|
{'col': 'K', 'title': 'Punkte', 'attr': 'player4_game_score',
|
|
'style': 'Integer', 'width': 8},
|
|
{'col': 'L', 'title': 'Dan Punkte', 'attr': 'dan_points',
|
|
'style': 'Integer', 'width': 12,
|
|
'footer': self.kyu_dan_ranking.legacy_dan_points},
|
|
{'col': 'M', 'title': 'Anmerkung', 'attr': 'player_comment',
|
|
'style': 'Content', 'width': 20, 'footer': 'Legacy Dan Punkte'},
|
|
)
|
|
|
|
@property
|
|
def xlsx_filename(self):
|
|
return "{username}_dan_score.xlsx".format(username=self.user.username)
|
|
|
|
|
|
class PlayerInvalidScore(PlayerScore):
|
|
template_name = 'mahjong_ranking/player_invalid_score.html'
|
|
|
|
def get_queryset(self):
|
|
self.xlsx_filename = "{username}_invalid_score.xlsx".format(
|
|
username=self.user.username)
|
|
return models.Hanchan.objects.unconfirmed(user=self.user)
|
|
|
|
|
|
class PlayerKyuScore(PlayerScore):
|
|
template_name = 'mahjong_ranking/player_kyu_score.html'
|
|
|
|
def get_queryset(self):
|
|
self.kyu_dan_ranking = models.KyuDanRanking.objects.get(user=self.user)
|
|
return models.Hanchan.objects.kyu_hanchans(
|
|
user=self.user,
|
|
since=self.kyu_dan_ranking.legacy_date)
|
|
|
|
@property
|
|
def xlsx_columns(self):
|
|
return (
|
|
{'col': 'A', 'title': 'Beginn', 'attr': 'start',
|
|
'style': 'Date Time',
|
|
'width': 14, 'footer': self.kyu_dan_ranking.legacy_date},
|
|
{'col': 'B', 'title': 'Termin', 'attr': 'event.name',
|
|
'style': 'Content', 'width': 16},
|
|
{'col': 'C', 'title': 'Platzierung', 'attr': 'placement',
|
|
'style': 'Integer', 'width': 11},
|
|
{'col': 'D', 'title': 'Spieler 1', 'attr': 'player1.username',
|
|
'style': 'Content', 'width': 16},
|
|
{'col': 'E', 'title': 'Punkte', 'attr': 'player1_game_score',
|
|
'style': 'Integer', 'width': 8},
|
|
{'col': 'F', 'title': 'Spieler 2', 'attr': 'player2.username',
|
|
'style': 'Content', 'width': 16},
|
|
{'col': 'G', 'title': 'Punkte', 'attr': 'player2_game_score',
|
|
'style': 'Integer', 'width': 8},
|
|
{'col': 'H', 'title': 'Spieler 3', 'attr': 'player3.username',
|
|
'style': 'Content', 'width': 16},
|
|
{'col': 'I', 'title': 'Punkte', 'attr': 'player3_game_score',
|
|
'style': 'Integer', 'width': 8},
|
|
{'col': 'J', 'title': 'Spieler 4', 'attr': 'player4.username',
|
|
'style': 'Content', 'width': 16},
|
|
{'col': 'K', 'title': 'Punkte', 'attr': 'player4_game_score',
|
|
'style': 'Integer', 'width': 8},
|
|
{'col': 'L', 'title': 'Kyū Punkte', 'attr': 'kyu_points',
|
|
'style': 'Integer', 'width': 12,
|
|
'footer': self.kyu_dan_ranking.legacy_kyu_points},
|
|
{'col': 'M', 'title': 'Anmerkung', 'attr': 'comment',
|
|
'style': 'Content', 'width': 24, 'footer': 'Legacy Kyū Punkte'},
|
|
)
|
|
|
|
@property
|
|
def xlsx_filename(self):
|
|
return "{username}_kyu_score.xlsx".format(username=self.user.username)
|
|
|
|
|
|
class PlayerLadderScore(PlayerScore):
|
|
season = None
|
|
template_name = 'mahjong_ranking/player_ladder_score.html'
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(PlayerLadderScore, self).get_context_data(**kwargs)
|
|
context['season'] = self.season
|
|
context['season_start'] = date(year=self.season, month=1, day=1)
|
|
context['season_end'] = date(year=self.season, month=12, day=31)
|
|
context['season_list'] = models.SeasonRanking.objects.season_list
|
|
return context
|
|
|
|
def get_queryset(self, **kwargs):
|
|
self.season = int(self.request.GET.get('season', date.today().year))
|
|
hanchan_list = models.Hanchan.objects.season_hanchans(
|
|
user=self.user,
|
|
season=self.season
|
|
)
|
|
return hanchan_list
|
|
|
|
@property
|
|
def xlsx_columns(self):
|
|
return (
|
|
{'col': 'A', 'title': 'Beginn', 'attr': 'start',
|
|
'style': 'Date Time', 'width': 14},
|
|
{'col': 'B', 'title': 'Termin', 'attr': 'event.name',
|
|
'style': 'Content', 'width': 16},
|
|
{'col': 'C', 'title': 'Platzierung', 'attr': 'placement',
|
|
'style': 'Integer', 'width': 11},
|
|
{'col': 'D', 'title': 'Spieler 1', 'attr': 'player1.username',
|
|
'style': 'Content', 'width': 16},
|
|
{'col': 'E', 'title': 'Punkte', 'attr': 'player1_game_score',
|
|
'style': 'Integer', 'width': 8},
|
|
{'col': 'F', 'title': 'Spieler 2', 'attr': 'player2.username',
|
|
'style': 'Content', 'width': 16},
|
|
{'col': 'G', 'title': 'Punkte', 'attr': 'player2_game_score',
|
|
'style': 'Integer', 'width': 8},
|
|
{'col': 'H', 'title': 'Spieler 3', 'attr': 'player3.username',
|
|
'style': 'Content', 'width': 16},
|
|
{'col': 'I', 'title': 'Punkte', 'attr': 'player3_game_score',
|
|
'style': 'Integer', 'width': 8},
|
|
{'col': 'J', 'title': 'Spieler 4', 'attr': 'player4.username',
|
|
'style': 'Content', 'width': 16},
|
|
{'col': 'K', 'title': 'Punkte', 'attr': 'player4_game_score',
|
|
'style': 'Integer', 'width': 8},
|
|
{'col': 'L', 'title': 'Punkte', 'attr': 'game_score',
|
|
'style': 'Integer', 'width': 8},
|
|
)
|
|
|
|
@property
|
|
def xlsx_filename(self):
|
|
return "{username}_ladder_score_{season}.xlsx".format(
|
|
username=self.user.username,
|
|
season=self.season
|
|
)
|