Anpassungen für das Hosting bei Djangoeurope und damit verbundenen Versionen Django 1.8 und Python 2.7

This commit is contained in:
Christian Berg
2015-08-05 18:55:48 +02:00
committed by Christian Berg
parent cb4b15b3c6
commit b96b485b61
1354 changed files with 7289 additions and 6858 deletions

View File

View File

@@ -0,0 +1,64 @@
# -*- encoding: utf-8 -*-
"""
Created on 19.09.2011
@author: christian
"""
from django.contrib import admin
from django.utils.translation import ugettext as _
from . import forms, models
def recalculate(modeladmin, request, queryset): # @UnusedVariable
if isinstance(modeladmin, RankingAdmin):
seasons = set()
for ranking in queryset:
ranking.recalculate()
seasons.add(ranking.season)
for season in seasons:
models.Ranking.objects.calculate_rankings(season)
recalculate.short_description = _("Recalculate")
class RankingAdmin(admin.ModelAdmin):
actions = [recalculate]
list_display = (
'season', 'placement', 'user', 'avg_placement', 'avg_score',
'games_count', 'games_good', 'games_won'
)
list_display_links = ('user',)
list_filter = ['season']
class GameAdmin(admin.ModelAdmin):
actions = [recalculate]
# date_hierarchy = 'event__start'
fields = (
'event',
('player1', 'player1_score', 'player1_placement'),
('player2', 'player2_score', 'player2_placement'),
('player3', 'player3_score', 'player3_placement'),
('player4', 'player4_score', 'player4_placement'),
('player5', 'player5_score', 'player5_placement'),
('player6', 'player6_score', 'player6_placement'),
'comment',
'confirmed'
)
form = forms.GameForm
list_display = ('event', 'season', 'player_names', 'comment', 'confirmed')
readonly_fields = (
'player1_placement', 'player2_placement', 'player3_placement',
'player4_placement', 'player5_placement', 'player6_placement'
)
search_fields = [
'player1__username', 'player2__username', 'player3__username',
'player4__username', 'player5__username', 'player6__username'
]
admin.site.register(models.Game, GameAdmin)
admin.site.register(models.Ranking, RankingAdmin)

View File

@@ -0,0 +1,37 @@
# -*- encoding: utf-8 -*-
__author__ = 'christian'
from django import forms
from django.utils.translation import ugettext as _
from . import models
class GameForm(forms.ModelForm):
error_css_class = 'error'
required_css_class = 'required'
class Meta(object):
fields = [
'player1', 'player1_score',
'player2', 'player2_score',
'player3', 'player3_score',
'player4', 'player4_score',
'player5', 'player5_score',
'player6', 'player6_score',
'comment'
]
model = models.Game
def clean(self):
cleaned_data = super(GameForm, self).clean()
players_in_game = set()
for player_nr in (
'player1', 'player2', 'player3', 'player4', 'player5', 'player6'):
current_player = cleaned_data.get(player_nr)
if current_player and current_player in players_in_game:
msg = _("%s may only participate once." % current_player)
self._errors[player_nr] = self.error_class([msg])
del cleaned_data[player_nr]
players_in_game.add(current_player)
return cleaned_data

View File

@@ -0,0 +1,272 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: kasu.mahjong_ranking\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-01-05 19:23+0100\n"
"PO-Revision-Date: 2014-12-11 22:47+0100\n"
"Last-Translator: Christian Berg <xeniac.at@gmail.com>\n"
"Language-Team: Kasu <verein@kasu.at>\n"
"Language: de\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"
"X-Generator: Poedit 1.6.11\n"
"X-Translated-Using: django-rosetta 0.7.2\n"
#: admin.py:24
msgid "Recalculate"
msgstr "Neuberechnen"
#: forms.py:33
#, python-format
msgid "%s may only participate once."
msgstr "%s darf nur einmal teilnehmen."
#: models.py:20
msgid "Comment"
msgstr "Kommentar"
#: models.py:22
msgid "Player 1"
msgstr "Spieler 1"
#: models.py:24 models.py:30 models.py:36 models.py:42 models.py:48
#: models.py:54 templates/maistar_ranking/ranking_list.html:20
msgid "Score"
msgstr "Punkte"
#: models.py:28
msgid "Player 2"
msgstr "Spieler 2"
#: models.py:34
msgid "Player 3"
msgstr "Spieler 3"
#: models.py:40
msgid "Player 4"
msgstr "Spieler 4"
#: models.py:46
msgid "Player 5"
msgstr "Spieler 5"
#: models.py:52
msgid "Player 6"
msgstr "Spieler 6"
#: models.py:58
msgid "Has been confirmed"
msgstr "Wurde bestätigt"
#: models.py:60
msgid "the game only counts whe it has been confirmed"
msgstr "das Spiel zählt nur wenn es bestätigt wurde"
#: models.py:63 models.py:151
#: templates/maistar_ranking/player_game_list.html:6
#: templates/maistar_ranking/ranking_list.html:4
#: templates/maistar_ranking/ranking_list.html:71
msgid "Season"
msgstr "Saison"
#: models.py:69
msgid "Mai-Star Game with {0} from {1:%Y-%m-%d}"
msgstr "Mai-Star Spiel mit {0} vom {1:%Y-%m-%d}"
#: templates/maistar_ranking/game_form.html:5
#: templates/maistar_ranking/game_form.html:16
#: templates/maistar_ranking/game_list.html:27
#: templates/maistar_ranking/player_game_list.html:46
msgid "Edit Game"
msgstr "Spiel bearbeiten"
#: templates/maistar_ranking/game_form.html:5
#: templates/maistar_ranking/game_form.html:16
#: templates/maistar_ranking/game_list.html:42
msgid "Add Game"
msgstr "Spiel hinzufügen"
#: templates/maistar_ranking/game_form.html:78
msgid "Back"
msgstr "Zurück"
#: templates/maistar_ranking/game_form.html:80
msgid "Save"
msgstr "Speichern"
#: templates/maistar_ranking/game_list.html:4
#: templates/maistar_ranking/player_game_list.html:6
msgid "Mai-Star Games"
msgstr "Mai-Star Spiele"
#: templates/maistar_ranking/game_list.html:7
msgid "Played Mai-Star Games"
msgstr "Gespielte Mai-Star Spiele"
#: templates/maistar_ranking/game_list.html:12
msgid "Game"
msgstr "Spiel"
#: templates/maistar_ranking/game_list.html:15
msgid "Place"
msgstr "Platz"
#: templates/maistar_ranking/game_list.html:19
#: templates/maistar_ranking/player_game_list.html:38
msgid "Points"
msgstr "Punkte"
#: templates/maistar_ranking/game_list.html:24
#: templates/maistar_ranking/hanchan_confirm_delete.html:18
#: templates/maistar_ranking/hanchan_confirm_delete.html:19
#: templates/maistar_ranking/player_game_list.html:43
msgid "Delete"
msgstr "Löschen"
#: templates/maistar_ranking/game_list.html:24
#: templates/maistar_ranking/player_game_list.html:43
msgid "Delete Game"
msgstr "Spiel löschen"
#: templates/maistar_ranking/game_list.html:27
#: templates/maistar_ranking/player_game_list.html:46
msgid "Edit"
msgstr "Bearbeiten"
#: templates/maistar_ranking/game_list.html:32
msgid "No Mai-Star games have been added to this event yet."
msgstr "Für diese Veranstaltung wurden noch keine Mai-Star Spiele erfasst."
#: templates/maistar_ranking/game_list.html:40
#: templates/maistar_ranking/game_list.html:42
msgid "Add"
msgstr "Hinzufügen"
#: templates/maistar_ranking/game_list.html:40
msgid "Edit Event"
msgstr "Veranstaltung bearbeiten"
#: templates/maistar_ranking/hanchan_confirm_delete.html:4
#: templates/maistar_ranking/hanchan_confirm_delete.html:10
msgid "Delete game"
msgstr "Spiel löschen"
#: templates/maistar_ranking/hanchan_confirm_delete.html:14
#: templates/maistar_ranking/hanchan_confirm_delete.html:15
msgid "Cancel"
msgstr "Abbrechen"
#: templates/maistar_ranking/page.html:5
msgid "Archive"
msgstr "Archiv"
#: templates/maistar_ranking/page.html:7
msgid "Add Event"
msgstr "Veranstaltung hinzufügen"
#: templates/maistar_ranking/player_game_list.html:4
msgid "Ladder Score for"
msgstr "Ladder Wertung für"
#: templates/maistar_ranking/player_game_list.html:10
msgid "Mai-Star Games with"
msgstr "Mai-Star Spiele mit"
#: templates/maistar_ranking/player_game_list.html:15
msgid "Date"
msgstr "Datum"
#: templates/maistar_ranking/player_game_list.html:16
msgid "Event"
msgstr "Veranstaltung"
#: templates/maistar_ranking/player_game_list.html:17
msgid "Players"
msgstr "Spieler"
#: templates/maistar_ranking/ranking_list.html:4
msgid "Mai-Star Ranking"
msgstr "Mai-Star Platzierung"
#: templates/maistar_ranking/ranking_list.html:11
#: templates/maistar_ranking/ranking_list.html:19
msgid "Placement"
msgstr "Platzierung"
#: templates/maistar_ranking/ranking_list.html:12
msgid "Avatar"
msgstr "Avatar"
#: templates/maistar_ranking/ranking_list.html:13
msgid "Nickname"
msgstr "Spitzname"
#: templates/maistar_ranking/ranking_list.html:14
msgid "Name"
msgstr "Name"
#: templates/maistar_ranking/ranking_list.html:15
msgid "Average"
msgstr "Durchschnitt"
#: templates/maistar_ranking/ranking_list.html:16
msgid "Games"
msgstr "Spiele"
#: templates/maistar_ranking/ranking_list.html:21
msgid "count"
msgstr "Anzahl"
#: templates/maistar_ranking/ranking_list.html:22
msgid "good"
msgstr "Gut"
#: templates/maistar_ranking/ranking_list.html:23
msgid "won"
msgstr "Gewonnen"
#: templates/maistar_ranking/ranking_list.html:42
msgid ""
"Unfortunately, nobody has it been done in the ranking.\n"
" A player must have 6 games done, to be added to the ranking."
msgstr ""
"Leider hat es noch niemand in die Wertung geschafft. Spieler, die weniger "
"als 6 Spiele innerhalb einer Saison absolviert haben, werden für das "
"Endergebnis nicht gewertet."
#: templates/maistar_ranking/ranking_list.html:52
msgid "Latest Games"
msgstr "Letzten Spiele"
#: templates/maistar_ranking/ranking_list.html:62
msgid "Latest Events"
msgstr "Letzten Veranstaltungen"
#: templates/maistar_ranking/ranking_list.html:69
msgid "Ladder Archive"
msgstr "Archiv"
#~ msgid "Player List"
#~ msgstr "Spieler Liste"
#~ msgid "Full Name"
#~ msgstr "Voller Name"
#~ msgid "Rank"
#~ msgstr "Rang"
#~ msgid "Games Total"
#~ msgstr "Spiele Gesamt"
#~ msgid "Event does not exist"
#~ msgstr "Termin existiert nicht."
#~ msgid "No user found matching the name %s"
#~ msgstr "Kein Benutzer mit dem Namen %s gefunden."

View File

@@ -0,0 +1,60 @@
# -*- encoding: utf-8 -*-
"""
Created on 22.11.2014
@author: christian
"""
from django.db import models
from . import settings
class GameManager(models.Manager):
use_for_related_fields = True
def player_games(self, player, season=None, **kwargs):
queryset = self.filter(
models.Q(player1=player) | models.Q(player2=player) |
models.Q(player3=player) | models.Q(player4=player) |
models.Q(player5=player) | models.Q(player6=player)
)
if season:
queryset = queryset.filter(season=season)
if kwargs:
queryset = queryset.filter(**kwargs)
return queryset
class LadderManager(models.Manager):
use_for_related_fields = True
def calculate_rankings(self, season):
"""
Berechnet die Jahresrankings für die Spieler neu.
@param season: Das Jahr das neu berechnet werden soll
@type season: Integer
"""
rankings = self.filter(season=season)
rankings.update(placement=None)
rankings = rankings.filter(
games_count__gte=settings.MAISTAR_GAMES_FOR_LADDERRANKING) # @IgnorePep8
rankings = rankings.order_by('avg_placement', '-avg_score')
placement = 1
previous_avg_placement = None
previous_avg_score = None
previous_placement = None
for ranking in rankings:
if ranking.avg_placement == previous_avg_placement \
and ranking.avg_score == previous_avg_score:
ranking.placement = previous_placement
else:
ranking.placement = placement
ranking.save(force_update=True)
previous_avg_placement = ranking.avg_placement
previous_avg_score = ranking.avg_score
previous_placement = ranking.placement
placement += 1
def get_seasons(self):
return self.values_list('season', flat=True).order_by(
'season').distinct()

View File

@@ -0,0 +1,221 @@
# -*- encoding: utf-8 -*-
import logging
from django.core.urlresolvers import reverse
from django.db import models
from django.utils.translation import ugettext as _
from events.models import Event
from membership.models import Membership
from . import settings, managers
class Game(models.Model):
"""
Ein kompettes Spiel Mai-Star bestehend aus 6 Spielern
"""
event = models.ForeignKey(Event, related_name='maistargame_set')
comment = models.TextField(_('Comment'), blank=True)
player1 = models.ForeignKey(
settings.AUTH_USER_MODEL, verbose_name=_("Player 1"), related_name='+'
)
player1_score = models.SmallIntegerField(_("Score"))
player1_placement = models.PositiveSmallIntegerField(editable=False)
player2 = models.ForeignKey(
settings.AUTH_USER_MODEL, verbose_name=_("Player 2"), related_name='+'
)
player2_score = models.SmallIntegerField(_("Score"))
player2_placement = models.PositiveSmallIntegerField(editable=False)
player3 = models.ForeignKey(
settings.AUTH_USER_MODEL, verbose_name=_("Player 3"), related_name='+'
)
player3_score = models.SmallIntegerField(_("Score"))
player3_placement = models.PositiveSmallIntegerField(editable=False)
player4 = models.ForeignKey(
settings.AUTH_USER_MODEL, verbose_name=_("Player 4"), related_name='+'
)
player4_score = models.SmallIntegerField(_("Score"))
player4_placement = models.PositiveSmallIntegerField(editable=False)
player5 = models.ForeignKey(
settings.AUTH_USER_MODEL, verbose_name=_("Player 5"), related_name='+'
)
player5_score = models.SmallIntegerField(_("Score"))
player5_placement = models.PositiveSmallIntegerField(editable=False)
player6 = models.ForeignKey(
settings.AUTH_USER_MODEL, verbose_name=_("Player 6"), related_name='+'
)
player6_score = models.SmallIntegerField(_("Score"))
player6_placement = models.PositiveSmallIntegerField(editable=False)
confirmed = models.BooleanField(
_('Has been confirmed'),
default=True,
help_text=_('the game only counts whe it has been confirmed')
)
player_names = models.CharField(max_length=255, editable=False)
season = models.PositiveSmallIntegerField(_('Season'), editable=False,
db_index=True)
objects = managers.GameManager()
def __str__(self):
return _("Mai-Star Game with {0} from {1:%Y-%m-%d}").format(
self.player_names, self.event.start
)
def get_absolute_url(self):
"""
URL zur Hanchanliste des Events wo diese Hanchan gelistet wurde.
"""
url = reverse('maistar-game-list',
kwargs={'event': self.event.pk})
return u'%(url)s#%(pk)d' % {'url': url, 'pk': self.pk}
@property
def player_list(self):
try:
return self._player_list
except AttributeError:
self._player_list = list()
for nr in range(1, 7):
self._player_list.append({
'user': getattr(self, 'player%d' % nr),
'membership': Membership.objects.get(
user=getattr(self, 'player%d' % nr)
),
'score': getattr(self, 'player%d_score' % nr),
'placement': getattr(self, 'player%d_placement' % nr),
})
return self._player_list
def save(self, force_insert=False, force_update=False, using=None,
update_fields=None):
u"""
Bestimmt die Platzierung eines jeden Spielers noch vor dem speichern.
Außerdem wird eine Kommasperierte Liste der Spiele mitgespeichert.
"""
logging.debug("Berechne die Platzierungen neu...")
game_date = self.event.start.date()
player_tuples = [
(self.player1.id, self.player1.username, self.player1_score),
(self.player2.id, self.player2.username, self.player2_score),
(self.player3.id, self.player3.username, self.player3_score),
(self.player4.id, self.player4.username, self.player4_score),
(self.player5.id, self.player5.username, self.player5_score),
(self.player6.id, self.player6.username, self.player6_score),
]
season_start = settings.MAISTAR_SEASON_START.replace(
year=game_date.year)
# sort player by Score:
player_tuples = sorted(player_tuples, key=lambda player: player[2],
reverse=True)
logging.debug(player_tuples)
other_player_ranking = 1
other_player_score = 0
player_names = []
ranking = 1
player_nr = 1
for player_id, player_name, player_score in player_tuples:
if player_score == other_player_score:
player_ranking = other_player_ranking
else:
player_ranking = ranking
setattr(self, "player%d_id" % player_nr, player_id)
setattr(self, "player%d_score" % player_nr, player_score)
setattr(self, "player%d_placement" % player_nr, player_ranking)
other_player_ranking = player_ranking
other_player_score = player_score
player_names.append(player_name)
player_nr += 1
ranking += 1
self.player_names = ', '.join(player_names)
if game_date >= season_start:
self.season = season_start.year
else:
self.season = season_start.year - 1
super(Game, self).save(force_insert=force_insert,
force_update=force_update, using=using,
update_fields=update_fields)
class Ranking(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
season = models.PositiveSmallIntegerField(_("Season"))
placement = models.PositiveIntegerField(blank=True, null=True)
avg_placement = models.PositiveSmallIntegerField(blank=True, null=True)
avg_score = models.SmallIntegerField(blank=True, null=True)
games_count = models.PositiveSmallIntegerField(default=0)
games_good = models.PositiveSmallIntegerField(default=0)
games_won = models.PositiveSmallIntegerField(default=0)
objects = managers.LadderManager()
class Meta(object):
ordering = ('-season', 'placement', 'avg_placement', '-avg_score',)
def __str__(self):
return "Mai-Star Ranking: %s, Season: %d" % (self.user, self.season)
def get_absolute_url(self):
return reverse('maistar-player-games', kwargs={
'username': self.user.username,
'season': self.season
})
def recalculate(self):
logging.info(
u'Recalculate Mai-Star Ranking for Player %s in Season %s',
self.user, self.season
)
self.placement = None
self.avg_placement = None
self.avg_score = None
self.games_count = 0
self.games_good = 0
self.games_won = 0
player_score = 0
player_placement = 0
for game in Game.objects.player_games(self.user, self.season):
placement = 0
score = 0
for player in ('player1', 'player2', 'player3', 'player4',
'player5', 'player6'):
if getattr(game, player) == self.user:
placement = getattr(game, "%s_placement" % player)
score = getattr(game, "%s_score" % player)
player_placement += placement
player_score += score
self.games_count += 1
self.games_good += 1 if placement <= 3 else 0
self.games_won += 1 if placement == 1 else 0
if self.games_count > 0:
self.avg_placement = round(player_placement / self.games_count)
self.avg_score = round(player_score / self.games_count)
self.save()
def update_maistar_ranking(sender, instance, **kwargs):
for player in instance.player_list:
ranking, created = Ranking.objects.get_or_create(
user=player['user'],
season=instance.season
)
if created:
logging.debug('Created ranking for %s in Season %d',
player['user'].username, instance.season)
else:
logging.debug('Updating ranking for %s in Season %d',
player['user'].username, instance.season)
ranking.recalculate()
Ranking.objects.calculate_rankings(instance.season)
models.signals.post_delete.connect(update_maistar_ranking, sender=Game)
models.signals.post_save.connect(update_maistar_ranking, sender=Game)

View File

@@ -0,0 +1,24 @@
"""
Global Settings for the Maistar Ranking System
Created on 22.11.2014
@author: christian
"""
from datetime import date
from django.conf import settings
AUTH_USER_MODEL = settings.AUTH_USER_MODEL
MAISTAR_GAMES_FOR_LADDERRANKING = getattr(
settings, 'MAISTAR_GAMES_FOR_LADDERRANKING', 6
)
MAISTAR_SEASON_START = getattr(
settings, 'MAISTAR_SEASON_START', date(year=1, month=8, day=1)
)

View File

@@ -0,0 +1,87 @@
{% extends "events/event_detail.html" %}
{% load i18n comments fieldset_extras %}
{% block title %}
{% if game.id %}{% trans "Edit Game" %}{% else %}{% trans "Add Game" %}{% endif %}
{% endblock %}
{% block maincontent %}
{% for error in form.errors %}<p class="error">{{error}}</p>{% endfor %}
{% for error in form.non_field_errors %}<p class="error">{{error}}</p>{% endfor %}
<form class="grid_12" method="post">
{% csrf_token %}
<fieldset>
<legend>{% if game.id %}{% trans "Edit Game" %}{% else %} {% trans "Add Game" %}{% endif %}</legend>
<p>
<label for="id_player1" class="field_name {{ form.player1.css_classes }}">{{ form.player1.label }}</label>
{{ form.player1 }}
<label for="id_player1_score" class="{{ form.player1_score.css_classes }}">{{ form.player1_score.label }}</label>
{{ form.player1_score}}
</p>
{% if form.player1.errors %}{{ form.player1.errors }}{% endif %}
{% if form.player1_score.errors %}{{ form.player1_score.errors }}{% endif %}
<p>
<label for="id_player2" class="field_name {{ form.player2.css_classes }}">{{ form.player2.label }}</label>
{{ form.player2 }}
<label for="id_player2_score" class="{{ form.player2_score.css_classes }}">{{ form.player2_score.label }}</label>
{{ form.player2_score}}
</p>
{% if form.player2.errors %}{{ form.player2.errors }}{% endif %}
{% if form.player2_score.errors %}{{ form.player2_score.errors }}{% endif %}
<p>
<label for="id_player3" class="field_name {{ form.player3.css_classes }}">{{ form.player3.label }}</label>
{{ form.player3 }}
<label for="id_player3_score" class="{{ form.player3_score.css_classes }}">{{ form.player3_score.label }}</label>
{{ form.player3_score}}
</p>
{% if form.player3.errors %}{{ form.player3.errors }}{% endif %}
{% if form.player3_score.errors %}{{ form.player3_score.errors }}{% endif %}
<p>
<label for="id_player4" class="field_name {{ form.player4.css_classes }}">{{ form.player4.label }}</label>
{{ form.player4 }}
<label for="id_player4_score" class="{{ form.player4_score.css_classes }}">{{ form.player4_score.label }}</label>
{{ form.player4_score}}
</p>
{% if form.player4.errors %}{{ form.player4.errors }}{% endif %}
{% if form.player4_score.errors %}{{ form.player4_score.errors }}{% endif %}
<p>
<label for="id_player5" class="field_name {{ form.player5.css_classes }}">{{ form.player5.label }}</label>
{{ form.player5 }}
<label for="id_player5_score" class="{{ form.player5_score.css_classes }}">{{ form.player5_score.label }}</label>
{{ form.player5_score}}
</p>
{% if form.player5.errors %}{{ form.player5.errors }}{% endif %}
{% if form.player5_score.errors %}{{ form.player5_score.errors }}{% endif %}
<p>
<label for="id_player6" class="field_name {{ form.player6.css_classes }}">{{ form.player6.label }}</label>
{{ form.player6 }}
<label for="id_player6_score" class="{{ form.player6_score.css_classes }}">{{ form.player6_score.label }}</label>
{{ form.player6_score}}
</p>
{% if form.player6.errors %}{{ form.player6.errors }}{% endif %}
{% if form.player6_score.errors %}{{ form.player6_score.errors }}{% endif %}
<p>
<label for="id_comment" class="field_name {{ form.comment.css_classes }}">{{ form.comment.label }}</label>
{{ form.comment }}
</p>
<p class="buttonbar">
<a href="{{game.get_absolute_url}}" class="button"><img
src="{{STATIC_URL}}icons/arrow_undo.png"
alt="{% trans 'Back' %}"/> {% trans 'Back' %}</a>
<button type="submit"><img src="{{STATIC_URL}}icons/table_save.png"
alt="{% trans 'Save' %}"/> {% trans 'Save' %}
</button>
</p>
</fieldset>
</form>
{% endblock %}
{% block buttonbar %}{% endblock %}

View File

@@ -0,0 +1,44 @@
{% extends "events/event_detail.html" %}
{% load i18n humanize %}
{% block title %}{% trans 'Mai-Star Games' %} - {{ event.name }}{% endblock %}
{% block maincontent %}
<h2 class="grid_12">{% trans 'Played Mai-Star Games' %}</h2>
<p>&nbsp;</p>
{% for game in game_list %}
<article id="{{ game.pk }}">
<h3 class="grid_12">{{ forloop.counter|ordinal }} {% trans 'Game' %}</h3>
{% for player in game.player_list %}
<div class="grid_2 center">
<h4>{{ player.placement|ordinal }} {% trans 'Place' %}</h4>
<a href="{% url 'maistar-player-games' username=player.user.username season=game.season %}"><img
src="{% if player.membership.thumbnail %}{{player.membership.thumbnail.url}}{% else %}{{STATIC_URL}}img/unknown_thumbnail.png{% endif %}" alt=""/></a>
<p><a href="{% url 'maistar-player-games' username=player.user.username season=game.season %}">{{player.user.username}}</a><br/>
{{player.score}} {% trans 'Points' %}</p>
</div>
{% endfor %}
<div class="grid_12 buttonbar">
{% if perms.maistar_ranking.delete_dame %}
<a class="button" href="{% url 'maistar-delete-game' game.pk %}"><img src="{{STATIC_URL}}icons/table_delete.png" alt="{% trans 'Delete' %}"/> {% trans 'Delete Game' %}</a>
{% endif %}
{% if perms.maistar_ranking.change_game %}
<a class="button" href="{% url 'maistar-edit-game' game.pk %}"><img src="{{STATIC_URL}}icons/table_edit.png" alt="{% trans 'Edit' %}" /> {% trans 'Edit Game' %}</a>
{% endif %}
</div>
</article>
{% empty %}
<p class="grid_12">{% trans 'No Mai-Star games have been added to this event yet.'%}</p>
{% endfor %}
<p>&nbsp;</p>
{% endblock %}
{% block buttonbar %}
{% if perms.maistar_ranking.add_game %}
<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 'maistar-add-game' event.id %}"><img src="{{STATIC_URL}}icons/add.png"
alt="{% trans 'Add' %}"/> {% trans 'Add Game' %}</a>
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,26 @@
{% extends "base.html" %}
{% load i18n comments %}
{% block meta_title %}{% trans 'Delete game' %}{% endblock %}
{% block content %}
<form method="post">
{% csrf_token %}
<fieldset>
<legend>{% trans "Delete game" %}</legend>
{% include 'form.html' %}
<p class="buttonbar">
<button type="button" onclick="window.history.back()">
<img src="{{STATIC_URL}}icons/cancel.png" alt="{% trans 'Cancel' %}"/>
{% trans 'Cancel' %}
</button>
<button type="submit">
<img src="{{STATIC_URL}}icons/table_delete.png" alt="{% trans 'Delete' %}"/>
{% trans 'Delete' %}
</button>
</p>
</fieldset>
</form>
{% endblock %}
{% block buttonbar %}{% endblock %}

View File

@@ -0,0 +1,9 @@
{% extends "base.html" %}
{% load i18n %}
{% block additional_nav_elements %}
<a href="{% url 'season_ranking-archive' %}" class="{% if is_archive %}active{% endif %}">{% trans 'Archive' %}</a>
{% if perms.events.add_event %}
<a href="{% url 'event-form' %}" class="{% ifequal request.path '/events/add/' %}active{% endifequal %}">{% trans 'Add Event' %}</a>
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,55 @@
{% extends "membership/membership_detail.html" %}
{% load i18n humanize %}
{% block title %} {% trans 'Ladder Score for' %} {{membership.user.username}} {% endblock %}
{% block teaser %} <h2>{% trans 'Mai-Star Games' %}: {{membership.user.username}} <br/> {% trans 'Season' %} {{season}}</h2> {% endblock %}
{% block score_list %}
<div class="grid_12">
<h2>{% trans 'Mai-Star Games with' %} {{ membership.user.username }} - {{season}}</h2>
<table>
<thead>
<tr>
<th rowspan="2">{% trans 'Date' %}</th>
<th rowspan="2">{% trans 'Event' %}</th>
<th colspan="6">{% trans 'Players' %}</th>
<th rowspan="2"></th>
</tr>
<tr>
<th>{{ '1'|ordinal }}</th>
<th>{{ '2'|ordinal }}</th>
<th>{{ '3'|ordinal }}</th>
<th>{{ '4'|ordinal }}</th>
<th>{{ '5'|ordinal }}</th>
<th>{{ '6'|ordinal }}</th>
</tr>
</thead>
<tbody>
{% for game in game_list %}
<tr>
<td class="center">{{ game.event.start|date:'SHORT_DATE_FORMAT' }}</td>
<td><a href="{{ game.get_absolute_url }}">{{ game.event.name }}</a></td>
</td>
{% for player in game.player_list %}
<td class="center">
<a href="{% url 'maistar-player-games' username=player.user.username season=season %}">{{ player.user.username }}</a>
<br/>{{player.score}} {% trans 'Points' %}
</td>
{% endfor %}
<td>
{% if perms.maistar_ranking.delete_game %}
<a href="{% url 'maistar-delete-game' game.pk %}"><img src="{{STATIC_URL}}icons/table_delete.png" alt="{% trans 'Delete' %}" title="{% trans 'Delete Game' %}"/></a>
{% endif %}
{% if perms.maistar_ranking.change_game %}
<a href="{% url 'maistar-edit-game' game.pk %}"><img src="{{STATIC_URL}}icons/table_edit.png" alt="{% trans 'Edit' %}" title="{% trans 'Edit Game' %}"/></a>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}

View File

@@ -0,0 +1,79 @@
{% extends "base.html" %}
{% load i18n comments humanize %}
{% block teaser %} <h2>{% trans 'Mai-Star Ranking' %} - {% trans 'Season' %} {{season}}</h2> {% endblock %}
{% block maincontent %}
<main class="grid_12">
<table>
<thead>
<tr>
<th rowspan="2">{% trans "Placement" %}</th>
<th rowspan="2">{% trans "Avatar" %}</th>
<th rowspan="2">{% trans "Nickname" %}</th>
<th rowspan="2">{% trans "Name" %}</th>
<th colspan="2">{% trans 'Average' %}</th>
<th colspan="3">{% trans 'Games' %}</th>
</tr>
<tr>
<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 ranking_list %}
{% with player.user.get_profile as profile %}
<tr>
<td class="center">{{ player.placement|ordinal }}</td>
<td><a href="{{ player.get_absolute_url }}"><img src="{% if profile.thumbnail %}{{profile.thumbnail.url}}{% else %}{{STATIC_URL}}img/unknown_thumbnail.png{% endif %}" class="avatar" alt="{{ player.user }}"/></a></td>
<td><a href="{{ player.get_absolute_url }}">{{player.user}}</a></td>
<td>{% if user.is_authenticated %}{{profile.last_name}} {{profile.first_name}}{% else %} ---{% endif %}</td>
<td class="right">{{player.avg_placement|floatformat:0 }}</td>
<td class="right">{{player.avg_score|intcomma }}</td>
<td class="right">{{player.games_count}}</td>
<td class="right">{{player.games_good}}</td>
<td class="right">{{player.games_won}}</td>
</tr>
{% endwith %}
{% empty %}
<tr>
<td colspan="8">{% blocktrans %}Unfortunately, nobody has it been done in the ranking.
A player must have 6 games done, to be added to the ranking.{% endblocktrans %}
</td>
</tr>
{% endfor %}
</table>
</main>
{% endblock %}
{% block redbox %}
<h2>{% trans 'Latest Games' %}</h2>
<ul class="list">
{% for game in latest_games %}
<li class="hanchan">
<a href="{% url 'maistar-game-list' game.event.pk %}">{{game.event.start|date:'SHORT_DATE_FORMAT'}}:</a>
<small>{{game.player_names}}</small>
</li>
{% endfor %}
</ul>
<h3>{% trans 'Latest Events' %}</h3>
<ul class="list">
{% for event in latest_events %}
<li class="event"><a href="{% url 'maistar-game-list' event.pk %}">{{event.name}}</a></li>
{% endfor %}
</ul>
<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="{% url 'maistar-ranking' season=season_link %}" {% ifequal season season_link %}selected="selected"{% endifequal %}>{{ season_link }}</option>
{% endfor %}
</select>
</form>
{% endblock %}

View File

@@ -0,0 +1,32 @@
# -*- encoding: utf-8 -*-
"""
Created on 03.10.2011
@author: christian
"""
from django.conf.urls import * # @UnusedWildImport
from django.views.generic import RedirectView
from .views import DeleteGame, ListGames, ListPlayerGames, \
ListRankings, GameForm
urlpatterns = patterns(
'maistar_ranking.views',
url('^$', RedirectView.as_view(pattern_name='maistar-ranking', permanent=True)),
url(r'ranking/$', ListRankings.as_view(), name="maistar-ranking"),
url(r'ranking/(?P<season>[\d]+)/$', ListRankings.as_view(),
name="maistar-ranking"), # @IgnorePep8
url(r'event/(?P<event>[\d]+)/$', ListGames.as_view(),
name="maistar-game-list"), # @IgnorePep8
url(r'event/(?P<event>[\d]+)/add/$', GameForm.as_view(),
name="maistar-add-game"), # @IgnorePep8
url(r'game/(?P<game>[\d]+)/edit/$', GameForm.as_view(),
name="maistar-edit-game"), # @IgnorePep8
url(r'game/(?P<game>[\d]+)/delete/$', DeleteGame.as_view(),
name="maistar-delete-game"), # @IgnorePep8
url(r'player/(?P<username>[\-\.\d\w]+)/$', ListPlayerGames.as_view(),
name="maistar-player-games"), # @IgnorePep8
url(r'player/(?P<username>[\-\.\d\w]+)/(?P<season>[\d]+)/$',
ListPlayerGames.as_view(), name="maistar-player-games"), # @IgnorePep8
)

View File

@@ -0,0 +1,121 @@
# -*- encoding: utf-8 -*-
from datetime import date
from django.contrib import auth
from django.core.urlresolvers import reverse
from django.shortcuts import get_object_or_404
from django.utils.translation import gettext as _
from django.views import generic
from events.models import Event
from events.views import EventDetailMixin
from membership.models import Membership
from utils.mixins import LoginRequiredMixin, PermissionRequiredMixin
from mahjong_ranking.views import PlayerScore
from . import forms, models
class GameForm(EventDetailMixin, PermissionRequiredMixin, generic.UpdateView):
model = models.Game
permission_required = 'maistar_ranking.add_game'
form_class = forms.GameForm
def get_object(self, queryset=None):
if 'game' in self.kwargs:
game = get_object_or_404(models.Game, pk=self.kwargs['game'])
elif 'event' in self.kwargs:
self.event = get_object_or_404(Event, pk=self.kwargs['event'])
game = models.Game(event=self.event)
return game
class DeleteGame(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.
"""
model = models.Game
permission_required = 'maistar_ranking.delete_game'
pk_url_kwarg = 'hanchan'
def get_success_url(self):
return reverse(
'maistar_ranking-game-list',
kwargs={'event': self.object.event.pk}
)
class UpdateGame(EventDetailMixin, PermissionRequiredMixin, generic.UpdateView):
"""
Ein Formular um eine neues Spiel anzulegen, bzw. eine bestehendes zu
bearbeiten.
"""
model = models.Game
permission_required = 'maistar_ranking.update_game'
def get_object(self, queryset=None): # @UnusedVariable
game = models.Game.objects.get(id=self.kwargs['game'])
self.event = game.event
return game
def get_context_data(self, **kwargs):
context = generic.UpdateView.get_context_data(self, **kwargs)
context['event'] = self.event
return context
class ListGames(EventDetailMixin, generic.ListView):
"""
Auflistung aller Spiele welche während einer Veranstaltung gespielt wurden.
"""
model = models.Game
def get_queryset(self):
self.event = get_object_or_404(models.Event, pk=self.kwargs['event'])
return models.Game.objects.filter(event=self.event).select_related()
class ListPlayerGames(PlayerScore):
template_name = 'maistar_ranking/player_game_list.html'
paginate_by = 25
context_object_name = 'game_list'
def get_context_data(self, **kwargs):
context = super(ListPlayerGames, self).get_context_data()
context['membership'] = Membership.objects.get(user=self.user)
context['season_list'] = models.Ranking.objects.filter(user=self.user).values_list('season', flat=True)
context['season'] = self.season
return context
def get_queryset(self, **kwargs):
self.user = get_object_or_404(auth.get_user_model(),
username=self.kwargs.get('username'))
self.season = self.kwargs.get('season', date.today().year)
return models.Game.objects.player_games(player=self.user,
season=self.season)
class ListRankings(generic.ListView):
model = models.Ranking
paginate_by = 50
season = None
is_archive = False
def get_queryset(self):
self.season = int(self.kwargs.get('season', date.today().year))
queryset = models.Ranking.objects.filter(
season=self.season,
placement__isnull=False
)
queryset = queryset.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_list'] = models.Ranking.objects.get_seasons()
context['latest_games'] = models.Game.objects.filter(confirmed=True)[:3]
context['latest_events'] = Event.objects.archive()[:3]
return context