Initial commit

This commit is contained in:
2016-01-20 16:56:31 +01:00
commit 60d55652c0
26 changed files with 1668 additions and 0 deletions

0
tipp/__init__.py Normal file
View File

28
tipp/admin.py Normal file
View File

@@ -0,0 +1,28 @@
from tipp.models import Team, Match, Tipp, Score, Mandant, RelUserMandant, Competition, Post, UserProfile
from django.contrib import admin
class PostAdmin(admin.ModelAdmin):
# fields display on change list
list_display = ['title']
# fields to filter the change list with
list_filter = ['published', 'created']
# fields to search in change list
search_fields = ['title', 'content']
# enable the date drill down on change list
date_hierarchy = 'created'
# enable the save buttons on top on change form
save_on_top = True
# prepopulate the slug from the title - big timesaver!
prepopulated_fields = {"slug": ("title",)}
admin.site.register(Team)
admin.site.register(Match)
admin.site.register(Tipp)
admin.site.register(Mandant)
admin.site.register(Score)
admin.site.register(RelUserMandant)
admin.site.register(Competition)
admin.site.register(Post, PostAdmin)

40
tipp/forms.py Normal file
View File

@@ -0,0 +1,40 @@
from django import forms
from django.forms import ModelForm
from django.contrib.auth.models import User
from django.core.files.images import get_image_dimensions
from tipp.models import Match, Competition, Post, UserProfile
class NumberInput(forms.TextInput):
input_type = 'number'
class TippForm(forms.Form):
tippTeam1 = forms.IntegerField(required=True,widget=NumberInput(attrs={
'cols': '2',
'min': '0', 'max': '99', 'step': '1',
'class':'form-inline',
'role': 'form'}
))
tippTeam2 = forms.IntegerField(required=True,widget=NumberInput(attrs={
'cols': '2',
'min': '0', 'max': '99', 'step': '1',
'class':'form-inline',
'role': 'form'}
))
tippTeam1.widget.attrs['style'] = "width:35px"
tippTeam2.widget.attrs['style'] = "width:35px"
class BlogpostForm(ModelForm):
class Meta:
model = Post
fields = ['title', 'content']
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ['email', 'first_name', 'last_name']
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ['avatar']

111
tipp/models.py Normal file
View File

@@ -0,0 +1,111 @@
from django.db import models
from django.core.urlresolvers import reverse
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User)
avatar = models.ImageField(upload_to="profiles/", blank=True)
def __unicode__(self):
return self.user.username
class Competition(models.Model):
leagueShortcut = models.CharField(max_length=32)
leagueName = models.CharField(max_length=128)
season = models.CharField(max_length=4)
def __unicode__(self):
return(self.leagueShortcut)
class Team(models.Model):
teamID = models.IntegerField(unique=True, primary_key=True)
name = models.CharField(max_length=200)
icon = models.FileField(upload_to="images/team_logos/")
abbr = models.CharField(max_length=3)
def __unicode__(self):
return self.name
class Match(models.Model):
matchID = models.IntegerField(unique=True,primary_key=True)
matchDateTime = models.DateTimeField()
group = models.IntegerField()
matchday = models.IntegerField()
idTeam1 = models.ForeignKey(Team, related_name='+')
idTeam2 = models.ForeignKey(Team, related_name='+')
pointsTeam1 = models.SmallIntegerField()
pointsTeam2 = models.SmallIntegerField()
finished = models.BooleanField()
season = models.CharField(max_length=4)
leagueShortcut = models.CharField(max_length=12)
def __unicode__(self):
"""
return (str(self.matchID) +
str(Team.objects.get(teamID=int(self.idTeam1)).values(name)) + " - " +
str(Team.objects.get(teamID=int(self.idTeam2)).values(name)))
"""
return (str(self.matchID))
class Tipp(models.Model):
matchID = models.ForeignKey(Match)
tipperID = models.ForeignKey(User)
pointsTeam1 = models.PositiveSmallIntegerField()
pointsTeam2 = models.PositiveSmallIntegerField()
score = models.PositiveIntegerField(blank=True, null=True)
class Meta:
unique_together = ("matchID", "tipperID")
class Mandant(models.Model):
name = models.CharField(max_length=32, unique=True)
description = models.CharField(max_length=255)
def __unicode__(self):
return self.name
class Score(models.Model):
client = models.ForeignKey(Mandant)
exact_high = models.PositiveSmallIntegerField()
exact = models.PositiveSmallIntegerField()
diff = models.PositiveSmallIntegerField()
tendency = models.PositiveSmallIntegerField()
def __unicode__(self):
return str(self.client)
class chart(models.Model):
team = models.ForeignKey(Team)
competition = models.ForeignKey(Competition)
points = models.PositiveSmallIntegerField()
diff = models.SmallIntegerField()
games = models.PositiveSmallIntegerField()
class Meta:
unique_together = ("team", "competition")
class RelUserMandant(models.Model):
user = models.ForeignKey(User)
mandant = models.ForeignKey(Mandant)
class Meta:
unique_together = ("user", "mandant")
def __unicode__(self):
return (str(self.user) + " -> " + str(self.mandant))
class Post(models.Model):
title = models.CharField(max_length=255)
slug = models.SlugField(unique=True, max_length=255)
content = models.TextField()
published = models.BooleanField(default=True)
created = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(User)
class Meta:
ordering = ['-created']
def __unicode__(self):
return u'%s' % self.title
def get_absolute_url(self):
return reverse('tipp.views.blogpost', args=[self.slug])

68
tipp/openliga.py Executable file
View File

@@ -0,0 +1,68 @@
#!/usr/bin/env python
#
# Copyright 2013 by Martin Bley <martin@mb-oss.de>
#
# tippy.py is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# tippy.py is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with tippy.py. If not, see <http://www.gnu.org/licenses/>.
#
import sys, locale, suds, urllib2, psycopg2
class OpenLiga(object):
version = "0.1"
error = ""
proxyurl = None
debug = None
client = None
def __init__(self, proxyurl=None, debug=False):
# set locale to environment (for dispaying localized dates)
locale.setlocale(locale.LC_TIME, "")
self.debug = debug
# get a SUDS client object
if self.proxyurl is None:
try:
self.client = suds.client.Client('http://www.openligadb.de/Webservices/Sportsdata.asmx?WSDL')
except (urllib2.URLError):
self.error += "Connect to webservice failed."
else:
try:
t = suds.transport.http.HttpTransport()
proxy = urllib2.ProxyHandler({'http':proxyurl})
opener = urllib2.build_opener(proxy)
t.urlopener = opener
self.client = suds.client.Client('http://www.openligadb.de/Webservices/Sportsdata.asmx?WSDL', transport=t)
except urllib2.URLError as e:
self.error += "Connect to webservice failed (via proxy " + proxyurl + "): " + str(e) + "\n"
def getSeason(self, season, league='bl1'):
""" Get the whole season.
Args: season and league shortcut (optional)
"""
return(self.client.service.GetMatchdataByLeagueSaison(leagueShortcut=league,leagueSaison=season))
def getMatchday(self, season, matchdaynumber, league='bl1'):
""" Get matchday.
Args: season, matchdaynumber and league shortcut (optional)
"""
return(self.client.service.GetMatchdataByGroupLeagueSaison(groupOrderID=matchdaynumber,leagueShortcut=league,leagueSaison=season))
def getTeams(self, season, league='bl1'):
return(self.client.service.GetTeamsByLeagueSaison(leagueShortcut=league,leagueSaison=season))

16
tipp/tests.py Normal file
View File

@@ -0,0 +1,16 @@
"""
This file demonstrates writing tests using the unittest module. These will pass
when you run "manage.py test".
Replace this with more appropriate tests for your application.
"""
from django.test import TestCase
class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.
"""
self.assertEqual(1 + 1, 2)

3
tipp/updateMatch.py Normal file
View File

@@ -0,0 +1,3 @@
from tipp.models import Match

486
tipp/views.py Normal file
View File

@@ -0,0 +1,486 @@
# -*- coding: utf-8 -*-
from django.http import HttpResponse
from django.shortcuts import render_to_response, redirect, render, get_object_or_404
from django.contrib.auth import authenticate, login
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required
from django.contrib.auth.views import password_reset, password_reset_confirm
from django.core.context_processors import csrf
from django.core.exceptions import ObjectDoesNotExist
from django.core.urlresolvers import reverse
from django.core.paginator import Paginator, InvalidPage, EmptyPage, PageNotAnInteger
from django.utils import timezone
from django.utils.text import slugify
from django.db.models import Sum
from django.conf import settings
from os.path import join as pjoin
from tipp.models import *
from tipp.forms import *
from openliga import *
from datetime import datetime
from PIL import Image as PImage
import urllib2, pytz, os
timezoneLocal = pytz.timezone('Europe/Berlin')
@login_required
def home(request):
ls = get_current_ls()
season = get_current_season()
return redirect("matchday",
ls = ls,
season = season,
matchday=str(get_current_md(ls, season)).zfill(2)
)
@login_required
def profile(request, pk):
user = User.objects.get(id=pk)
profile, created = UserProfile.objects.get_or_create(user=user)
if profile.avatar:
img = profile.avatar.name
else:
img = None
debug = []
debug.append('avatar: ' + str(img))
# If it's a HTTP POST, we're interested in processing form data.
if request.method == 'POST':
# Attempt to grab information from the raw form information.
# Note that we make use of both UserForm and UserProfileForm.
user_form = UserForm(data=request.POST, instance=user)
profile_form = UserProfileForm(data=request.POST, instance=profile)
# If the two forms are valid...
if user_form.is_valid() and profile_form.is_valid():
# Save the user's form data to the database.
user = user_form.save()
# Now sort out the UserProfile instance.
# Since we need to set the user attribute ourselves, we set commit=False.
# This delays saving the model until we're ready to avoid integrity problems.
profile = profile_form.save(commit=False)
profile.user = user
# Did the user provide a profile picture?
# If so, we need to get it from the input form and put it in the UserProfile model.
if 'avatar' in request.FILES:
profile.avatar = request.FILES['avatar']
# Now we save the UserProfile model instance.
profile.save()
# create thumbnail
imfn = pjoin(settings.MEDIA_ROOT, profile.avatar.name)
im = PImage.open(imfn)
im.thumbnail((50,50), PImage.ANTIALIAS)
im.save(settings.MEDIA_ROOT + profile.avatar.name)
if 'avatar-clear' in request.POST:
if 'on' in request.POST['avatar-clear']:
image = pjoin(settings.MEDIA_ROOT, img)
debug.append('Is the image ' + str(image) + ' a regular file? ' + str(os.path.isfile(image)))
if os.path.isfile(image):
os.remove(image)
profile.save()
for item in request.POST:
debug.append(str(item) + " -> " + str(request.POST[item]))
# Invalid form or forms - mistakes or something else?
# Print problems to the terminal.
# They'll also be shown to the user.
else:
print user_form.errors, profile_form.errors
return redirect( '/accounts/profile/' + str(user.id) )
# Not a HTTP POST, so we render our form using two ModelForm instances.
# These forms will be blank, ready for user input.
else:
user_form = UserForm(
initial={ 'last_name': user.last_name,
'first_name': user.first_name,
'email': user.email },
instance=user
)
profile_form = UserProfileForm(instance=profile)
return render(request, 'registration/profile.html', {
'user_form': user_form,
'profile_form': profile_form,
'debug': debug,
'img': img}
)
@login_required
def update(request, ls, season, cur_md):
"""
To do:
- update table tipp_competition
"""
ol = OpenLiga()
md_matches = ol.getMatchday(str(season), int(cur_md) ,ls)
# Achtung: DateTimeField prüfen
for match in md_matches[0]:
# Endergebnis holen
matchResults = match['matchResults']
try:
for result in matchResults[0]:
if result['resultName'] == "Endergebnis":
pointsTeam1=int(result['pointsTeam1'])
pointsTeam2=int(result['pointsTeam2'])
elif result['resultName'] == "Halbzeitergebnis":
pointsTeam1=int(result['pointsTeam1'])
pointsTeam2=int(result['pointsTeam2'])
except:
pointsTeam1=-1
pointsTeam2=-1
m = Match(matchID=unicode(match['matchID']),
matchDateTime=datetime.strptime(unicode(match['matchDateTime']), '%Y-%m-%d %H:%M:%S'),
group=int(match['groupID']),
matchday=int(match['groupOrderID']),
idTeam1=Team.objects.get(teamID=int(match['idTeam1'])),
idTeam2=Team.objects.get(teamID=int(match['idTeam2'])),
pointsTeam1=pointsTeam1,
pointsTeam2=pointsTeam2,
finished=bool(match['matchIsFinished']),
season=match['leagueSaison'],
leagueShortcut=match['leagueShortcut']
)
m.save()
pointsTeam1=-1
pointsTeam2=-1
""" evaluate scores """
scores = Score.objects.get(client=Mandant.objects.get(name='huse'))
finished_matches=Match.objects.filter(finished=True)
for match in finished_matches:
tipps = Tipp.objects.filter(matchID=match.matchID)
for tipp in tipps:
score = 0
goals_total = match.pointsTeam1 + match.pointsTeam2
""" Tipp is acurate """
if (tipp.pointsTeam1 == match.pointsTeam1 and tipp.pointsTeam2 == match.pointsTeam2):
if goals_total >= 5:
score = scores.exact_high
else:
score = scores.exact
tipp.score = score
tipp.save()
continue
""" who won? """
winnerReal = None
if match.pointsTeam1 > match.pointsTeam2:
winnerReal = 1
elif (match.pointsTeam2 > match.pointsTeam1):
winnerReal = 2
elif (match.pointsTeam1 == match.pointsTeam2):
winnerReal = 0
winnerTipp = None
if tipp.pointsTeam1 > tipp.pointsTeam2:
winnerTipp = 1
elif (tipp.pointsTeam2 > tipp.pointsTeam1):
winnerTipp = 2
elif (tipp.pointsTeam1 == tipp.pointsTeam2):
winnerTipp = 0
diffReal = match.pointsTeam1 - match.pointsTeam2
diffTipp = tipp.pointsTeam1 - tipp.pointsTeam2
if ( winnerTipp == winnerReal ):
if ( diffTipp == diffReal ):
score = scores.diff
else:
score = scores.tendency
tipp.score = score
tipp.save()
continue
tipp.score = score
tipp.save()
continue
return redirect("matchday", ls=ls, season=season, matchday=cur_md)
@login_required
def matchday(request, ls, season, matchday, template_name='md.html'):
debug = ''
debug += "Debugging: "
has_refresh = True
""" get matchday closest to current date """
md_matches = Match.objects.filter(leagueShortcut=ls, season=season, matchday=int(matchday)).order_by('matchDateTime')
""" get the current user """
user = User.objects.get(username=request.user.username)
""" get mandants current user is related """
mandants = RelUserMandant.objects.filter(user=request.user).values_list('mandant', flat=True)
""" get mates """
tipp_mates = []
for m in mandants:
rs = RelUserMandant.objects.filter(mandant=m)
for r in rs:
tipp_mates.append({
'mate': r.user,
'tipps': [],
'sum_score': 0
})
matches = []
for match in md_matches:
"""
create a form for each tipp
"""
form = TippForm(request.POST or None, prefix=str(match.matchID))
"""
check if Tipp already exists
"""
try:
tipp = Tipp.objects.get(tipperID=user.id,matchID=match.matchID)
except ObjectDoesNotExist:
tipp = None
"""
if request is a POST, process form data, else just show form
"""
if form.is_valid():
data = form.cleaned_data
if tipp is not None:
""" Tipp exists an needs an UPDATE"""
tipp = Tipp(id=tipp.pk,
matchID=match,
tipperID=user,
pointsTeam1=data['tippTeam1'],
pointsTeam2=data['tippTeam2']
)
tipp.save()
else:
""" do INSERT """
tipp = Tipp( matchID=match,
tipperID=user,
pointsTeam1=data['tippTeam1'],
pointsTeam2=data['tippTeam2'])
tipp.save()
match_started = timezone.now() >= match.matchDateTime
if tipp is not None:
f = TippForm(prefix=str(match.matchID),
initial={'tippTeam1': tipp.pointsTeam1, 'tippTeam2': tipp.pointsTeam2}
)
else:
f = TippForm(prefix=str(match.matchID))
item = {}
item['matchDateTime'] = (match.matchDateTime.astimezone(timezoneLocal).strftime('%a %d.%m, %H:%M'))
item['iconTeam1']= str(match.idTeam1.icon)
item['nameTeam1']= str(match.idTeam1)
item['abbrTeam1']= str(match.idTeam1.abbr)
item['iconTeam2'] = str(match.idTeam2.icon)
item['nameTeam2'] = str(match.idTeam2)
item['abbrTeam2']= str(match.idTeam2.abbr)
item['started'] = match_started
item['finished'] = match.finished
if (match.pointsTeam1 == -1 or match.pointsTeam2 == -1):
item['matchResult'] = "-:-"
else:
item['matchResult'] = str(match.pointsTeam1) + ":" + str(match.pointsTeam2)
item['tippFormTeam1'] = f['tippTeam1']
item['tippFormTeam2'] = f['tippTeam2']
if match_started is True:
f.fields['tippTeam1'].widget.attrs['disabled'] = True
f.fields['tippTeam2'].widget.attrs['disabled'] = True
for mate in tipp_mates:
try:
matetipp = Tipp.objects.get(tipperID=mate['mate'],matchID=match.matchID)
if match_started is True:
mate['tipps'].append(str(matetipp.pointsTeam1) + ":" + str(matetipp.pointsTeam2) + "(" + str(matetipp.score) + ")")
if match.finished is True:
mate['sum_score'] += matetipp.score
else:
mate['tipps'].append(u'\u2714')
except Exception as e:
mate['tipps'].append(u'\u2717')
matches.append(item)
# get the newest blogposts
posts = []
for post in Post.objects.filter(published=True)[:2]:
try:
avatar = UserProfile.objects.get(user_id=post.author_id).avatar.name
except:
avatar = None
posts.append( (post, avatar) )
return render(request, 'md.html', {
#'debug': debug,
#'mds_season': mds_in_season,
'cur_md': matchday,
'matches': matches,
'ls': ls,
'season': season,
'username': user,
'tipp_mates': sorted(tipp_mates, key=lambda k: k['sum_score'], reverse=True),
'posts': posts,
'has_refresh': has_refresh
})
@login_required
def charts(request, ls, season, pos='default', template_name='charts.html'):
debug = ''
if pos == 'default':
if get_current_md(ls, season) < 18:
pos = 'hin'
matches = Match.objects.filter(leagueShortcut=ls, season=season, matchday__lte=17)
else:
pos = 'rueck'
matches = Match.objects.filter(leagueShortcut=ls, season=season, matchday__gte=18)
elif pos == 'hin':
matches = Match.objects.filter(leagueShortcut=ls, season=season, matchday__lte=17)
elif pos == 'rueck':
matches = Match.objects.filter(leagueShortcut=ls, season=season, matchday__gte=18)
else:
matches = Match.objects.filter(leagueShortcut=ls, season=season)
# get mandants of current user
mandants = RelUserMandant.objects.filter(user=request.user).values_list('mandant', flat=True)
# main loop
mandant_dict = {}
for m in mandants:
mandant = Mandant.objects.get(id=m)
# get users
users = RelUserMandant.objects.filter(mandant=m).values_list('user', flat=True)
user_dict = {}
for userid in users:
# get user object, then fetch matches for user
user = User.objects.get(id=userid)
score = Tipp.objects.filter(matchID__in=matches, tipperID=user).aggregate(Sum('score'))
user_dict[user.first_name] = score['score__sum']
mandant_dict[mandant.name] = sorted(user_dict.items(), key=lambda x: x[1], reverse=True)
return render(request, template_name, {
#'debug': debug,
'mandant_dict': mandant_dict,
'season': season,
'ls': ls,
'pos': pos
})
@login_required
def blogindex(request, page):
# get the blog posts that are published
post_list = []
for post in Post.objects.filter(published=True):
try:
avatar = UserProfile.objects.get(user_id=post.author_id).avatar.name
except:
avatar = None
post_list.append( (post, avatar) )
p = Paginator(post_list, 5)
try:
posts = p.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
posts = p.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
posts = p.page(p.num_pages)
# now return the rendered template
return render(request, 'blogindex.html', {
'posts': posts,
'ls': get_current_ls(),
'season': get_current_season(),
'page': page
})
@login_required
def blogpost(request, slug):
# get the Post object
post = get_object_or_404(Post, slug=slug)
# now return the rendered template
return render(request, 'blogpost.html', {
'post': post,
'ls': get_current_ls(),
'season': get_current_season()
})
@login_required
def newBlogpost(request):
"""
if this is a POST request we need to process the form data
"""
if request.method == 'POST':
# create form instance and populate it with data from the request
form = BlogpostForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data
data = form.cleaned_data
slug = slugify(data['title'])
p = Post(author_id=request.user.id, slug=slug, title=data['title'], content=data['content'])
p.save()
# ...
# redirect to a new URL:
return redirect( '/blog/1')
# if a GET (or any other method) we'll create a blank form
else:
blogpostForm = BlogpostForm()
return render(request, 'newblogpost.html', {
'form': blogpostForm,
'ls': get_current_ls(),
'season': get_current_season()
})
def logout(request):
"""
Log users out and re-direct them to the main page.
"""
logout(request)
return HttpResponseRedirect('/')
def get_current_md(ls,season):
""" get current matchday """
current_md = Match.objects.filter(leagueShortcut=ls, season=season, finished=False).order_by('matchday').values_list('matchday', flat=True).distinct()[0]
return(current_md)
def get_current_ls():
return("bl1")
def get_current_season():
return("2015")