Paginator der besser ins Design passt.

This commit is contained in:
Christian Berg
2014-12-10 00:23:36 +01:00
parent 2011d3ce25
commit 711c303f9a
75 changed files with 675 additions and 1599 deletions

View File

@@ -30,7 +30,6 @@ DAN_RANKS = (
DAN_RANKS_DICT = dict([(dan, points) for points, dan in DAN_RANKS])
MIN_HANCHANS_FOR_LADDER = 10
logger = getLogger('kasu.mahjong_ranking')

View File

@@ -7,9 +7,10 @@ Created on 19.09.2011
"""
# import stuff we need from django
from django.contrib import admin
from django.utils.translation import ugettext as _
from . import models, set_dirty
from forms import PlayerFormSet
from django.utils.translation import ugettext as _
def recalculate(modeladmin, request, queryset):
@@ -27,7 +28,10 @@ def recalculate(modeladmin, request, queryset):
set_dirty(season=ranking_season.id)
elif isinstance(modeladmin, LadderRankingAdmin):
for ladder_ranking in queryset:
set_dirty(user=ladder_ranking.user_id, season=ladder_ranking.season_id) # @IgnorePep8
set_dirty(user=ladder_ranking.user_id,
season=ladder_ranking.season_id) # @IgnorePep8
recalculate.short_description = _("Recalculate")
@@ -35,7 +39,7 @@ class PlayerInline(admin.TabularInline):
extra = 4
formset = PlayerFormSet
readonly_fields = ('placement', 'kyu_points', 'dan_points', 'bonus_points',
'comment',)
'comment',)
max_num = 4
model = models.Player
@@ -43,7 +47,7 @@ class PlayerInline(admin.TabularInline):
class EventRankingAdmin(admin.ModelAdmin):
list_filter = ['event']
list_display = ('placement', 'user', 'event', 'avg_placement', 'avg_score',
'hanchan_count', 'good_hanchans', 'won_hanchans', 'dirty')
'hanchan_count', 'good_hanchans', 'won_hanchans', 'dirty')
list_display_links = ('user',)
actions = [recalculate]
@@ -53,7 +57,7 @@ class HanchanAdmin(admin.ModelAdmin):
date_hierarchy = 'start'
list_filter = ['season', 'event']
list_display = ('event', 'start', 'player_names', 'comment',
'confirmed', 'valid', 'check_validity')
'confirmed', 'valid', 'check_validity')
inlines = (PlayerInline,)
readonly_fields = ('valid', 'check_validity')
@@ -66,13 +70,14 @@ class HanchanAdmin(admin.ModelAdmin):
class KyuDanAdmin(admin.ModelAdmin):
actions = [recalculate]
list_display = ('user', 'kyu', 'kyu_points', 'dan', 'dan_points',
'hanchan_count', 'dirty')
'hanchan_count', 'dirty')
class LadderRankingAdmin(admin.ModelAdmin):
actions = [recalculate]
list_display = ('placement', 'season', 'user', 'avg_placement',
'avg_score', 'hanchan_count', 'good_hanchans', 'won_hanchans', 'dirty')
'avg_score', 'hanchan_count', 'good_hanchans',
'won_hanchans', 'dirty')
list_display_links = ('user',)
list_filter = ('season',)

View File

@@ -12,7 +12,6 @@ from django.utils import timezone
from django.utils.translation import ugettext as _
from utils.html5 import forms
from . import models
@@ -81,7 +80,6 @@ class PlayerForm(forms.ModelForm):
class PlayerInlineFormSet(BaseInlineFormSet):
def clean(self):
"""Checks that no two articles have the same title."""
for form in self.forms:
@@ -102,6 +100,7 @@ class SeasonSelectForm(django.forms.Form):
season_list = season_list.values_list('season__id', 'season__name')
self.fields['season'] = django.forms.ChoiceField(choices=season_list)
PlayerFormSet = inlineformset_factory(
models.Hanchan,
models.Player,

View File

@@ -4,13 +4,16 @@
Generate Randum Mahjong Hanchans to the the Raning System
"""
from django.contrib import auth
from django.core.management.base import BaseCommand
from events.models import Event
from mahjong_ranking import models
import random
from datetime import timedelta
from django.contrib import auth
from django.core.management.base import BaseCommand
from events.models import Event
from mahjong_ranking import models
class Command(BaseCommand):
help = "Deletes all expired user registrations from the database"
@@ -23,7 +26,8 @@ class Command(BaseCommand):
player_list = list()
ostwind_list = list()
for user in user_list:
player_list.append(models.Player(user=user, hanchan=hanchan, score=25000))
player_list.append(
models.Player(user=user, hanchan=hanchan, score=25000))
for player in player_list:
player.save()
@@ -33,8 +37,8 @@ class Command(BaseCommand):
ostwind = ostwind_list.pop()
while not end_of_game:
score = random.randrange(1300, 8000, 100)
loser = player_list[random.randrange(0,4,1)]
winner = player_list[random.randrange(0,4,1)]
loser = player_list[random.randrange(0, 4, 1)]
winner = player_list[random.randrange(0, 4, 1)]
winner.score += score
print 'Ostwind: %s, Gewinner: %s, Verlierer: %s, %d Punkte' % (
@@ -73,9 +77,9 @@ class Command(BaseCommand):
print ""
def create_hanchan(self, event):
start = event.start + timedelta(minutes = random.randrange(00, 300, 15))
start = event.start + timedelta(minutes=random.randrange(00, 300, 15))
print event.name, start
print '='*80
print '=' * 80
hanchan = models.Hanchan(event=event, start=start)
hanchan.save()
self.add_players(hanchan)
@@ -87,7 +91,7 @@ class Command(BaseCommand):
self.user_list = list(auth.get_user_model().objects.all())
for event in Event.objects.all():
for i in range(random.randrange(2,8)):
for i in range(random.randrange(2, 8)):
self.create_hanchan(event)

View File

@@ -6,6 +6,7 @@ Created on 23.05.2011
"""
from django.core.cache import cache
from django.db import transaction
from mahjong_ranking import models
from . import logger
@@ -30,7 +31,8 @@ class DenormalizationUpdateMiddleware(object):
if len(event_ranking_queue) > 0:
while len(event_ranking_queue) > 0:
event_id, user_id = event_ranking_queue.pop()
logger.info("recalculate %d tournament Ranking in %s", user_id, event_id)
logger.info("recalculate %d tournament Ranking in %s", user_id,
event_id)
ranking = models.EventRanking.objects.get_or_create(
event_id=event_id, user_id=user_id)[0]
ranking.recalculate()
@@ -57,7 +59,8 @@ class DenormalizationUpdateMiddleware(object):
user_id=user_id, season_id=season_id)[0]
ranking.recalculate()
else:
logger.error('Season: %i; Benutzer Nr. %i - existiert nicht!', season_id, user_id)
logger.error('Season: %i; Benutzer Nr. %i - existiert nicht!',
season_id, user_id)
cache.set('ladder_ranking_queue', ladder_ranking_queue, 360)
transaction.commit()

View File

@@ -1,6 +1,7 @@
# -*- encoding: utf-8 -*-
from datetime import date, timedelta
from django.conf import settings
from django.core.cache import cache
from django.core.exceptions import ValidationError
@@ -9,11 +10,12 @@ from django.db import models
from django.db.models.aggregates import Sum
from django.utils import timezone
from django.utils.translation import ugettext as _
from events.models import Event
from events.models import Event
from . import KYU_RANKS, DAN_RANKS, DAN_RANKS_DICT, MIN_HANCHANS_FOR_LADDER
from . import logger, set_dirty
kyu_dan_rankings = set()
ladder_rankings = set()
ladder_seasons = set()
@@ -53,8 +55,10 @@ class EventRanking(models.Model):
zur neuberrechnung zu markieren. Mittlerweile wird ein lokaler
Cache dafür verwendet, das ist schneller.
"""
logger.info(u'Recalculate EventRanking for Player %s in %s', self.user, self.event.name) # @IgnorePep8
event_hanchans = Player.objects.valid_hanchans(user=self.user_id, event=self.event_id) # @IgnorePep8
logger.info(u'Recalculate EventRanking for Player %s in %s', self.user,
self.event.name) # @IgnorePep8
event_hanchans = Player.objects.valid_hanchans(user=self.user_id,
event=self.event_id) # @IgnorePep8
aggregator = event_hanchans.aggregate(
models.Avg('placement'),
models.Avg('score'),
@@ -78,7 +82,9 @@ class Hanchan(models.Model):
Außerdem gehört jede Hanchan zu einer Veranstaltung.
"""
comment = models.TextField(_('Comment'), blank=True)
confirmed = models.BooleanField(_('Has been Confirmed'), default=True, help_text=_('Only valid and confirmed Hanchans will be counted in the rating.')) # @IgnorePep8
confirmed = models.BooleanField(_('Has been Confirmed'), default=True,
help_text=_(
'Only valid and confirmed Hanchans will be counted in the rating.')) # @IgnorePep8
event = models.ForeignKey(Event)
player_names = models.CharField(max_length=127, editable=False)
players = models.ManyToManyField(
@@ -86,8 +92,10 @@ class Hanchan(models.Model):
through='Player',
verbose_name=_('Players')
)
season = models.ForeignKey('LadderSeason', blank=True, null=True, editable=False) # @IgnorePep8
start = models.DateTimeField(_('Start'), help_text=_('This is crucial to get the right Hanchans that scores')) # @IgnorePep8
season = models.ForeignKey('LadderSeason', blank=True, null=True,
editable=False) # @IgnorePep8
start = models.DateTimeField(_('Start'), help_text=_(
'This is crucial to get the right Hanchans that scores')) # @IgnorePep8
valid = models.BooleanField(_('Is Valid'), default=False)
class Meta(object):
@@ -96,7 +104,8 @@ class Hanchan(models.Model):
verbose_name_plural = _(u'Hanchans')
def __str__(self):
return "Hanchan am {0:%d.%m.%Y} um {0:%H:%M} ({1})".format(self.start, self.player_names)
return "Hanchan am {0:%d.%m.%Y} um {0:%H:%M} ({1})".format(self.start,
self.player_names)
def check_validity(self):
"""
@@ -148,12 +157,14 @@ class Hanchan(models.Model):
Die Gültigkeit wird geprüft und die Sasion in der die Hanchan liegt
wird aktualisert.
"""
logger.debug("Hanchan clean() wurde getriggert!")
super(Hanchan, self).clean()
# if self.pk and self.player_set.distinct().count() != 4:
# raise ValidationError(
# raise ValidationError(
# _('For a Hanchan exactly 4 players are needed.'))
if self.start and self.start > timezone.now():
if not self.event_id:
raise ValidationError(_("Hanchan has no event"))
elif self.start and self.start > timezone.now():
raise ValidationError(_("It's not allowed to enter future games."))
elif not (self.event.start <= self.start <= self.event.end):
raise ValidationError(_("Only games during the event are allowed"))
@@ -195,7 +206,8 @@ class Hanchan(models.Model):
def save(self, **kwargs):
logger.debug("Hanchan save() wurde getriggert!")
self.season = self.season or LadderSeason.objects.get_by_date(self.start)
self.season = self.season or LadderSeason.objects.get_by_date(
self.start)
if self.pk:
self.check_validity()
self.compute_player_placements()
@@ -245,7 +257,8 @@ class KyuDanRanking(models.Model):
self.wins_in_a_row = 0
if self.dan and self.wins_in_a_row > 2:
logger.info('adding bonuspoints for 3 wins in a row for %s', self.user) # @IgnorePep8
logger.info('adding bonuspoints for 3 wins in a row for %s',
self.user) # @IgnorePep8
new_dan_rank = self.dan + 1
new_dan_points = DAN_RANKS_DICT[new_dan_rank] + 1
bonus_points = new_dan_points - self.dan_points
@@ -253,7 +266,8 @@ class KyuDanRanking(models.Model):
logger.debug("Stats for %s:", self.user)
logger.debug("current dan_points: %d", self.dan_points)
logger.debug("current dan: %d", self.dan)
logger.debug("min required points for the next dan: %d", new_dan_points) # @IgnorePep8
logger.debug("min required points for the next dan: %d",
new_dan_points) # @IgnorePep8
logger.debug("bonus points to add: %d", bonus_points)
hanchan.dan_points += bonus_points
@@ -424,7 +438,8 @@ class LadderRanking(models.Model):
return reverse('player-ladder-score', args=[self.user.username])
def recalculate(self):
logger.info(u'Recalculate LadderRanking for Player %s in Season %s', self.user, self.season) # @IgnorePep8
logger.info(u'Recalculate LadderRanking for Player %s in Season %s',
self.user, self.season) # @IgnorePep8
ladder_hanchans = Player.objects.ladder_hanchans(
self.user_id, self.season_id)
aggregate = ladder_hanchans.aggregate(
@@ -443,7 +458,6 @@ class LadderRanking(models.Model):
class LadderSeasonManager(models.Manager):
def current(self):
"""
Returns the current season and caches the result for 12 hours
@@ -489,6 +503,14 @@ class LadderSeason(models.Model):
def __unicode__(self):
return self.name
def get_absolute_url(self):
"""
URL zur Hanchanliste des Events wo diese Hanchan gelistet wurde.
"""
return reverse('mahjong-ladder', kwargs={'season': self.pk})
def recalculate(self):
logger.info(u'Recalculate LadderSeason %s', self.name)
self.ladderranking_set.update(placement=None)
@@ -519,7 +541,8 @@ class PlayerManager(models.Manager):
queryset = queryset.filter(kyu_points__isnull=False).select_related()
return queryset
def ladder_hanchans(self, user=None, season=None, num_hanchans=None, max_age=None): # @IgnorePep8
def ladder_hanchans(self, user=None, season=None, num_hanchans=None,
max_age=None): # @IgnorePep8
queryset = self.valid_hanchans(user).order_by('-hanchan__start')
queryset = queryset.select_related()
season = season or LadderSeason.objects.current()
@@ -593,7 +616,8 @@ class Player(models.Model):
ordering = ['-score']
def __str__(self):
return "{0}'s Punkte vom {1: %d.%m.%Y um %H:%M}".format(self.user.username, self.hanchan.start)
return "{0}'s Punkte vom {1: %d.%m.%Y um %H:%M}".format(
self.user.username, self.hanchan.start)
def save(self, mark_dirty=True, season_id=None, *args, **kwargs):
season_id = season_id or self.hanchan.season_id
@@ -606,12 +630,15 @@ class Player(models.Model):
else:
return self
if season_id:
logger.debug("Marking %s's season no. %i ranking for recalculation.", self.user, season_id) # @IgnorePep8
logger.debug(
"Marking %s's season no. %i ranking for recalculation.",
self.user, season_id) # @IgnorePep8
set_dirty(season=season_id, user=self.user_id)
logger.debug("Marking season no %i for recalculation.", season_id)
set_dirty(season=season_id)
if self.hanchan.event.is_tournament:
logger.debug("Marking tournament %s for recalculation.", self.hanchan.event) # @IgnorePep8
logger.debug("Marking tournament %s for recalculation.",
self.hanchan.event) # @IgnorePep8
set_dirty(event=self.hanchan.event_id, user=self.user_id)
return self
@@ -622,4 +649,5 @@ def update_ranking_delete(sender, instance, **kwargs): # @UnusedVariable
if instance.season_id:
set_dirty(season=instance.season_id, user=player.user_id)
models.signals.pre_delete.connect(update_ranking_delete, sender=Hanchan)

View File

@@ -1,17 +1,11 @@
{% extends "events/event_site.html" %}
{% extends "events/event_detail.html" %}
{% load i18n comments%}
{% block title %}{% trans "Tournament Ranking" %}: {{ event.name }}{% endblock %}
{% block teaser %}<h1>{% trans "Tournament Ranking" %}: {{ event.name }}</h1>{% endblock %}
{% block event_content %}
{% if event.is_tournament %}
<ul class="tabs grid_12">
<li><a href="{% url 'event-hanchan-list' event.id %}">{% trans "Tournament Hanchans" %}</a></li>
<li class="active"><a href="{% url 'event-ranking' event.id %}">{% trans "Tournament Ranking" %}</a></li>
</ul>
{% endif %}
{% block maincontent %}
<div class="grid_12">
<table>
<thead>
@@ -21,13 +15,14 @@
<th rowspan="2">{% trans "Nickname" %}</th>
<th rowspan="2">{% trans "Name" %}</th>
<th colspan="2">{% trans 'Average' %}</th>
<th colspan="2">Hanchans</th>
<th colspan="3">Hanchans</th>
</tr>
<tr>
<th>{% trans 'Placement' %}</th>
<th>{% trans "Score" %}</th>
<th>{% trans "won" %}</th>
<th>{% trans "good" %}</th>
<th>{% trans 'Placement' %}</th>
<th>{% trans "Score" %}</th>
<th>{% trans "count" %}</th>
<th>{% trans "good" %}</th>
<th>{% trans "won" %}</th>
</tr>
</thead>
{% for player in eventranking_list %}
@@ -42,11 +37,12 @@
{% endif %}
</a></td>
<td><a href="{{ player.user.get_absolute_url }}">{{player.user}}</a></td>
<td>{{profile.last_name}} {{profile.first_name}}</td>
<td>{% if user.is_authenticated %}{{profile.last_name}} {{profile.first_name}}{% else %} ---{% endif %}</td>
<td class="center">{{player.avg_placement|floatformat:2 }}</td>
<td class="right">{{player.avg_score|floatformat:0 }}</td>
<td class="center">{{player.won_hanchans}}</td>
<td class="center">{{player.good_hanchans}}</td>
<td class="right">{{player.hanchan_count}}</td>
<td class="right">{{player.good_hanchans}}</td>
<td class="right">{{player.won_hanchans}}</td>
</tr>
{% endwith %}
{% empty %}

View File

@@ -1,10 +1,10 @@
{% extends "base.html" %}
{% extends "events/event_detail.html" %}
{% load i18n comments %}
{% block meta_title %}{% trans 'Delete Hanchan' %}{% endblock %}
{% block content %}
<form method="post">
{% block maincontent %}
<form method="post" class="grid_12">
{% csrf_token %}
<fieldset>
<legend>{% trans "Delete Hanchan" %}</legend>

View File

@@ -1,11 +1,11 @@
{% extends "events/event_site.html" %}
{% extends "events/event_detail.html" %}
{% load i18n comments fieldset_extras %}
{% block title %}
{% if hanchan.id %}{% trans "Edit Hanchan" %}{% else %}{% trans "Add Hanchan" %}{% endif %}
{% endblock %}
{% block event_content %}
{% block maincontent %}
{% get_fieldset "event, start" from form as event_formset %}
{% if perms.mahjong_ranking.delete_hanchan %}
{% get_fieldset "comment, confirmed" from form as hanchan_formset %}

View File

@@ -1,53 +1,56 @@
{% extends "events/event_site.html" %}
{% load i18n comments %}
{% extends "events/event_detail.html" %}
{% load i18n humanize %}
{% block title %}Hanchans: {{ event.name }}{% endblock %}
{% block event_content %}
{% if event.is_tournament %}
<ul class="tabs grid_12">
<li class="active"><a href="{% url 'event-hanchan-list' event.id %}">{% trans "Tournament Hanchans" %}</a></li>
<li><a href="{% url 'event-ranking' event.id %}">{% trans "Tournament Ranking" %}</a></li>
</ul>
{% endif %}
{% block maincontent %}
<h2 class="grid_12">{% trans 'Played Hanchans' %}</h2>
<p>&nbsp;</p>
{% for hanchan in hanchan_list %}
<h3 class="grid_12 clearfix" id="{{ hanchan.pk }}">{{hanchan.start|time:'H:i'}}: {{ hanchan.player_names }}</h3>
{% for player in hanchan.player_set.all %}
<div class="player" >
<a href="{% url 'player-ladder-score' player.user %}"><img
src="{% if player.user.get_profile.thumbnail %}{{player.user.get_profile.thumbnail.url}}{% else %}{{STATIC_URL}}img/unknown_thumbnail.png{% endif %}"
class="avatar" alt=""
title="{% if player.dan_points != None %}Dan P.: {{player.dan_points}}{% else %}Kyu P.: {{player.kyu_points}}{% endif %} - {{player.comment}}"/></a>
<h4>{{player.placement}}. - <a href="{% url 'player-ladder-score' player.user %}">{{ player.user }}</a></h4>
<strong>{% trans 'Score' %}:</strong> {{player.score}}
</div>
{% endfor %}
{% if not hanchan.valid %}
<p class="grid_12 error"><strong>Ungültig:</strong> {{hanchan.check_validity}}</p>
{% elif not hanchan.confirmed %}
<p class="grid_12 error">Diese Hanchan wurde nicht anerkannt und wird daher nicht gezählt.</p>
{% elif hanchan.comment %}
<p class="grid_12">{{ hanchan.comment }}</p>
{% endif %}
<p class="grid_12 more_link">
{% if perms.mahjong_ranking.delete_hanchan %}
<a href="{% url 'delete-hanchan' hanchan.pk %}" class="button"><img src="{{STATIC_URL}}icons/table_delete.png" alt="{% trans 'Delete' %}"/> {% trans 'Delete Hanchan' %}</a>
{% endif %}
{% if perms.mahjong_ranking.change_hanchan %}
<a href="{% url 'edit-hanchan' hanchan.pk %}" class="button"><img src="{{STATIC_URL}}icons/table_edit.png" alt="{% trans 'Edit' %}"/> {% trans 'Edit Hanchan' %}</a>
{% endif %}
</p>
<div class="grid_12" id="{{ hanchan.pk }}"><h3>{{hanchan.start|time:'H:i'}}: {{ hanchan.player_names }}</h3></div>
{% for player in hanchan.player_set.all %}
<a class="grid_1" href="{% url 'player-ladder-score' player.user %}"><img src="{% if player.user.get_profile.thumbnail %}{{player.user.get_profile.thumbnail.url}}{% else %}{{STATIC_URL}}img/unknown_thumbnail.png{% endif %}" class="avatar" alt="{{ player.user }}" title="{{ player.user }}"/></a>
<div class="grid_2">
<a class="player" href="{% url 'player-ladder-score' player.user %}" title="{{ player.comment }}">{{ player.user }}</a>
<p><strong>{{ player.placement|ordinal }} {% trans 'Place' %}</strong><br />
<strong>{% trans 'Score' %}:</strong> {{ player.score|intcomma }}<br />
{% if player.dan_points != None %}
<strong>{% trans 'Dan Points' %}:</strong> {{ player.dan_points }}
{% else %}
<strong>{% trans 'Kyu Points' %}:</strong> {{ player.kyu_points|default:0 }}
{% endif %}
</p>
</div>
{% endfor %}
{% if not hanchan.valid %}
<p class="grid_12 error"><strong>Ungültig:</strong> {{hanchan.check_validity}}</p>
{% elif not hanchan.confirmed %}
<p class="grid_12 error">Diese Hanchan wurde nicht anerkannt und wird daher nicht gezählt.</p>
{% elif hanchan.comment %}
<p class="grid_12">{{ hanchan.comment }}</p>
{% endif %}
<p class="grid_12 more_link">
{% if perms.mahjong_ranking.delete_hanchan %}
<a href="{% url 'delete-hanchan' hanchan.pk %}" class="button"><img src="{{STATIC_URL}}icons/table_delete.png"
alt="{% trans 'Delete' %}"/>
{% trans 'Delete Hanchan' %}</a>
{% endif %}
{% if perms.mahjong_ranking.change_hanchan %}
<a href="{% url 'edit-hanchan' hanchan.pk %}" class="button"><img src="{{STATIC_URL}}icons/table_edit.png"
alt="{% trans 'Edit' %}"/>
{% trans 'Edit Hanchan' %}</a>
{% endif %}
</p>
{% empty %}
<h3 class="grid_12">{% trans 'No Hanchan has been added to this event yet.'%}</h3>
<h3 class="grid_12">{% trans 'No Hanchan has been added to this event yet.'%}</h3>
{% endfor %}
{% endblock %}
{% block buttonbar %}
{% if perms.mahjong_ranking.add_hanchan %}
<a class="button" href="{{event.get_edit_url}}"><img src="{{STATIC_URL}}icons/calendar_edit.png" alt="{% trans 'Add' %}"/> {% trans 'Edit Event' %}</a>
<a class="button" href="{% url 'add-hanchan-form' event.id %}"><img src="{{STATIC_URL}}icons/table_add.png" alt="{% trans 'Add' %}"/> {% trans 'Add Hanchan' %}</a>
{% endif %}
{% if perms.mahjong_ranking.add_hanchan %}
<a class="button" href="{{event.get_edit_url}}"><img src="{{STATIC_URL}}icons/calendar_edit.png"
alt="{% trans 'Add' %}"/> {% trans 'Edit Event' %}</a>
<a class="button" href="{% url 'add-hanchan-form' event.id %}"><img src="{{STATIC_URL}}icons/table_add.png"
alt="{% trans 'Add' %}"/> {% trans 'Add Hanchan' %}</a>
{% endif %}
{% endblock %}

View File

@@ -1,7 +1,9 @@
{% extends "base.html" %}
{% load i18n comments%}
{% block teaser %} <h2>Mahjong Ranking - {{season.name}}</h2> {% endblock %}
{% block teaser %}
<h2>Mahjong Ranking - {{season.name}}</h2>
{% endblock %}
{% block maincontent %}
<main class="grid_12">
@@ -49,14 +51,6 @@
{% endblock %}
{% block redbox %}
{% if is_archive %}
<h2>{% trans 'Ladder Archive' %}</h2>
<ul class="list">
{% for season in season_archive %}
<li class="season"><a href="{% url 'mahjong-ladder-archive' season.id %}">{{season.name}}</a></li>
{% endfor %}
</ul>
{% else %}
<h2>{% trans 'Latest Hanchans' %}</h2>
<ul class="list">
{% for hanchan in latest_hanchan_list %}
@@ -69,9 +63,17 @@
</ul>
<h3>{% trans 'Latest Events' %}</h3>
<ul class="list">
{% for event in latest_event_list|slice:":3" %}
{% for event in latest_event_list %}
<li class="event"><a href="{% url 'event-hanchan-list' event.pk %}">{{event.name}}</a></li>
{% endfor %}
</ul>
{% endif %}
<h3>{% trans 'Ladder Archive' %}</h3>
<form name="season_select">
<label for="season">{% trans 'Season' %}</label>
<select id="season" name="season" size="1" onChange="window.location.href = document.season_select.season.options[document.season_select.season.selectedIndex].value;">
{% for season_link in season_list%}
<option value="{{ season_link.get_absolute_url }}" {% ifequal season.id season_link.id %}selected="selected"{% endifequal %}>{{ season_link.name }}</option>
{% endfor %}
</select>
</form>
{% endblock %}

View File

@@ -2,7 +2,9 @@
{% load i18n %}
{% block title %} {% trans 'Kyu Score for' %} {{player.username}} {% endblock %}
{% block teaser %}<h2>{% trans 'Invalid hanchans with' %} {{membership.user.username}}</h2>{% endblock %}
{% block score_list %}
<div class="grid_12">
<h2>{% trans 'Invalid hanchans with' %} {{membership.user.username}}</h2>

View File

@@ -6,49 +6,37 @@ Created on 03.10.2011
@author: christian
"""
from django.conf.urls import * # @UnusedWildImport
from django.views.generic import RedirectView
import views
urlpatterns = patterns(
'',
url(r'^$', views.LadderRankingList.as_view(), name="mahjong-ladder"),
url(r'archive/$',
views.LadderRankingList.as_view(),
kwargs={'is_archive': True},
name="mahjong-ladder-archive"),
url(r'archive/(?P<season>[\d]+)/$',
views.LadderRankingList.as_view(),
name="mahjong-ladder-archive"),
url(r'players/$',
views.KyuDanRankingList.as_view(),
url('^$', RedirectView.as_view(pattern_name='mahjong-ladder')),
url(r'players/$', views.KyuDanRankingList.as_view(),
name="kyudanranking-list"),
url(r'players/(?P<order_by>[\+\-\w]+)/$',
views.KyuDanRankingList.as_view(),
url(r'players/(?P<order_by>[\+\-\w]+)/$', views.KyuDanRankingList.as_view(),
name="kyudanranking-list"),
url(r'event/(?P<event>[\d]+)/$',
views.EventHanchanList.as_view(),
url(r'ranking/$', views.LadderRankingList.as_view(), name="mahjong-ladder"),
url(r'ranking/(?P<season>[\d]+)/$', views.LadderRankingList.as_view(),
name="mahjong-ladder"),
url(r'ranking/event/(?P<event>[\d]+)/$', views.EventHanchanList.as_view(),
name="event-hanchan-list"),
url(r'event/(?P<event>[\d]+)/ranking/$',
views.EventRankingList.as_view(),
name="event-ranking"),
url(r'event/(?P<event>[\d]+)/add-hanchan/$',
views.HanchanForm.as_view(),
name="add-hanchan-form"),
url(r'hanchan/(?P<hanchan>[\d]+)/edit/$',
views.HanchanForm.as_view(),
url(r'ranking/event/(?P<event>[\d]+)/ranking/$',
views.EventRankingList.as_view(), name="event-ranking"),
url(r'ranking/event/(?P<event>[\d]+)/add-hanchan/$',
views.HanchanForm.as_view(), name="add-hanchan-form"),
url(r'hanchan/(?P<hanchan>[\d]+)/edit/$', views.HanchanForm.as_view(),
name="edit-hanchan"),
url(r'hanchan/(?P<hanchan>[\d]+)/delete/$',
views.DeleteHanchan.as_view(),
url(r'hanchan/(?P<hanchan>[\d]+)/delete/$', views.DeleteHanchan.as_view(),
name="delete-hanchan"),
url(r'dan_score/(?P<username>[\-\.\d\w]+)/$',
views.PlayerDanScore.as_view(),
name="player-dan-score"),
url(r'invalid_score/(?P<username>[\-\.\d\w]+)/$',
views.PlayerInvalidScore.as_view(),
name="player-invalid-score"),
url(r'kyu_score/(?P<username>[\-\.\d\w]+)/$',
views.PlayerKyuScore.as_view(),
name="player-kyu-score"),
url(r'ladder_score/(?P<username>[\-\.\d\w]+)/$',
views.PlayerLadderScore.as_view(),
name="player-ladder-score"),
url(r'player/(?P<username>[\-\.\d\w]+)/dan/$',
views.PlayerDanScore.as_view(), name="player-dan-score"),
url(r'player/(?P<username>[\-\.\d\w]+)/invalid/$',
views.PlayerInvalidScore.as_view(), name="player-invalid-score"),
url(r'player/(?P<username>[\-\.\d\w]+)/kyu/$',
views.PlayerKyuScore.as_view(), name="player-kyu-score"),
url(r'player/(?P<username>[\-\.\d\w]+)/ladder/$',
views.PlayerLadderScore.as_view(), name="player-ladder-score"),
)

View File

@@ -11,6 +11,7 @@ from django.views import generic
import xlwt
from events.models import Event
from events.views import EventDetailMixin
from . import forms, models
from membership.models import Membership
from utils.mixins import LoginRequiredMixin, PermissionRequiredMixin
@@ -30,7 +31,7 @@ kyu_dan_order = {
}
class DeleteHanchan(PermissionRequiredMixin, generic.DeleteView):
class DeleteHanchan(EventDetailMixin, PermissionRequiredMixin, generic.DeleteView):
"""
Fragt zuerst nach, ob die Hanchan wirklich gelöscht werden soll.
Wir die Frage mit "Ja" beantwortet, wird die die Hanchan gelöscht.
@@ -42,10 +43,10 @@ class DeleteHanchan(PermissionRequiredMixin, generic.DeleteView):
def get_success_url(self):
return reverse('event-hanchan-list',
kwargs={'event': self.object.event.pk})
kwargs={'event': self.object.event.pk})
class HanchanForm(PermissionRequiredMixin, generic.UpdateView):
class HanchanForm(EventDetailMixin, PermissionRequiredMixin, generic.UpdateView):
"""
Ein Formular um eine neue Hanchan anzulegen, bzw. eine bestehende zu
bearbeitsen
@@ -130,7 +131,7 @@ class HanchanForm(PermissionRequiredMixin, generic.UpdateView):
return self.form_invalid(form, formset)
class EventHanchanList(generic.ListView):
class EventHanchanList(EventDetailMixin, generic.ListView):
"""
Auflistung aller Hanchan die während der Veranstaltung gespielt wurden.
"""
@@ -146,13 +147,8 @@ class EventHanchanList(generic.ListView):
except models.Event.DoesNotExist:
raise django.http.Http404(_('Event does not exist'))
def get_context_data(self, **kwargs):
context = generic.ListView.get_context_data(self, **kwargs)
context['event'] = self.event
return context
class EventRankingList(generic.ListView):
class EventRankingList(EventDetailMixin, generic.ListView):
"""
Anzeige des Eventrankings, daß erstellt wurde falls der Termin als internes
Turnier markiert wurde.
@@ -168,11 +164,6 @@ class EventRankingList(generic.ListView):
except models.Event.DoesNotExist:
raise django.http.Http404(_('Event does not exist'))
def get_context_data(self, **kwargs):
context = generic.ListView.get_context_data(self, **kwargs)
context['event'] = self.event
return context
class KyuDanRankingList(generic.ListView):
"""
@@ -183,7 +174,8 @@ class KyuDanRankingList(generic.ListView):
paginate_by = 25
def dispatch(self, request, *args, **kwargs):
self.order_by = kyu_dan_order[kwargs.get('order_by', self.default_order)] # @IgnorePep8
self.order_by = kyu_dan_order[
kwargs.get('order_by', self.default_order)] # @IgnorePep8
return generic.ListView.dispatch(self, request, *args, **kwargs)
def get_queryset(self):
@@ -202,7 +194,8 @@ class LadderRankingList(generic.ListView):
def get_queryset(self):
try:
if self.kwargs.get('season'):
self.season = models.LadderSeason.objects.get(pk=self.kwargs['season'])
self.season = models.LadderSeason.objects.get(
pk=self.kwargs['season'])
self.is_archive = True
elif self.kwargs.get('is_archive'):
self.season = models.LadderSeason.objects.order_by('-pk')[1]
@@ -211,16 +204,18 @@ class LadderRankingList(generic.ListView):
self.season = models.LadderSeason.objects.current()
except models.LadderSeason.DoesNotExist:
raise django.http.Http404(_('Season does not exist'))
queryset = models.LadderRanking.objects.filter(season=self.season, placement__isnull=False).select_related()
queryset = models.LadderRanking.objects.filter(season=self.season,
placement__isnull=False).select_related()
return queryset
def get_context_data(self, **kwargs):
context = generic.ListView.get_context_data(self, **kwargs)
context['is_archive'] = self.is_archive
context['season'] = self.season
context['season_archive'] = models.LadderSeason.objects.all()
context['latest_hanchan_list'] = models.Hanchan.objects.filter(valid=True)[:5]
context['latest_event_list'] = Event.objects.archive()[:5]
context['season_list'] = models.LadderSeason.objects.all()
context['latest_hanchan_list'] = models.Hanchan.objects.filter(
valid=True)[:3]
context['latest_event_list'] = Event.objects.archive()[:3]
return context
@@ -238,11 +233,13 @@ class LadderRankingExcel(generic.View):
response = django.http.HttpResponse(mimetype=u'application/msexcel')
filename = urllib.quote(self.filename.encode('utf-8'))
response['Content-Disposition'] = "attachment; filename*=UTF-8''%s" % filename
response[
'Content-Disposition'] = "attachment; filename*=UTF-8''%s" % filename
field_names = [u"Login", u"Name", u"E-Mail", u"Telefon", u"Handy", u"Geburtstag",
u"T-Shirt", u"Teams", u"Gr.", u"Kg", u"Notfall Adresse",
u"Notfall Nummer", u"Notizen", ]
field_names = [u"Login", u"Name", u"E-Mail", u"Telefon", u"Handy",
u"Geburtstag",
u"T-Shirt", u"Teams", u"Gr.", u"Kg", u"Notfall Adresse",
u"Notfall Nummer", u"Notizen", ]
# Erstelle ein Workbook (Das ist eine Excel Datei)
@@ -253,7 +250,8 @@ class LadderRankingExcel(generic.View):
sheet = workbook.add_sheet('Mitglieder', cell_overwrite_ok=False)
sheet.set_panes_frozen(True)
sheet.set_horz_split_pos(1) # in general, freeze after last heading row
sheet.set_remove_splits(True) # if user does unfreeze, don't leave a split there
sheet.set_remove_splits(
True) # if user does unfreeze, don't leave a split there
for column in range(0, len(field_names)):
sheet.write(0, column, field_names[column], style=header)
@@ -267,13 +265,17 @@ class LadderRankingExcel(generic.View):
profile = user.get_profile()
self.set_col(sheet, current_row, 3, profile.telephone or None)
self.set_col(sheet, current_row, 4, profile.mobilephone or None)
self.set_col(sheet, current_row, 5, profile.birthday or None, style=self.date)
self.set_col(sheet, current_row, 6, profile.shirt_size or None, style=self.center)
self.set_col(sheet, current_row, 5, profile.birthday or None,
style=self.date)
self.set_col(sheet, current_row, 6, profile.shirt_size or None,
style=self.center)
self.set_col(sheet, current_row, 7, self.get_other_teams(user))
self.set_col(sheet, current_row, 8, profile.height or None)
self.set_col(sheet, current_row, 9, profile.weight or None)
self.set_col(sheet, current_row, 10, profile.emergency_contact or None)
self.set_col(sheet, current_row, 11, profile.emergency_phone or None)
self.set_col(sheet, current_row, 10,
profile.emergency_contact or None)
self.set_col(sheet, current_row, 11,
profile.emergency_phone or None)
except Membership.DoesNotExist:
pass
current_row += 1
@@ -290,17 +292,22 @@ class PlayerScore(LoginRequiredMixin, generic.ListView):
def get(self, request, *args, **kwargs):
try:
self.user = auth.get_user_model().objects.get(username=self.kwargs.get('username'))
self.membership = Membership.objects.get_or_create(user=self.user)[0]
self.user = auth.get_user_model().objects.get(
username=self.kwargs.get('username'))
self.membership = Membership.objects.get_or_create(user=self.user)[
0]
except auth.get_user_model().DoesNotExist:
raise django.http.Http404(_("No user found matching the name %s") % self.kwargs.get('username'))
raise django.http.Http404(
_("No user found matching the name %s") % self.kwargs.get(
'username'))
return generic.ListView.get(self, request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = generic.ListView.get_context_data(self, **kwargs)
context['membership'] = self.membership
try:
context['kyu_dan_ranking'] = models.KyuDanRanking.objects.get(user=self.user)
context['kyu_dan_ranking'] = models.KyuDanRanking.objects.get(
user=self.user)
except models.KyuDanRanking.DoesNotExist:
context['ranking'] = None
try:
@@ -312,7 +319,6 @@ class PlayerScore(LoginRequiredMixin, generic.ListView):
return context
class PlayerDanScore(PlayerScore):
template_name = 'mahjong_ranking/player_dan_score.html'
@@ -339,16 +345,20 @@ class PlayerLadderScore(PlayerScore):
def get_context_data(self, **kwargs):
context = PlayerScore.get_context_data(self, **kwargs)
season_list = models.LadderRanking.objects.filter(user=self.user).select_related('user')
season_list = models.LadderRanking.objects.filter(
user=self.user).select_related('user')
season_list = season_list.values_list('id', 'season__name')
context['season'] = self.season
context['seasons_select_form'] = forms.SeasonSelectForm(user=self.user)
context['seasons_select_field'] = django.forms.ChoiceField(choices=season_list)
context['seasons_select_field'] = django.forms.ChoiceField(
choices=season_list)
return context
def get_queryset(self, **kwargs):
if self.request.GET.get('season'):
self.season = models.LadderSeason.objects.get(pk=self.request.GET['season'])
self.season = models.LadderSeason.objects.get(
pk=self.request.GET['season'])
else:
self.season = models.LadderSeason.objects.current()
return models.Player.objects.ladder_hanchans(user=self.user, season=self.season)
return models.Player.objects.ladder_hanchans(user=self.user,
season=self.season)