Added a setting where the exported excel files should be stored.
Added a option to send the exported excel as mail attachment.
This commit is contained in:
@@ -273,6 +273,7 @@ KYU_RANKS = (
|
|||||||
|
|
||||||
DAN_ALLOW_DROP_DOWN = True
|
DAN_ALLOW_DROP_DOWN = True
|
||||||
MIN_HANCHANS_FOR_LADDER = 5
|
MIN_HANCHANS_FOR_LADDER = 5
|
||||||
|
RANKING_EXPORT_PATH = path.join(PROJECT_PATH, 'backup', 'mahjong_ranking')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from .local_settings import * # Ignore PyLintBear (W0401, W0614)
|
from .local_settings import * # Ignore PyLintBear (W0401, W0614)
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
"""Export Mahjong Rankings as excel files."""
|
"""Export Mahjong Rankings as excel files."""
|
||||||
|
|
||||||
import openpyxl
|
import os
|
||||||
from django.core.management.base import BaseCommand
|
|
||||||
from django.utils.dateparse import parse_date
|
|
||||||
from openpyxl.styles import Border
|
|
||||||
from datetime import date, time, datetime
|
from datetime import date, time, datetime
|
||||||
|
|
||||||
|
import openpyxl
|
||||||
|
from django.conf import settings
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
from django.utils.dateparse import parse_date
|
||||||
|
from django.core.mail import EmailMessage
|
||||||
|
|
||||||
from mahjong_ranking.models import SeasonRanking, KyuDanRanking
|
from mahjong_ranking.models import SeasonRanking, KyuDanRanking
|
||||||
|
|
||||||
THIN_BORDER = openpyxl.styles.Side(style='thin', color="d3d7cf")
|
THIN_BORDER = openpyxl.styles.Side(style='thin', color="d3d7cf")
|
||||||
@@ -38,7 +42,19 @@ DATE_STYLE.font = DEFAULT_STYLE.font
|
|||||||
DATE_STYLE.border = DEFAULT_STYLE.border
|
DATE_STYLE.border = DEFAULT_STYLE.border
|
||||||
DATE_STYLE.number_format = 'dd.mm.yyyy'
|
DATE_STYLE.number_format = 'dd.mm.yyyy'
|
||||||
|
|
||||||
|
MAIL_BODY = """
|
||||||
|
Hallo! Ich bin's dein Server.
|
||||||
|
|
||||||
|
Ich habe gerade die Mahjong Rankings als Excel exportiert und dachte mir das
|
||||||
|
ich sie dir am besten gleich schicke.
|
||||||
|
|
||||||
|
Bitte versuche nicht auf diese E-Mail zu antworten.
|
||||||
|
Ich bin nur ein dummes Programm.
|
||||||
|
|
||||||
|
mit lieben Grüßen
|
||||||
|
|
||||||
|
Der Kasu Server
|
||||||
|
"""
|
||||||
def geneate_excel():
|
def geneate_excel():
|
||||||
"""Generate an excel .xlsx spreadsheet from json data of the kyu/dan
|
"""Generate an excel .xlsx spreadsheet from json data of the kyu/dan
|
||||||
rankings.
|
rankings.
|
||||||
@@ -108,7 +124,7 @@ def export_season_rankings(workbook, until):
|
|||||||
'style': 'content',
|
'style': 'content',
|
||||||
'width': 25},
|
'width': 25},
|
||||||
{'col': 'C', 'title': '⌀ Platz', 'attr': 'avg_placement',
|
{'col': 'C', 'title': '⌀ Platz', 'attr': 'avg_placement',
|
||||||
'style': 'int', 'width': 8},
|
'style': 'float', 'width': 8},
|
||||||
{'col': 'D', 'title': '⌀ Punkte', 'attr': 'avg_score',
|
{'col': 'D', 'title': '⌀ Punkte', 'attr': 'avg_score',
|
||||||
'style': 'float', 'width': 12},
|
'style': 'float', 'width': 12},
|
||||||
{'col': 'E', 'title': 'Hanchans', 'attr': 'hanchan_count',
|
{'col': 'E', 'title': 'Hanchans', 'attr': 'hanchan_count',
|
||||||
@@ -156,17 +172,43 @@ def export_kyu_dan_rankings(workbook, until):
|
|||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
"""Exports the SeasonRankings"""
|
"""Exports the SeasonRankings"""
|
||||||
|
filename = str()
|
||||||
|
until = datetime
|
||||||
|
|
||||||
def add_arguments(self, parser):
|
def add_arguments(self, parser):
|
||||||
parser.add_argument('--until', nargs='?', type=parse_date)
|
parser.add_argument(
|
||||||
|
'--until', nargs='?', type=parse_date,
|
||||||
|
default=date.today(), metavar='YYYY-MM-DD',
|
||||||
|
help='Calculate and export rankings until the given date.')
|
||||||
|
parser.add_argument(
|
||||||
|
'--mail', nargs='*', type=str, metavar='user@example.com',
|
||||||
|
help='Send the spreadsheet via eMail to the given recipient.')
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
"""Exports the current ladder ranking in a spreadsheet.
|
"""Exports the current ladder ranking in a spreadsheet.
|
||||||
This is useful as a backup in form of a hardcopy."""
|
This is useful as a backup in form of a hardcopy."""
|
||||||
until = timezone.make_aware(
|
self.until = timezone.make_aware(datetime.combine(
|
||||||
datetime.combine(options['until'] or date.today(),
|
options['until'], time(23, 59, 59)
|
||||||
time(23, 59, 59)))
|
))
|
||||||
|
|
||||||
|
self.filename = os.path.join(
|
||||||
|
settings.RANKING_EXPORT_PATH,
|
||||||
|
'mahjong_rankings_{:%Y-%m-%d}.xlsx'.format(self.until)
|
||||||
|
)
|
||||||
workbook = geneate_excel()
|
workbook = geneate_excel()
|
||||||
export_season_rankings(workbook, until=until)
|
export_season_rankings(workbook, until=self.until)
|
||||||
export_kyu_dan_rankings(workbook, until=until)
|
export_kyu_dan_rankings(workbook, until=self.until)
|
||||||
workbook.save('mahjong_rankings_{:%Y-%m-%d}.xlsx'.format(until))
|
os.makedirs(settings.RANKING_EXPORT_PATH, exist_ok=True)
|
||||||
|
workbook.save(self.filename)
|
||||||
|
if options['mail']:
|
||||||
|
self.send_mail(options['mail'])
|
||||||
|
|
||||||
|
def send_mail(self, recipients):
|
||||||
|
mail = EmailMessage(
|
||||||
|
subject='Mahjong Rankings vom {:%d.%m.%Y}'.format(self.until),
|
||||||
|
body=MAIL_BODY,
|
||||||
|
from_email=settings.DEFAULT_FROM_EMAIL,
|
||||||
|
to=recipients)
|
||||||
|
mail.attach_file(self.filename)
|
||||||
|
mail.send()
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,9 @@
|
|||||||
# werden dürfen.
|
# werden dürfen.
|
||||||
|
|
||||||
from __future__ import division
|
from __future__ import division
|
||||||
|
|
||||||
from datetime import datetime, time
|
from datetime import datetime, time
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
@@ -463,8 +465,12 @@ class KyuDanRanking(models.Model):
|
|||||||
datetime.combine(self.legacy_date, time(0, 0, 0)))
|
datetime.combine(self.legacy_date, time(0, 0, 0)))
|
||||||
else:
|
else:
|
||||||
since = None
|
since = None
|
||||||
else:
|
elif self.last_hanchan_date:
|
||||||
since = self.last_hanchan_date or self.legacy_date
|
since = self.last_hanchan_date
|
||||||
|
elif self.legacy_date:
|
||||||
|
since = timezone.make_aware(
|
||||||
|
datetime.combine(self.legacy_date, time(0, 0, 0))
|
||||||
|
)
|
||||||
LOGGER.info(
|
LOGGER.info(
|
||||||
"recalculating Kyu/Dan points for %(user)s since %(since)s...",
|
"recalculating Kyu/Dan points for %(user)s since %(since)s...",
|
||||||
{'user': self.user, 'since': str(since)}
|
{'user': self.user, 'since': str(since)}
|
||||||
@@ -474,13 +480,11 @@ class KyuDanRanking(models.Model):
|
|||||||
if until:
|
if until:
|
||||||
valid_hanchans = valid_hanchans.filter(start__lte=until)
|
valid_hanchans = valid_hanchans.filter(start__lte=until)
|
||||||
|
|
||||||
""" TODO: Hanchan Punkte nur neu berechnen wenn sie nach hachan_start
|
|
||||||
lagen. Es müssen aber alle durch die Schleife rennen, damit die Punkte
|
|
||||||
richtig gezählt werden."""
|
|
||||||
self.hanchan_count += valid_hanchans.count()
|
self.hanchan_count += valid_hanchans.count()
|
||||||
for hanchan in valid_hanchans:
|
for hanchan in valid_hanchans:
|
||||||
hanchan.get_playerdata(self.user)
|
hanchan.get_playerdata(self.user)
|
||||||
if since and since < hanchan.start:
|
if since and hanchan.start < since:
|
||||||
|
print(hanchan, "<", since, "no recalc")
|
||||||
self.dan_points += hanchan.dan_points or 0
|
self.dan_points += hanchan.dan_points or 0
|
||||||
self.kyu_points += hanchan.kyu_points or 0
|
self.kyu_points += hanchan.kyu_points or 0
|
||||||
self.update_rank()
|
self.update_rank()
|
||||||
@@ -495,19 +499,19 @@ class KyuDanRanking(models.Model):
|
|||||||
self.update_rank()
|
self.update_rank()
|
||||||
hanchan.update_playerdata(self.user)
|
hanchan.update_playerdata(self.user)
|
||||||
hanchan.save(recalculate=False)
|
hanchan.save(recalculate=False)
|
||||||
self.won_hanchans += 1 if hanchan.placement == 1 else 0
|
self.won_hanchans += 1 if hanchan.placement == 1 else 0
|
||||||
self.good_hanchans += 1 if hanchan.placement == 2 else 0
|
self.good_hanchans += 1 if hanchan.placement == 2 else 0
|
||||||
self.last_hanchan_date = hanchan.start
|
self.last_hanchan_date = hanchan.start
|
||||||
LOGGER.debug(
|
LOGGER.debug(
|
||||||
'id: %(id)d, start: %(start)s, placement: %(placement)d, '
|
'id: %(id)d, start: %(start)s, placement: %(placement)d, '
|
||||||
'score: %(score)d, kyu points: %(kyu_points)d, dan points: '
|
'score: %(score)d, kyu points: %(kyu_points)d, dan points: '
|
||||||
'%(dan_points)d, bonus points: %(bonus_points)d',
|
'%(dan_points)d, bonus points: %(bonus_points)d',
|
||||||
{'id': hanchan.pk, 'start': hanchan.start,
|
{'id': hanchan.pk, 'start': hanchan.start,
|
||||||
'placement': hanchan.placement, 'score': hanchan.game_score,
|
'placement': hanchan.placement, 'score': hanchan.game_score,
|
||||||
'kyu_points': hanchan.kyu_points or 0,
|
'kyu_points': hanchan.kyu_points or 0,
|
||||||
'dan_points': hanchan.dan_points or 0,
|
'dan_points': hanchan.dan_points or 0,
|
||||||
'bonus_points': hanchan.bonus_points or 0}
|
'bonus_points': hanchan.bonus_points or 0}
|
||||||
)
|
)
|
||||||
self.save(force_update=True)
|
self.save(force_update=True)
|
||||||
|
|
||||||
|
|
||||||
@@ -564,6 +568,7 @@ class KyuDanRanking(models.Model):
|
|||||||
hanchan.kyu_points -= (self.kyu_points + hanchan.kyu_points)
|
hanchan.kyu_points -= (self.kyu_points + hanchan.kyu_points)
|
||||||
self.kyu_points += hanchan.kyu_points
|
self.kyu_points += hanchan.kyu_points
|
||||||
|
|
||||||
|
|
||||||
# TODO: Merkwürdige Methode die zwar funktioniert aber nicht sehr
|
# TODO: Merkwürdige Methode die zwar funktioniert aber nicht sehr
|
||||||
# aussagekräfig ist. Überarbeiten?
|
# aussagekräfig ist. Überarbeiten?
|
||||||
def update_rank(self):
|
def update_rank(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user