def results(request): base = base_ctx('Results', 'By Date', request) try: day = datetime.strptime(get_param(request, 'd', None), '%Y-%m-%d').date() except: day = date.today() bounds = Match.objects.aggregate(Min('date'), Max('date')) day = min(max(bounds['date__min'], day), bounds['date__max']) base.update({ 'mindate': bounds['date__min'], 'maxdate': bounds['date__max'], 'td': day, }) matches = (Match.objects.filter(date=day).order_by( 'eventobj__idx', 'eventobj__latest', 'event', 'id').prefetch_related('message_set', 'rta', 'rtb', 'pla', 'plb', 'eventobj').annotate(Count('eventobj__match'))) add_links = request.user.is_authenticated() and request.user.is_staff base['matches'] = display_matches(matches, date=False, ratings=True, messages=True, eventcount=True, add_links=add_links) return render_to_response('results.djhtml', base)
def add_matches(request): base = base_ctx('Submit', 'Matches', request) login_message(base) if request.method == 'POST' and 'submit' in request.POST: form = AddMatchesForm(base['adm'], request=request) base['matches'] = display_matches(form.parse_matches(request.user), messages=False) base['messages'] += form.messages else: form = AddMatchesForm(base['adm']) try: get_event = Event.objects.get(id=request.GET['eventid']) if get_event.closed: get_event.open() base['messages'].append(Message(_("Reopened '%s'.") % get_event.fullname, type=Message.SUCCESS)) form['eventobj'].field.choices.append((get_event.id, get_event.fullname)) form['eventobj'].field.choices.sort(key=lambda e: e[1]) base['event_override'] = get_event.id except: pass base['form'] = form base.update({"title": _("Submit results")}) return render_to_response('add.html', base)
def add_matches(request): base = base_ctx('Submit', 'Matches', request) login_message(base) if request.method == 'POST' and 'submit' in request.POST: form = AddMatchesForm(base['adm'], request=request) base['matches'] = display_matches(form.parse_matches(request.user), messages=False) base['messages'] += form.messages else: form = AddMatchesForm(base['adm']) try: get_event = Event.objects.get(id=request.GET['eventid']) if get_event.closed: get_event.open() base['messages'].append( Message(_("Reopened '%s'.") % get_event.fullname, type=Message.SUCCESS)) form['eventobj'].field.choices.append( (get_event.id, get_event.fullname)) form['eventobj'].field.choices.sort(key=lambda e: e[1]) base['event_override'] = get_event.id except: pass base['form'] = form return render_to_response('add.djhtml', base)
def review_matches(request): base = base_ctx('Submit', 'Review', request) if not base['adm']: return redirect('/login/') login_message(base) if request.method == 'POST': form = ReviewMatchesForm(request=request, submitter=request.user) base['messages'] += form.messages else: form = ReviewMatchesForm() base['form'] = form base['groups'] = ( PreMatchGroup.objects.filter(prematch__isnull=False) .prefetch_related('prematch_set') .order_by('id', 'event') .distinct() ) for g in base['groups']: g.prematches = display_matches(g.prematch_set.all(), messages=False, no_events=True) return render_to_response('review.djhtml', base)
def review_matches(request): base = base_ctx('Submit', 'Review', request) if not base['adm']: return redirect('/login/') login_message(base) if request.method == 'POST': form = ReviewMatchesForm(request=request, submitter=request.user) base['messages'] += form.messages else: form = ReviewMatchesForm() base['form'] = form base['groups'] = ( PreMatchGroup.objects.filter(prematch__isnull=False) .prefetch_related('prematch_set') .order_by('id', 'event') .distinct() ) for g in base['groups']: g.prematches = display_matches(g.prematch_set.all(), messages=False) base.update({"title": _("Review results")}) return render_to_response('review.html', base)
def player_results(request, player_id): player = get_object_or_404(Player, id=int(player_id)) matches = Match.objects.filter(Q(pla=player) | Q(plb=player)) base = base_ctx('Ranking', 'Match history', request, context=player) if 'race' in request.GET: q = None for r in request.GET['race']: try: q |= Q(pla=player, rcb=r) q |= Q(plb=player, rca=r) except: q = Q(pla=player, rcb=r) q |= Q(plb=player, rca=r) matches = matches.filter(q) base['race'] = request.GET['race'] else: base['race'] = 'ptzr' if 'nats' in request.GET: if request.GET['nats'] == 'foreigners': matches = matches.exclude(Q(pla=player, plb__country='KR') | Q(plb=player, pla__country='KR')) elif request.GET['nats'] == 'kr': matches = matches.filter(Q(pla=player, plb__country='KR') | Q(plb=player, pla__country='KR')) base['nats'] = request.GET['nats'] else: base['nats'] = 'all' if 'bo' in request.GET: if request.GET['bo'] == '3': matches = matches.filter(Q(sca__gte=2) | Q(scb__gte=2)) elif request.GET['bo'] == '5': matches = matches.filter(Q(sca__gte=3) | Q(scb__gte=3)) base['bo'] = request.GET['bo'] else: base['bo'] = 'all' if 'offline' in request.GET: if request.GET['offline'] == 'online': matches = matches.filter(offline=0) elif request.GET['offline'] == 'offline': matches = matches.filter(offline=1) base['offline'] = request.GET['offline'] else: base['offline'] = 'both' matches = matches.order_by('-date', '-eventobj__lft', 'event', '-id') matches = matches.select_related('pla__rating').select_related('plb__rating').select_related('period') base['matches'] = display_matches(matches, fix_left=player, ratings=True) base['sc_my'] = sum([m.pla_score for m in base['matches']]) base['sc_op'] = sum([m.plb_score for m in base['matches']]) base['msc_my'] = sum([1 if m.pla_score > m.plb_score else 0 for m in base['matches']]) base['msc_op'] = sum([1 if m.plb_score > m.pla_score else 0 for m in base['matches']]) base['player'] = player return render_to_response('player_results.html', base)
def results(request): base = base_ctx('Results', 'By Date', request) try: day = datetime.strptime(get_param(request, 'd', None), '%Y-%m-%d').date() except: day = date.today() bounds = Match.objects.aggregate(Min('date'), Max('date')) day = min(max(bounds['date__min'], day), bounds['date__max']) base.update({ 'mindate': bounds['date__min'], 'maxdate': bounds['date__max'], 'td': day, }) matches = ( Match.objects.filter(date=day).order_by('eventobj__idx', 'eventobj__latest', 'event', 'id') .prefetch_related('message_set', 'rta', 'rtb', 'pla', 'plb', 'eventobj') .annotate(Count('eventobj__match')) ) add_links = request.user.is_authenticated() and request.user.is_staff base['matches'] = display_matches(matches, date=False, ratings=True, messages=True, eventcount=True, add_links=add_links) return render_to_response('results.djhtml', base)
def integrity(request): base = base_ctx('Submit', 'Integrity', request) if not base['adm']: base.update(csrf(request)) return render_to_response('login.html', base) add_login_message(base) base.update(csrf(request)) with open(M_WARNINGS, 'r') as f: warnings = pickle.load(f) with open(M_APPROVED, 'r') as f: approved = pickle.load(f) if 'del' in request.POST or 'del_ok' in request.POST: ndel = 0 for key in request.POST: if request.POST[key] != 'y': continue if key[0:6] == 'match-': try: Match.objects.get(id=int(key.split('-')[-1])).delete() ndel += 1 except: pass base['messages'].append(Message('Deleted %i match(es).' % ndel, type=Message.SUCCESS)) if 'del_ok' in request.POST or 'false' in request.POST: warning = tuple([int(f) for f in request.POST['warning'].split(',')]) warnings.remove(warning) approved.add(warning) with open(M_WARNINGS, 'w') as f: pickle.dump(warnings, f) with open(M_APPROVED, 'w') as f: pickle.dump(approved, f) base['messages'].append(Message('Resolved one integrity warning.', type=Message.SUCCESS)) matches = [] for w in warnings: block = [] for id in w: try: block.append(Match.objects.get(id=id)) except: pass matches.append((','.join(str(k) for k in list(w)), display_matches(block, messages=False))) if len(matches) == 50: break base['matches'] = matches if len(matches) == 0: base['messages'].append(Message('There are currently no warnings pending resolution.', type=Message.INFO)) base['num'] = len(warnings) return render_to_response('integrity.html', base)
def results(request, player_id): # {{{ Get objects player = get_object_or_404(Player, id=player_id) base = base_ctx('Ranking', 'Match history', request, context=player) base['player'] = player # }}} # {{{ Filtering matches = player.get_matchset(related=['pla','plb','eventobj']) form = ResultsFilterForm(request.GET) base['form'] = form form.is_valid() q = Q() for r in form.cleaned_data['race'].upper(): q |= Q(pla=player, rcb=r) | Q(plb=player, rca=r) matches = matches.filter(q) if form.cleaned_data['country'] == 'foreigners': matches = matches.exclude(Q(pla=player, plb__country='KR') | Q(plb=player, pla__country='KR')) elif form.cleaned_data['country'] != 'all': matches = matches.filter( Q(pla=player, plb__country=form.cleaned_data['country']) | Q(plb=player, pla__country=form.cleaned_data['country']) ) if form.cleaned_data['bestof'] != 'all': sc = int(form.cleaned_data['bestof'])//2 + 1 matches = matches.filter(Q(sca__gte=sc) | Q(scb__gte=sc)) if form.cleaned_data['offline'] != 'both': matches = matches.filter(offline=(form.cleaned_data['offline']=='offline')) if form.cleaned_data['game'] != 'all': matches = matches.filter(game=form.cleaned_data['game']) if form.cleaned_data['after'] is not None: matches = matches.filter(date__gte=form.cleaned_data['after']) if form.cleaned_data['before'] is not None: matches = matches.filter(date__lte=form.cleaned_data['before']) # }}} # {{{ Statistics base['matches'] = display_matches(matches, fix_left=player) base.update({ 'sc_my': sum([m['pla_score'] for m in base['matches']]), 'sc_op': sum([m['plb_score'] for m in base['matches']]), 'msc_my': sum([1 if m['pla_score'] > m['plb_score'] else 0 for m in base['matches']]), 'msc_op': sum([1 if m['plb_score'] > m['pla_score'] else 0 for m in base['matches']]), }) # }}} base.update({"title": player.tag}) return render_to_response('player_results.html', base)
def integrity(request): base = base_ctx('Submit', 'Integrity', request) if not base['adm']: base.update(csrf(request)) return render_to_response('login.html', base) base['user'] = request.user.username base.update(csrf(request)) with open(M_WARNINGS, 'r') as f: warnings = pickle.load(f) with open(M_APPROVED, 'r') as f: approved = pickle.load(f) if 'del' in request.POST or 'del_ok' in request.POST: for key in request.POST: if request.POST[key] != 'y': continue if key[0:6] == 'match-': try: Match.objects.get(id=int(key.split('-')[-1])).delete() except: pass if 'del_ok' in request.POST or 'false' in request.POST: warning = tuple([int(f) for f in request.POST['warning'].split(',')]) warnings.remove(warning) approved.add(warning) with open(M_WARNINGS, 'w') as f: pickle.dump(warnings, f) with open(M_APPROVED, 'w') as f: pickle.dump(approved, f) matches = [] for w in warnings: block = [] for id in w: try: block.append(Match.objects.get(id=id)) except: pass matches.append((','.join(str(k) for k in list(w)), display_matches(block))) if len(matches) == 50: break base['matches'] = matches base['num'] = len(warnings) return render_to_response('integrity.html', base)
def results(request): base = base_ctx('Results', 'By Date', request) try: ints = [int(x) for x in request.GET['d'].split('-')] td = datetime.date(ints[0], ints[1], ints[2]) except: td = datetime.date.today() matches = Match.objects.filter(date=td).order_by('eventobj__lft', 'event', 'id') base['matches'] = display_matches(matches, date=False, ratings=True) base['td'] = td return render_to_response('results.html', base)
def clocks(request): ctx = base_ctx('Misc', 'Days Since…', request) ctx["title"] = _("Number of days since…") ctx["clocks"] = list() for desc, alt_desc, q, t in CLOCKS: obj = None extra = None date = None if t == "match": q = q.prefetch_related("pla", "plb", "eventobj") matches = list(q[:10]) extra = display_matches(matches) obj = matches[0] date = obj.date elif t == "event_winner": q = q.prefetch_related("earnings_set") events = list(q[:10]) obj = events[0] extra = list() for e in events: pearnings = list( e.earnings_set .exclude(placement=0) .order_by("placement") .prefetch_related("player")[:2] ) extra.append((e, pearnings)) date = obj.latest elif t == "one_time": date = q() diff = datetime.today().date() - date years = diff.days // 365 days = diff.days % 365 c = Clock(desc, alt_desc, obj, t, date, years, days, extra) ctx["clocks"].append(c) ctx["clocks"].sort(key=lambda c: c.date, reverse=True) return render_to_response("clocks.html", ctx)
def clocks(request): ctx = base_ctx('Misc', 'Days Since…', request) ctx["clocks"] = list() for desc, alt_desc, q, t in CLOCKS: obj = None extra = None date = None if t == "match": q = q.prefetch_related("pla", "plb", "eventobj", "message_set") matches = q[:10] extra = display_matches(matches) date = extra[0]["date"] elif t == "event_winner": q = q.prefetch_related("earnings_set") events = list(q[:10]) obj = events[0] extra = list() for e in events: pearnings = list( e.earnings_set.exclude(placement=0).order_by( "placement").prefetch_related("player")[:2]) extra.append((e, pearnings)) date = obj.latest elif t == "one_time": date = q() diff = datetime.today().date() - date years = diff.days // 365 days = diff.days % 365 c = Clock(desc, alt_desc, obj, t, date, years, days, extra) ctx["clocks"].append(c) ctx["clocks"].sort(key=lambda c: c.date, reverse=True) return render_to_response("clocks.djhtml", ctx)
def match(request): base = base_ctx('Inference', 'Predict', request=request) # {{{ Get data, set up and simulate form = SetupForm(request.GET) if not form.is_valid(): return redirect('/inference/') result = MatchPredictionResult( dbpl=form.cleaned_data['ps'], bos=form.cleaned_data['bo'], s1=get_param(request, 's1', 0), s2=get_param(request, 's2', 0), ) # }}} # {{{ Postprocessing base.update({ 'form': form, 'dbpl': result.dbpl, 'rta': result.rta, 'rtb': result.rtb, 'proba': result.proba, 'probb': result.probb, 'match': result.obj, }) base.update({ 'max': max(base['proba'], base['probb']), 'fav': result.dbpl[0] if base['proba'] > base['probb'] else result.dbpl[1], }) resa = [oc for oc in result.outcomes if oc['sca'] > oc['scb']] resb = [oc for oc in result.outcomes if oc['scb'] > oc['sca']] if len(resa) < len(resb): resa = [None] * (len(resb) - len(resa)) + resa else: resb = [None] * (len(resa) - len(resb)) + resb base['res'] = list(zip(resa, resb)) # }}} # {{{ Scores and other data dbpl = result.dbpl thr = date.today() - relativedelta(months=2) pla_matches = dbpl[0].get_matchset() plb_matches = dbpl[1].get_matchset() base['tot_w_a'], base['tot_l_a'] = count_winloss_player(pla_matches, dbpl[0]) base['frm_w_a'], base['frm_l_a'] = count_winloss_player(pla_matches.filter(date__gte=thr), dbpl[0]) base['tot_w_b'], base['tot_l_b'] = count_winloss_player(plb_matches, dbpl[1]) base['frm_w_b'], base['frm_l_b'] = count_winloss_player(plb_matches.filter(date__gte=thr), dbpl[1]) if dbpl[1].race in 'PTZ': base['mu_w_a'], base['mu_l_a'] = count_matchup_player(pla_matches, dbpl[0], dbpl[1].race) base['fmu_w_a'], base['fmu_l_a'] = count_matchup_player( pla_matches.filter(date__gte=thr), dbpl[0], dbpl[1].race ) if dbpl[0].race in 'PTZ': base['mu_w_b'], base['mu_l_b'] = count_matchup_player(plb_matches, dbpl[1], dbpl[0].race) base['fmu_w_b'], base['fmu_l_b'] = count_matchup_player( plb_matches.filter(date__gte=thr), dbpl[1], dbpl[0].race ) wa_a, wb_a = count_winloss_games(Match.objects.filter(pla=dbpl[0], plb=dbpl[1])) wb_b, wa_b = count_winloss_games(Match.objects.filter(pla=dbpl[1], plb=dbpl[0])) base['vs_a'] = wa_a + wa_b base['vs_b'] = wb_a + wb_b base['matches'] = display_matches( Match.objects.filter(Q(pla=dbpl[0], plb=dbpl[1]) | Q(plb=dbpl[0], pla=dbpl[1])) .select_related('period', 'pla', 'plb') .order_by('-date', 'id'), fix_left=dbpl[0], ) # }}} postable_match(base, request) return render_to_response('pred_match.djhtml', base)
def match(request): base = base_ctx('Inference', 'Predict', request=request) # {{{ Get data, set up and simulate form = SetupForm(request.GET) if not form.is_valid(): return redirect('/inference/') result = MatchPredictionResult( dbpl=form.cleaned_data['ps'], bos=form.cleaned_data['bo'], s1=get_param(request, 's1', 0), s2=get_param(request, 's2', 0), ) # }}} # {{{ Postprocessing base.update({ 'form': form, 'dbpl': result.dbpl, 'rta': result.rta, 'rtb': result.rtb, 'proba': result.proba, 'probb': result.probb, 'match': result.obj, }) base.update({ 'max': max(base['proba'], base['probb']), 'fav': result.dbpl[0] if base['proba'] > base['probb'] else result.dbpl[1], }) resa = [oc for oc in result.outcomes if oc['sca'] > oc['scb']] resb = [oc for oc in result.outcomes if oc['scb'] > oc['sca']] if len(resa) < len(resb): resa = [None] * (len(resb) - len(resa)) + resa else: resb = [None] * (len(resa) - len(resb)) + resb base['res'] = list(zip(resa, resb)) # }}} # {{{ Scores and other data dbpl = result.dbpl thr = date.today() - relativedelta(months=2) pla_matches = dbpl[0].get_matchset() plb_matches = dbpl[1].get_matchset() base['tot_w_a'], base['tot_l_a'] = count_winloss_player( pla_matches, dbpl[0]) base['frm_w_a'], base['frm_l_a'] = count_winloss_player( pla_matches.filter(date__gte=thr), dbpl[0]) base['tot_w_b'], base['tot_l_b'] = count_winloss_player( plb_matches, dbpl[1]) base['frm_w_b'], base['frm_l_b'] = count_winloss_player( plb_matches.filter(date__gte=thr), dbpl[1]) if dbpl[1].race in 'PTZ': base['mu_w_a'], base['mu_l_a'] = count_matchup_player( pla_matches, dbpl[0], dbpl[1].race) base['fmu_w_a'], base['fmu_l_a'] = count_matchup_player( pla_matches.filter(date__gte=thr), dbpl[0], dbpl[1].race) if dbpl[0].race in 'PTZ': base['mu_w_b'], base['mu_l_b'] = count_matchup_player( plb_matches, dbpl[1], dbpl[0].race) base['fmu_w_b'], base['fmu_l_b'] = count_matchup_player( plb_matches.filter(date__gte=thr), dbpl[1], dbpl[0].race) wa_a, wb_a = count_winloss_games( Match.objects.filter(pla=dbpl[0], plb=dbpl[1])) wb_b, wa_b = count_winloss_games( Match.objects.filter(pla=dbpl[1], plb=dbpl[0])) base['vs_a'] = wa_a + wa_b base['vs_b'] = wb_a + wb_b base['matches'] = display_matches( Match.objects.filter( Q(pla=dbpl[0], plb=dbpl[1]) | Q(plb=dbpl[0], pla=dbpl[1])).select_related( 'period', 'pla', 'plb').order_by('-date', 'id'), fix_left=dbpl[0], ) # }}} postable_match(base, request) return render_to_response('pred_match.djhtml', base)
def events(request, event_id=None): # {{{ Get base context, redirect if necessary if 'goto' in request.GET: return redirect('/results/events/' + request.GET['goto']) base = base_ctx('Results', 'By Event', request) # }}} # {{{ Display the main table if event ID is not given if event_id is None: root_events = ( Event.objects .annotate(num_uplinks=Count("uplink")) .filter(num_uplinks=1) .order_by('name') .only('id', 'name', 'big', 'category', 'fullname') ) base.update({ 'ind_bigs': collect(root_events.filter(big=True, category=CAT_INDIVIDUAL), 2), 'ind_smalls': root_events.filter(big=False, category=CAT_INDIVIDUAL).order_by('name'), 'team_bigs': collect(root_events.filter(big=True, category=CAT_TEAM), 2), 'team_smalls': root_events.filter(big=False, category=CAT_TEAM).order_by('name'), 'freq_bigs': collect(root_events.filter(big=True, category=CAT_FREQUENT), 2), 'freq_smalls': root_events.filter(big=False, category=CAT_FREQUENT).order_by('name'), }) return render_to_response('events.html', base) # }}} # {{{ Get object, generate messages, and ensure big is set. Find familial relationships. event = get_object_or_404(Event, id=event_id) base['messages'] += generate_messages(event) matches = event.get_matchset() if matches.count() > 200 and not event.big: event.set_big(True) base.update({ 'event': event, 'siblings': event.get_parent().get_immediate_children().exclude(id=event.id) if event.get_parent() else None, 'path': event.get_ancestors(id=True), 'children': event.get_immediate_children(), }) # }}} # {{{ Make forms if base['adm']: def check_form(formname, cl, check): if request.method == 'POST' and check in request.POST: f = cl(request=request, event=event) base['messages'] += f.update_event(event) else: f = cl(event=event) base[formname] = f check_form('form', EventModForm, 'modevent') check_form('addform', AddForm, 'addevent') if event.has_children(): check_form('reorderform', ReorderForm, 'reorder') if event.type == TYPE_EVENT: check_form('ppform', PrizepoolModForm, 'modpp') if not event.has_children() and event.get_immediate_matchset().exists(): check_form('stform', StoryModForm, 'modstories') # }}} # {{{ Prizepool information for the public total_earnings = Earnings.objects.filter(event__uplink__parent=event) currencies = list({r['currency'] for r in total_earnings.values('currency').distinct()}) base.update({ 'prizepool': total_earnings.aggregate(Sum('earnings'))['earnings__sum'], 'nousdpp': len(currencies) > 1 or len(currencies) == 1 and currencies[0] != 'USD', 'prizepoolorig': [{ 'pp': total_earnings.filter(currency=k).aggregate(Sum('origearnings'))['origearnings__sum'], 'cur': k, } for k in currencies], }) # }}} # {{{ Other easy statistics base.update({ 'game': etn(lambda: dict(Match.GAMES)[matches.values('game').distinct()[0]['game']]), 'offline': etn(lambda: matches.values('offline').distinct()[0]['offline']), 'nmatches': matches.count(), 'ngames': sum(count_winloss_games(matches)), 'pvp_games': count_mirror_games(matches, 'P'), 'tvt_games': count_mirror_games(matches, 'T'), 'zvz_games': count_mirror_games(matches, 'Z'), 'matches': display_matches( matches.prefetch_related('message_set') .prefetch_related('pla', 'plb', 'eventobj') .annotate(Count('eventobj__match')) .order_by('-eventobj__latest', '-eventobj__idx', '-date', '-id')[0:200], eventcount=True, ), 'nplayers': Player.objects.filter( Q(id__in=matches.values('pla')) | Q(id__in=matches.values('plb')) ).count(), }) base['pvt_wins'], base['pvt_loss'] = count_matchup_games(matches, 'P', 'T') base['pvz_wins'], base['pvz_loss'] = count_matchup_games(matches, 'P', 'Z') base['tvz_wins'], base['tvz_loss'] = count_matchup_games(matches, 'T', 'Z') base['tot_mirror'] = base['pvp_games'] + base['tvt_games'] + base['zvz_games'] # }}} base.update({"title": event}) return render_to_response('eventres.html', base)
def results(request, player_id): # {{{ Get objects player = get_object_or_404(Player, id=player_id) base = base_ctx('Ranking', 'Match history', request, context=player) base['player'] = player # }}} # {{{ Filtering matches = player.get_matchset(related=['pla', 'plb', 'eventobj']) form = ResultsFilterForm(request.GET) base['form'] = form form.is_valid() q = Q() for r in form.cleaned_data['race'].upper(): q |= Q(pla=player, rcb=r) | Q(plb=player, rca=r) matches = matches.filter(q) if form.cleaned_data['country'] == 'foreigners': matches = matches.exclude( Q(pla=player, plb__country='KR') | Q(plb=player, pla__country='KR')) elif form.cleaned_data['country'] != 'all': matches = matches.filter( Q(pla=player, plb__country=form.cleaned_data['country']) | Q(plb=player, pla__country=form.cleaned_data['country'])) if form.cleaned_data['bestof'] != 'all': sc = int(form.cleaned_data['bestof']) // 2 + 1 matches = matches.filter(Q(sca__gte=sc) | Q(scb__gte=sc)) if form.cleaned_data['offline'] != 'both': matches = matches.filter( offline=(form.cleaned_data['offline'] == 'offline')) if form.cleaned_data['game'] != 'all': matches = matches.filter(game=form.cleaned_data['game']) if form.cleaned_data['wcs_season'] != '': if form.cleaned_data['wcs_season'] == 'all': matches = matches.filter( eventobj__uplink__parent__wcs_year__isnull=False) else: matches = matches.filter(eventobj__uplink__parent__wcs_year=int( form.cleaned_data['wcs_season'])) if form.cleaned_data['wcs_tier'] != '': tiers = list(map(int, form.cleaned_data['wcs_tier'])) matches = matches.filter(eventobj__uplink__parent__wcs_tier__in=tiers) if form.cleaned_data['after'] is not None: matches = matches.filter(date__gte=form.cleaned_data['after']) if form.cleaned_data['before'] is not None: matches = matches.filter(date__lte=form.cleaned_data['before']) if form.cleaned_data['event'] is not None: lex = shlex.shlex(form.cleaned_data['event'], posix=True) lex.wordchars += "'" lex.quotes = '"' terms = [s.strip() for s in list(lex) if s.strip() != ''] matches = matches.filter(eventobj__fullname__iregex=(r"\s".join( r".*{}.*".format(term) for term in terms))) matches = matches.distinct() # }}} # {{{ Statistics disp_matches = display_matches(matches, fix_left=player) base['matches'] = disp_matches base.update({ 'sc_my': sum(m['pla']['score'] for m in base['matches']), 'sc_op': sum(m['plb']['score'] for m in base['matches']), 'msc_my': sum(1 for m in base['matches'] if m['pla']['score'] > m['plb']['score']), 'msc_op': sum(1 for m in base['matches'] if m['plb']['score'] > m['pla']['score']), }) recent = matches.filter(date__gte=(date.today() - relativedelta(months=2))) base.update({ 'total': count_winloss_player(matches, player), 'vp': count_matchup_player(matches, player, P), 'vt': count_matchup_player(matches, player, T), 'vz': count_matchup_player(matches, player, Z), 'totalf': count_winloss_player(recent, player), 'vpf': count_matchup_player(recent, player, P), 'vtf': count_matchup_player(recent, player, T), 'vzf': count_matchup_player(recent, player, Z) }) # }}} # {{{ TL Postable has_after = form.cleaned_data['after'] is not None has_before = form.cleaned_data['before'] is not None if not has_after and not has_before: match_date = "" elif not has_after: # and has_before match_date = _(" before {}").format(form.cleaned_data['before']) elif not has_before: # and has_after match_date = _(" after {}").format(form.cleaned_data['after']) else: match_date = _(" between {} and {}").format( form.cleaned_data['after'], form.cleaned_data['before']) match_filter = "" def switcher(race): if race == "S": return "R" elif race == "s": return "r" return race def win(match): return match['pla']['score'] >= match['plb']['score'] def format_match(d): # TL only recognizes lower case country codes :( if d["pla"]["country"] is not None: d["pla_country_formatted"] = ":{}:".format( d["pla"]["country"].lower()) else: d["pla_country_formatted"] = "" if d["plb"]["country"] is not None: d["plb_country_formatted"] = ":{}:".format( d["plb"]["country"].lower()) else: d["plb_country_formatted"] = "" # and no race switchers d["pla_race"] = switcher(d["pla"]["race"]) d["plb_race"] = switcher(d["plb"]["race"]) # Check who won temp = {"plaws": "", "plawe": "", "plbws": "", "plbwe": ""} if win(d): temp["plaws"] = "[b]" temp["plawe"] = "[/b]" else: temp["plbws"] = "[b]" temp["plbwe"] = "[/b]" d.update(temp) d["pla_id"] = d["pla"]["id"] d["pla_tag"] = d["pla"]["tag"] d["pla_score"] = d["pla"]["score"] d["plb_id"] = d["plb"]["id"] d["plb_tag"] = d["plb"]["tag"] d["plb_score"] = d["plb"]["score"] return TL_HISTORY_MATCH_TEMPLATE.format(**d) recent_matches = disp_matches[:min(10, len(disp_matches))] recent = "\n".join(format_match(m) for m in recent_matches) recent_form = " ".join("W" if win(m) else "L" for m in reversed(recent_matches)) # Get the parameters and remove those with None value get_params = dict((k, form.cleaned_data[k]) for k in form.cleaned_data if form.cleaned_data[k] is not None) country = "" if player.country is not None: country = ":{}:".format(player.country.lower()) tl_params = { "player_tag": player.tag, "player_country_formatted": country, "player_race": switcher(player.race), "filter": match_filter, "date": match_date, "recent": recent, "pid": player_id, "get": urlencode(get_params), "url": "http://aligulac.com" } tl_params.update({ "sc_my": base["sc_my"], "sc_op": base["sc_op"], "msc_my": base["msc_my"], "msc_op": base["msc_op"], "form": recent_form }) def calc_percent(s): f, a = float(int(tl_params[s + "_my"])), int(tl_params[s + "_op"]) if f + a == 0: return " NaN" return round(100 * f / (f + a), 2) tl_params.update({ "sc_percent": calc_percent("sc"), "msc_percent": calc_percent("msc") }) tl_params.update(get_params) # Final clean up and translation if tl_params["bestof"] != "all": tl_params["bestof"] = _('best of') + ' {}'.format(tl_params["bestof"]) else: tl_params['bestof'] = _('all') if set(tl_params["race"]) == set('ptzr'): tl_params["race"] = _('all') else: tl_params['race'] = { 'p': _('Protoss'), 't': _('Terran'), 'z': _('Zerg'), 'ptr': _('No Zerg'), 'pzr': _('No Terran'), 'tzr': _('No Protoss'), }[tl_params['race']] if tl_params['country'] in ['all', 'foreigners']: tl_params['country'] = { 'all': _('all'), 'foreigners': _('foreigners'), }[tl_params['country']] else: tl_params['country'] = transformations.ccn_to_cn( transformations.cca2_to_ccn(tl_params['country'])) tl_params['offline'] = { 'offline': _('offline'), 'online': _('online'), 'both': _('both'), }[tl_params['offline']] if tl_params['game'] == 'all': tl_params['game'] = _('all') else: tl_params['game'] = dict(GAMES)[tl_params['game']] tl_params.update({ 'resfor': _('Results for'), 'games': _('Games'), 'matches': _('Matches'), 'curform': _('Current form'), 'recentmatches': _('Recent matches'), 'filters': _('Filters'), # Translators: These have to line up on the right! 'opprace': _('Opponent Race: '), # Translators: These have to line up on the right! 'oppcountry': _('Opponent Country: '), # Translators: These have to line up on the right! 'matchformat': _('Match Format: '), # Translators: These have to line up on the right! 'onoff': _('On/offline: '), # Translators: These have to line up on the right! 'version': _('Game Version: '), 'statslink': _('Stats by [url={url}]Aligulac[/url]'), # Translators: Link in the sense of a HTTP hyperlink. 'link': _('Link'), }) base.update({ # One of the replacement strings contain another string interpolation, # so do it twice. "postable_tl": TL_HISTORY_TEMPLATE.format(**tl_params).format(**tl_params) }) # }}} return render_to_response('player_results.djhtml', base)
def review(request): base = base_ctx('Submit', 'Review', request) if not base['adm']: base.update(csrf(request)) return render_to_response('login.html', base) add_login_message(base) base['events'] = Event.objects.filter(closed=False, rgt=F('lft')+1).order_by('lft') if 'act' in request.POST and base['adm'] == True: if int(request.POST['eobj']) != 2: eobj = Event.objects.get(id=int(request.POST['eobj'])) base['eobj'] = eobj.id delete = True if request.POST['act'] == 'reject' else False success = [] ndel = 0 for key in sorted(request.POST.keys()): if request.POST[key] != 'y': continue if key[0:6] == 'match-': pm = PreMatch.objects.get(id=int(key.split('-')[-1])) if delete: group = pm.group pm.delete() if not group.prematch_set.all().exists(): group.delete() ndel += 1 continue if pm.pla == None: pm.pla_string = request.POST['match-%i-pla' % pm.id] if pm.plb == None: pm.plb_string = request.POST['match-%i-plb' % pm.id] if pm.pla == None or pm.plb == None: review_treat_players(pm, base) if pm.pla and not pm.rca: pm.pla = None if pm.plb and not pm.rcb: pm.plb = None pm.save() if pm.pla and pm.plb and pm.rca and pm.rcb: m = Match() m.pla = pm.pla m.plb = pm.plb m.sca = pm.sca m.scb = pm.scb m.rca = pm.rca m.rcb = pm.rcb if request.POST['date'].strip() == '': m.date = pm.group.date else: m.date = request.POST['date'] m.event = pm.group.event m.eventobj = eobj m.submitter = request.user m.set_period() m.offline = pm.group.offline m.game = pm.group.game m.save() success.append(m) group = pm.group pm.delete() if not group.prematch_set.all().exists(): group.delete() base['success'] = display_matches(success, messages=False) if len(success) > 0: base['messages'].append(Message('Approved %i match(es).' % len(success), type=Message.SUCCESS)) if ndel > 0: base['messages'].append(Message('Rejected %i match(es).' % ndel, type=Message.SUCCESS)) groups = PreMatchGroup.objects.filter(prematch__isnull=False)\ .select_related('prematch').order_by('id', 'event').distinct() for g in groups: g.prematches = display_matches(g.prematch_set.all(), messages=False) base['groups'] = groups base.update(csrf(request)) return render_to_response('review.html', base)
def events(request, event_id=None): # {{{ Get base context, redirect if necessary if 'goto' in request.GET: return redirect('/results/events/' + request.GET['goto']) base = base_ctx('Results', 'By Event', request) # }}} # {{{ Display the main table if event ID is not given if event_id is None: root_events = ( Event.objects .annotate(num_uplinks=Count("uplink")) .filter(num_uplinks=1) .order_by('name') .only('id', 'name', 'big', 'category', 'fullname') ) base.update({ 'bigs': ( list(root_events.filter(big=True, category=CAT_INDIVIDUAL)) + list(root_events.filter(big=True, category=CAT_TEAM)) + list(root_events.filter(big=True, category=CAT_FREQUENT)) ), 'smalls': ( list(root_events.filter(big=False, category=CAT_INDIVIDUAL).order_by('name')) + list(root_events.filter(big=False, category=CAT_TEAM).order_by('name')) + list(root_events.filter(big=False, category=CAT_FREQUENT).order_by('name')) ) }) base['messages'].append(Message( _('The events are organized in a hierarchical fashion. Thus, all GSL tournaments ' 'are filed under GSL, all Code S under their respective seasons, all groups under ' 'their respective Code S event, and so on.'), type=Message.INFO )) return render_to_response('events.djhtml', base) # }}} # {{{ Get object, generate messages, and ensure big is set. Find familial relationships. event = get_object_or_404(Event, id=event_id) base['messages'] += generate_messages(event) matches = event.get_matchset() if matches.count() > 200 and not event.big: event.set_big(True) base.update({ 'event': event, 'siblings': event.get_parent().get_immediate_children().exclude(id=event.id) if event.get_parent() else None, 'path': event.get_ancestors(id=True), 'children': event.get_immediate_children(), }) # }}} # {{{ Make forms if base['adm']: def check_form(formname, cl, check): if request.method == 'POST' and check in request.POST: f = cl(request=request, event=event) base['messages'] += f.update_event(event) else: f = cl(event=event) base[formname] = f check_form('form', EventModForm, 'modevent') check_form('addform', AddForm, 'addevent') if event.has_children(): check_form('reorderform', ReorderForm, 'reorder') if event.type == TYPE_EVENT: check_form('ppform', PrizepoolModForm, 'modpp') check_form('wcsform', WCSModForm, 'modwcs') if not event.has_children() and event.get_immediate_matchset().exists(): check_form('stform', StoriesForm, 'modstory') if 'close' in request.GET and request.GET['close'] == '1': event.close() base['messages'].append(Message(_('Sucessfully closed event.'), type=Message.SUCCESS)) # }}} # {{{ Prizepool information for the public total_earnings = Earnings.objects.filter(event__uplink__parent=event) local_earnings = Earnings.objects.filter(event=event) ranked_prize = local_earnings.exclude(placement=0)\ .order_by('-earnings', 'placement') unranked_prize = list( local_earnings.filter(placement=0).order_by('-earnings') ) placements = get_placements(event) prize_pool_table = list() for k, g in groupby(ranked_prize, key=lambda x: x.earnings): gl = list(g) prize_pool_table.append((k, placements[k], gl, len(gl))) if len(prize_pool_table) > 0: base['ranked_prize'] = prize_pool_table if len(unranked_prize) > 0: base['unranked_prize'] = unranked_prize currencies = list({r['currency'] for r in total_earnings.values('currency').distinct()}) base.update({ 'prizepool': total_earnings.aggregate(Sum('earnings'))['earnings__sum'], 'nousdpp': len(currencies) > 1 or len(currencies) == 1 and currencies[0] != 'USD', 'prizepoolorig': [{ 'pp': total_earnings.filter(currency=k).aggregate(Sum('origearnings'))['origearnings__sum'], 'cur': k, } for k in currencies], }) # }}} # {{{ Other easy statistics add_links = request.user.is_authenticated() and request.user.is_staff base.update({ 'game': etn(lambda: dict(GAMES)[matches.values('game').distinct()[0]['game']]), 'nmatches': matches.count(), 'ngames': sum(count_winloss_games(matches)), 'pvp_games': count_mirror_games(matches, 'P'), 'tvt_games': count_mirror_games(matches, 'T'), 'zvz_games': count_mirror_games(matches, 'Z'), 'matches': display_matches( matches.prefetch_related('message_set') .prefetch_related('pla', 'plb', 'eventobj') .annotate(Count('eventobj__match')) .order_by('-eventobj__latest', '-eventobj__idx', '-date', '-id')[0:200], eventcount=True, add_links=add_links ), 'nplayers': Player.objects.filter( Q(id__in=matches.values('pla')) | Q(id__in=matches.values('plb')) ).count(), }) offlines = list(matches.values('offline').distinct()) if len(offlines) > 1: base['offline'] = _('Both') elif len(offlines) == 1: base['offline'] = _('Offline') if offlines[0]['offline'] else _('Online') base['pvt_wins'], base['pvt_loss'] = count_matchup_games(matches, 'P', 'T') base['pvz_wins'], base['pvz_loss'] = count_matchup_games(matches, 'P', 'Z') base['tvz_wins'], base['tvz_loss'] = count_matchup_games(matches, 'T', 'Z') base['tot_mirror'] = base['pvp_games'] + base['tvt_games'] + base['zvz_games'] # }}} return render_to_response('eventres.djhtml', base)
def player(request, player_id): player = get_object_or_404(Player, id=player_id) base = base_ctx('Ranking', '%s:' % player.tag, request, context=player) base.update(csrf(request)) # Make modifications if 'op' in request.POST and request.POST['op'] == 'Submit' and base['adm'] == True: tag = request.POST['tag'] country = request.POST['country'] name = request.POST['fullname'] if name == '': name = None akas = request.POST['AKA'] if akas != '': aka = [s for s in akas.split(',')] else: aka = None birthday = request.POST['birthday'] if birthday == '': birthday = None sc2c = request.POST['SC2C'] if sc2c == '': sc2c = None tlpdkr = request.POST['TLPDKR'] if tlpdkr == '': tlpdkr = None tlpdin = request.POST['TLPDIN'] if tlpdin == '': tlpdin = None sc2e = request.POST['SC2E'] if sc2e == '': sc2e = None lp = request.POST['LP'] if lp == '': lp = None if tag != '': player.set_tag(tag) player.set_country(country) player.set_name(name) player.set_birthday(birthday) player.set_aliases(aka) player.update_external_links(sc2c, tlpdkr, tlpdin, sc2e, lp) countries = [] for k, v in data.ccn_to_cn.iteritems(): countries.append([k, v, data.ccn_to_cca2[k]]) countries.sort(key=lambda a: a[1]) base['countries'] = countries try: base['team'] = Team.objects.filter(active=True, teammembership__player=player, teammembership__current=True)[0] except: pass try: base['first'] = Match.objects.filter(Q(pla=player) | Q(plb=player)).order_by('date')[0] base['last'] = Match.objects.filter(Q(pla=player) | Q(plb=player)).order_by('-date')[0] except: pass base['totalmatches'] = Match.objects.filter(Q(pla=player) | Q(plb=player)).count() base['offlinematches'] = Match.objects.filter(Q(pla=player) | Q(plb=player), offline=True).count() base['aliases'] = Alias.objects.filter(player=player) earnings = Earnings.objects.filter(player=player) base['earnings'] = earnings.aggregate(Sum('earnings'))['earnings__sum'] # Winrates matches_a = Match.objects.filter(pla=player) matches_b = Match.objects.filter(plb=player) def ntz(n): return n if n is not None else 0 a = matches_a.aggregate(Sum('sca'), Sum('scb')) b = matches_b.aggregate(Sum('sca'), Sum('scb')) base['total'] = (ntz(a['sca__sum']) + ntz(b['scb__sum']), ntz(a['scb__sum']) + ntz(b['sca__sum'])) a = matches_a.filter(rcb='P').aggregate(Sum('sca'), Sum('scb')) b = matches_b.filter(rca='P').aggregate(Sum('sca'), Sum('scb')) base['vp'] = (ntz(a['sca__sum']) + ntz(b['scb__sum']), ntz(a['scb__sum']) + ntz(b['sca__sum'])) a = matches_a.filter(rcb='T').aggregate(Sum('sca'), Sum('scb')) b = matches_b.filter(rca='T').aggregate(Sum('sca'), Sum('scb')) base['vt'] = (ntz(a['sca__sum']) + ntz(b['scb__sum']), ntz(a['scb__sum']) + ntz(b['sca__sum'])) a = matches_a.filter(rcb='Z').aggregate(Sum('sca'), Sum('scb')) b = matches_b.filter(rca='Z').aggregate(Sum('sca'), Sum('scb')) base['vz'] = (ntz(a['sca__sum']) + ntz(b['scb__sum']), ntz(a['scb__sum']) + ntz(b['sca__sum'])) # Career highs try: base['highs'] = (Rating.objects.filter(player=player).order_by('-rating')[0],\ Rating.objects.filter(player=player).extra(select={'d':'rating+rating_vp'}).order_by('-d')[0],\ Rating.objects.filter(player=player).extra(select={'d':'rating+rating_vt'}).order_by('-d')[0],\ Rating.objects.filter(player=player).extra(select={'d':'rating+rating_vz'}).order_by('-d')[0]) except: pass try: countryfull = transformations.cc_to_cn(player.country) except: countryfull = '' rating = Rating.objects.filter(player=player).order_by('period').select_related('period') base['charts'] = rating.count >= 2 if base['charts']: try: last_adjust = Rating.objects.filter(player=player, decay=0).order_by('-period')[0] rating = rating.filter(period_id__lte=last_adjust.period_id) except: pass base['ratings'] = rating base['patches'] = PATCHES recentchange = Rating.objects.filter(player=player, decay=0).order_by('-period') if recentchange.exists(): base['recentchange'] = recentchange[0] firstrating = Rating.objects.filter(player=player).order_by('period') if firstrating.exists(): base['firstrating'] = firstrating[0] if not rating.exists(): base.update({'player': player, 'countryfull': countryfull}) return render_to_response('player.html', base) rating = rating.order_by('-period')[0] matches = Match.objects.filter(Q(pla=player) | Q(plb=player))\ .select_related('pla__rating').select_related('plb__rating')\ .select_related('period')\ .extra(where=['abs(datediff(date,\'%s\')) < 90' % datetime.datetime.now()])\ .order_by('-date', '-id')[0:10] if matches.exists(): base['matches'] = display_matches(matches, fix_left=player, ratings=True) def meandate(tm): if tm.start != None and tm.end != None: return (tm.start.toordinal() + tm.end.toordinal())/2 elif tm.start != None: return tm.start.toordinal() elif tm.end != None: return tm.end.toordinal() else: return 1000000 teammems = list(TeamMembership.objects.filter(player=player).extra(select={'mid': '(start+end)/2'})) teammems = sorted(teammems, key=lambda t: t.id, reverse=True) teammems = sorted(teammems, key=meandate, reverse=True) teammems = sorted(teammems, key=lambda t: t.current, reverse=True) base.update({'player': player, 'countryfull': countryfull, 'rating': rating, 'teammems': teammems}) return render_to_response('player.html', base)
def results(request, player_id): # {{{ Get objects player = get_object_or_404(Player, id=player_id) base = base_ctx("Ranking", "Match history", request, context=player) base["player"] = player # }}} # {{{ Filtering matches = player.get_matchset(related=["pla", "plb", "eventobj"]) form = ResultsFilterForm(request.GET) base["form"] = form form.is_valid() q = Q() for r in form.cleaned_data["race"].upper(): q |= Q(pla=player, rcb=r) | Q(plb=player, rca=r) matches = matches.filter(q) if form.cleaned_data["country"] == "foreigners": matches = matches.exclude(Q(pla=player, plb__country="KR") | Q(plb=player, pla__country="KR")) elif form.cleaned_data["country"] != "all": matches = matches.filter( Q(pla=player, plb__country=form.cleaned_data["country"]) | Q(plb=player, pla__country=form.cleaned_data["country"]) ) if form.cleaned_data["bestof"] != "all": sc = int(form.cleaned_data["bestof"]) // 2 + 1 matches = matches.filter(Q(sca__gte=sc) | Q(scb__gte=sc)) if form.cleaned_data["offline"] != "both": matches = matches.filter(offline=(form.cleaned_data["offline"] == "offline")) if form.cleaned_data["game"] != "all": matches = matches.filter(game=form.cleaned_data["game"]) if form.cleaned_data["after"] is not None: matches = matches.filter(date__gte=form.cleaned_data["after"]) if form.cleaned_data["before"] is not None: matches = matches.filter(date__lte=form.cleaned_data["before"]) if form.cleaned_data["event"] is not None: lex = shlex.shlex(form.cleaned_data["event"], posix=True) lex.wordchars += "'" lex.quotes = '"' terms = [s.strip() for s in list(lex) if s.strip() != ""] matches = matches.filter(eventobj__fullname__iregex=(r"\s".join(r".*{}.*".format(term) for term in terms))) # }}} # {{{ Statistics disp_matches = display_matches(matches, fix_left=player) base["matches"] = disp_matches base.update( { "sc_my": sum(m["pla"]["score"] for m in base["matches"]), "sc_op": sum(m["plb"]["score"] for m in base["matches"]), "msc_my": sum(1 for m in base["matches"] if m["pla"]["score"] > m["plb"]["score"]), "msc_op": sum(1 for m in base["matches"] if m["plb"]["score"] > m["pla"]["score"]), } ) recent = matches.filter(date__gte=(date.today() - relativedelta(months=2))) base.update( { "total": count_winloss_player(matches, player), "vp": count_matchup_player(matches, player, P), "vt": count_matchup_player(matches, player, T), "vz": count_matchup_player(matches, player, Z), "totalf": count_winloss_player(recent, player), "vpf": count_matchup_player(recent, player, P), "vtf": count_matchup_player(recent, player, T), "vzf": count_matchup_player(recent, player, Z), } ) # }}} # {{{ TL Postable has_after = form.cleaned_data["after"] is not None has_before = form.cleaned_data["before"] is not None if not has_after and not has_before: match_date = "" elif not has_after: # and has_before match_date = _(" before {}").format(form.cleaned_data["before"]) elif not has_before: # and has_after match_date = _(" after {}").format(form.cleaned_data["after"]) else: match_date = _(" between {} and {}").format(form.cleaned_data["after"], form.cleaned_data["before"]) match_filter = "" def switcher(race): if race == "S": return "R" elif race == "s": return "r" return race def win(match): return match["pla"]["score"] >= match["plb"]["score"] def format_match(d): # TL only recognizes lower case country codes :( if d["pla"]["country"] is not None: d["pla_country_formatted"] = ":{}:".format(d["pla"]["country"].lower()) else: d["pla_country_formatted"] = "" if d["plb"]["country"] is not None: d["plb_country_formatted"] = ":{}:".format(d["plb"]["country"].lower()) else: d["plb_country_formatted"] = "" # and no race switchers d["pla_race"] = switcher(d["pla"]["race"]) d["plb_race"] = switcher(d["plb"]["race"]) # Check who won temp = {"plaws": "", "plawe": "", "plbws": "", "plbwe": ""} if win(d): temp["plaws"] = "[b]" temp["plawe"] = "[/b]" else: temp["plbws"] = "[b]" temp["plbwe"] = "[/b]" d.update(temp) d["pla_id"] = d["pla"]["id"] d["pla_tag"] = d["pla"]["tag"] d["pla_score"] = d["pla"]["score"] d["plb_id"] = d["plb"]["id"] d["plb_tag"] = d["plb"]["tag"] d["plb_score"] = d["plb"]["score"] return TL_HISTORY_MATCH_TEMPLATE.format(**d) recent_matches = disp_matches[: min(10, len(disp_matches))] recent = "\n".join(format_match(m) for m in recent_matches) recent_form = " ".join("W" if win(m) else "L" for m in reversed(recent_matches)) # Get the parameters and remove those with None value get_params = dict((k, form.cleaned_data[k]) for k in form.cleaned_data if form.cleaned_data[k] is not None) country = "" if player.country is not None: country = ":{}:".format(player.country.lower()) tl_params = { "player_tag": player.tag, "player_country_formatted": country, "player_race": switcher(player.race), "filter": match_filter, "date": match_date, "recent": recent, "pid": player_id, "get": urlencode(get_params), "url": "http://aligulac.com", } tl_params.update( { "sc_my": base["sc_my"], "sc_op": base["sc_op"], "msc_my": base["msc_my"], "msc_op": base["msc_op"], "form": recent_form, } ) def calc_percent(s): f, a = float(int(tl_params[s + "_my"])), int(tl_params[s + "_op"]) if f + a == 0: return " NaN" return round(100 * f / (f + a), 2) tl_params.update({"sc_percent": calc_percent("sc"), "msc_percent": calc_percent("msc")}) tl_params.update(get_params) # Final clean up and translation if tl_params["bestof"] != "all": tl_params["bestof"] = _("best of") + " {}".format(tl_params["bestof"]) else: tl_params["bestof"] = _("all") if set(tl_params["race"]) == set("ptzr"): tl_params["race"] = _("all") else: tl_params["race"] = { "p": _("Protoss"), "t": _("Terran"), "z": _("Zerg"), "ptr": _("No Zerg"), "pzr": _("No Terran"), "tzr": _("No Protoss"), }[tl_params["race"]] if tl_params["country"] in ["all", "foreigners"]: tl_params["country"] = {"all": _("all"), "foreigners": _("foreigners")}[tl_params["country"]] else: tl_params["country"] = transformations.ccn_to_cn(transformations.cca2_to_ccn(tl_params["country"])) tl_params["offline"] = {"offline": _("offline"), "online": _("online"), "both": _("both")}[tl_params["offline"]] if tl_params["game"] == "all": tl_params["game"] = _("all") else: tl_params["game"] = dict(GAMES)[tl_params["game"]] tl_params.update( { "resfor": _("Results for"), "games": _("Games"), "matches": _("Matches"), "curform": _("Current form"), "recentmatches": _("Recent matches"), "filters": _("Filters"), # Translators: These have to line up on the right! "opprace": _("Opponent Race: "), # Translators: These have to line up on the right! "oppcountry": _("Opponent Country: "), # Translators: These have to line up on the right! "matchformat": _("Match Format: "), # Translators: These have to line up on the right! "onoff": _("On/offline: "), # Translators: These have to line up on the right! "version": _("Game Version: "), "statslink": _("Stats by [url={url}]Aligulac[/url]"), # Translators: Link in the sense of a HTTP hyperlink. "link": _("Link"), } ) base.update( { # One of the replacement strings contain another string interpolation, # so do it twice. "postable_tl": TL_HISTORY_TEMPLATE.format(**tl_params).format(**tl_params) } ) # }}} return render_to_response("player_results.djhtml", base)
def add_matches(request): # This view is the default redirect for login requests if 'username' in request.POST and 'password' in request.POST: user = authenticate(username=request.POST['username'], password=request.POST['password']) if user != None and user.is_active: login(request, user) base = base_ctx('Submit', 'Matches', request) add_login_message(base, extra='Submitted results will be pending review before inclusion.') # If the user is logged in, the template needs a username and a list of event objects if base['adm']: base['events'] = Event.objects.filter(closed=False, rgt=F('lft')+1).order_by('lft') if 'matches' in request.POST: # Collect various information from the form try: event = request.POST['event'].strip() except: event = None date = request.POST['date'] matches = request.POST['matches'].splitlines() offline = not (request.POST['type'] != 'offline') game = request.POST['game'] if game not in ['WoL', 'HotS']: game = 'WoL' base['game'] = game base['type'] = 'offline' if offline else 'online' base['matches'] = '\n'.join(matches) base['date'] = date base['event'] = event # Get event object. If not admin, an exception will be thrown and eventobj = None. try: eventobj = Event.objects.get(id=int(request.POST['eobj'])) if eventobj.id == 2: eventobj = None except: eventobj = None if eventobj is not None: base['eobj'] = eventobj.id # Get extra data needed if not admin. try: source = request.POST['source'] contact = request.POST['contact'] notes = request.POST['notes'] base['source'] = source base['contact'] = contact base['notes'] = notes except: pass # Check various requirements for non-admins if not base['adm'] and len(matches) > 100: base['messages'].append(Message('Please do not submit more than 100 results at a time.', 'Too many entries', Message.ERROR)) base.update(csrf(request)) return render_to_response('add.html', base) if not base['adm'] and source.strip() == '': base['messages'].append(Message('Please include a source.', 'Source missing', Message.ERROR)) base.update(csrf(request)) return render_to_response('add.html', base) # If not admin, make a PreMatchGroup. if not base['adm']: pmgroup = PreMatchGroup(date=date, event=event, source=source, contact=contact, notes=notes,\ game=game, offline=offline) pmgroup.save() # Lists of successes and failures success = [] failure = [] # Loop through match entries for s in matches: if s.strip() == '': continue try: # Parse and collect the components collect = parse_match(s.strip()) pla = collect[0] plb = collect[1] sca = int(collect[2][0]) scb = int(collect[2][1]) # Check for !DUP and !MAKE switches if user is logged in dup_switch = False make_switch = False while collect[2][-1][0] == '!': if collect[2][-1] == '!MAKE': make_switch = True elif collect[2][-1] == '!DUP': dup_switch = True collect[2] = collect[2][:-1] if not base['adm']: make_switch = False # Check for race overrides def get_race(lst): if lst[-1][:2].upper() == 'R:': r = lst[-1][2:].upper() if lst[-1][2:].upper() in 'PTZR' else None return r, lst[:-1] else: return None, lst rca, pla = get_race(pla) rcb, plb = get_race(plb) # Find players def get_player(lst, failure, base, make, adm): #try: pls = find_player(lst, make=make) #except Exception as e: #failure.append(s) #base['messages'].append(Message('Could not parse: ' + e.message, #s, Message.ERROR)) #return None if not pls.exists() and adm: # Player not found, and user logged in. Add failure message and return None. failure.append(s) base['messages'].append(Message( 'Could not find player \'%s\', add !MAKE switch to create.' % ' '.join(lst), s, Message.ERROR)) return None if pls.count() > 1 and adm: # Too many players found, and used logged in. Add failure message and return None. failure.append(s) base['messages'].append(NotUniquePlayerMessage(' '.join(lst), pls)) return None if not pls.exists() or pls.count() > 1: # Too many or too few players found, and user not logged in. Just return None. return None return pls[0] # If the user is logged in and some players were not found, abort. pla_obj = get_player(pla, failure, base, make_switch, base['adm']) if pla_obj == None and base['adm']: continue plb_obj = get_player(plb, failure, base, make_switch, base['adm']) if plb_obj == None and base['adm']: continue # If both players are known, check for duplicates if pla_obj and plb_obj: n = find_duplicates(pla_obj, plb_obj, sca, scb, date) if n > 0 and not dup_switch: failure.append(s) base['messages'].append(Message( '%i possible duplicate(s) found, add !DUP switch to force.' % n, s, Message.ERROR)) continue # If the user is not logged in, we now have enough information to create a prematch. if not base['adm']: pm = PreMatch(group=pmgroup, sca=sca, scb=scb, pla=pla_obj, plb=plb_obj,\ pla_string=' '.join(pla), plb_string=' '.join(plb), date=pmgroup.date) if rca: pm.rca = rca elif pla_obj: pm.rca = pla_obj.race else: pm.rca = None if rcb: pm.rcb = rcb elif plb_obj: pm.rcb = plb_obj.race else: pm.rcb = None pm.save() success.append(pm) continue # Abort if race information is incorrect if pla_obj.race == 'S' and rca == None: failure.append(s) base['messages'].append(Message( '%s is Random or Switcher, need race information.' % pla_obj.tag, s, Message.ERROR)) continue if plb_obj.race == 'S' and rcb == None: failure.append(s) base['messages'].append(Message( '%s is Random or Switcher, need race information.' % plb_obj.tag, s, Message.ERROR)) continue # Add match m = Match() m.pla = pla_obj m.plb = plb_obj m.sca = sca m.scb = scb m.rca = pla_obj.race if rca == None else rca m.rcb = plb_obj.race if rcb == None else rcb m.date = date m.submitter = request.user m.set_period() m.eventobj = eventobj m.offline = offline m.game = game m.save() success.append(m) except Exception as e: failure.append(s) base['messages'].append(Message('Could not parse: ' + e.message, s, Message.ERROR)) continue success = display_matches(success, messages=False) if len(success) > 0: base['messages'].append(Message('Added %i match(es).' % len(success), type=Message.SUCCESS)) base.update({'matches': '\n'.join(failure), 'success': success}) elif 'eventid' in request.GET: try: event = Event.objects.get(id=int(request.GET['eventid'])) if event.closed: event.closed = False event.save() base['messages'].append(Message('Reopened \'%s\'.' % event.fullname, type=Message.SUCCESS)) base['eobj'] = event.id except: base['messages'].append(Message('Couldn\'t find event ID %s.' % request.GET['eventid'], type=Message.ERROR)) try: if base['adm'] and request.POST['action'] == 'Add and close event' and eventobj is not None: if len(failure) == 0: eventobj.close() base['messages'].append(Message('Event \'%s\' closed.' % eventobj.fullname, type=Message.SUCCESS)) else: base['messages'].append(Message('Event \'%s\' was NOT closed.' % eventobj.fullname, type=Message.WARNING)) except: pass base.update(csrf(request)) return render_to_response('add.html', base)
def results(request, player_id): # {{{ Get objects player = get_object_or_404(Player, id=player_id) base = base_ctx('Ranking', 'Match history', request, context=player) base['player'] = player # }}} # {{{ Filtering matches = player.get_matchset(related=['pla','plb','eventobj']) form = ResultsFilterForm(request.GET) base['form'] = form form.is_valid() q = Q() for r in form.cleaned_data['race'].upper(): q |= Q(pla=player, rcb=r) | Q(plb=player, rca=r) matches = matches.filter(q) if form.cleaned_data['country'] == 'foreigners': matches = matches.exclude(Q(pla=player, plb__country='KR') | Q(plb=player, pla__country='KR')) elif form.cleaned_data['country'] != 'all': matches = matches.filter( Q(pla=player, plb__country=form.cleaned_data['country']) | Q(plb=player, pla__country=form.cleaned_data['country']) ) if form.cleaned_data['bestof'] != 'all': sc = int(form.cleaned_data['bestof'])//2 + 1 matches = matches.filter(Q(sca__gte=sc) | Q(scb__gte=sc)) if form.cleaned_data['offline'] != 'both': matches = matches.filter(offline=(form.cleaned_data['offline']=='offline')) if form.cleaned_data['game'] != 'all': matches = matches.filter(game=form.cleaned_data['game']) if form.cleaned_data['wcs_season'] != '': if form.cleaned_data['wcs_season'] == 'all': matches = matches.filter( eventobj__uplink__parent__wcs_year__isnull=False ) else: matches = matches.filter( eventobj__uplink__parent__wcs_year=int(form.cleaned_data['wcs_season']) ) if form.cleaned_data['wcs_tier'] != '': tiers = list(map(int, form.cleaned_data['wcs_tier'])) matches = matches.filter( eventobj__uplink__parent__wcs_tier__in=tiers ) if form.cleaned_data['after'] is not None: matches = matches.filter(date__gte=form.cleaned_data['after']) if form.cleaned_data['before'] is not None: matches = matches.filter(date__lte=form.cleaned_data['before']) if form.cleaned_data['event'] is not None: lex = shlex.shlex(form.cleaned_data['event'], posix=True) lex.wordchars += "'" lex.quotes = '"' terms = [s.strip() for s in list(lex) if s.strip() != ''] matches = matches.filter( eventobj__fullname__iregex=( r"\s".join(r".*{}.*".format(term) for term in terms) ) ) matches = matches.distinct() # }}} # {{{ Statistics disp_matches = display_matches(matches, fix_left=player) base['matches'] = disp_matches base.update({ 'sc_my': sum(m['pla']['score'] for m in base['matches']), 'sc_op': sum(m['plb']['score'] for m in base['matches']), 'msc_my': sum(1 for m in base['matches'] if m['pla']['score'] > m['plb']['score']), 'msc_op': sum(1 for m in base['matches'] if m['plb']['score'] > m['pla']['score']), }) recent = matches.filter(date__gte=(date.today() - relativedelta(months=2))) base.update({ 'total': count_winloss_player(matches, player), 'vp': count_matchup_player(matches, player, P), 'vt': count_matchup_player(matches, player, T), 'vz': count_matchup_player(matches, player, Z), 'totalf': count_winloss_player(recent, player), 'vpf': count_matchup_player(recent, player, P), 'vtf': count_matchup_player(recent, player, T), 'vzf': count_matchup_player(recent, player, Z) }) # }}} # {{{ TL Postable has_after = form.cleaned_data['after'] is not None has_before = form.cleaned_data['before'] is not None if not has_after and not has_before: match_date = "" elif not has_after: # and has_before match_date = _(" before {}").format(form.cleaned_data['before']) elif not has_before: # and has_after match_date = _(" after {}").format(form.cleaned_data['after']) else: match_date = _(" between {} and {}").format(form.cleaned_data['after'], form.cleaned_data['before']) match_filter = "" def switcher(race): if race == "S": return "R" elif race == "s": return "r" return race def win(match): return match['pla']['score'] >= match['plb']['score'] def format_match(d): # TL only recognizes lower case country codes :( if d["pla"]["country"] is not None: d["pla_country_formatted"] = ":{}:".format(d["pla"]["country"].lower()) else: d["pla_country_formatted"] = "" if d["plb"]["country"] is not None: d["plb_country_formatted"] = ":{}:".format(d["plb"]["country"].lower()) else: d["plb_country_formatted"] = "" # and no race switchers d["pla_race"] = switcher(d["pla"]["race"]) d["plb_race"] = switcher(d["plb"]["race"]) # Check who won temp = { "plaws": "", "plawe": "", "plbws": "", "plbwe": "" } if win(d): temp["plaws"] = "[b]" temp["plawe"] = "[/b]" else: temp["plbws"] = "[b]" temp["plbwe"] = "[/b]" d.update(temp) d["pla_id"] = d["pla"]["id"] d["pla_tag"] = d["pla"]["tag"] d["pla_score"] = d["pla"]["score"] d["plb_id"] = d["plb"]["id"] d["plb_tag"] = d["plb"]["tag"] d["plb_score"] = d["plb"]["score"] return TL_HISTORY_MATCH_TEMPLATE.format(**d) recent_matches = disp_matches[:min(10, len(disp_matches))] recent = "\n".join(format_match(m) for m in recent_matches) recent_form = " ".join("W" if win(m) else "L" for m in reversed(recent_matches)) # Get the parameters and remove those with None value get_params = dict((k, form.cleaned_data[k]) for k in form.cleaned_data if form.cleaned_data[k] is not None) country = "" if player.country is not None: country = ":{}:".format(player.country.lower()) tl_params = { "player_tag": player.tag, "player_country_formatted": country, "player_race": switcher(player.race), "filter": match_filter, "date": match_date, "recent": recent, "pid": player_id, "get": urlencode(get_params), "url": "http://aligulac.com" } tl_params.update({ "sc_my": base["sc_my"], "sc_op": base["sc_op"], "msc_my": base["msc_my"], "msc_op": base["msc_op"], "form": recent_form }) def calc_percent(s): f, a = float(int(tl_params[s+"_my"])), int(tl_params[s+"_op"]) if f + a == 0: return " NaN" return round(100 * f / (f+a), 2) tl_params.update({ "sc_percent": calc_percent("sc"), "msc_percent": calc_percent("msc") }) tl_params.update(get_params) # Final clean up and translation if tl_params["bestof"] != "all": tl_params["bestof"] = _('best of') + ' {}'.format(tl_params["bestof"]) else: tl_params['bestof'] = _('all') if set(tl_params["race"]) == set('ptzr'): tl_params["race"] = _('all') else: tl_params['race'] = { 'p': _('Protoss'), 't': _('Terran'), 'z': _('Zerg'), 'ptr': _('No Zerg'), 'pzr': _('No Terran'), 'tzr': _('No Protoss'), }[tl_params['race']] if tl_params['country'] in ['all', 'foreigners']: tl_params['country'] = { 'all': _('all'), 'foreigners': _('foreigners'), }[tl_params['country']] else: tl_params['country'] = transformations.ccn_to_cn(transformations.cca2_to_ccn(tl_params['country'])) tl_params['offline'] = { 'offline': _('offline'), 'online': _('online'), 'both': _('both'), }[tl_params['offline']] if tl_params['game'] == 'all': tl_params['game'] = _('all') else: tl_params['game'] = dict(GAMES)[tl_params['game']] tl_params.update({ 'resfor': _('Results for'), 'games': _('Games'), 'matches': _('Matches'), 'curform': _('Current form'), 'recentmatches': _('Recent matches'), 'filters': _('Filters'), # Translators: These have to line up on the right! 'opprace': _('Opponent Race: '), # Translators: These have to line up on the right! 'oppcountry': _('Opponent Country: '), # Translators: These have to line up on the right! 'matchformat': _('Match Format: '), # Translators: These have to line up on the right! 'onoff': _('On/offline: '), # Translators: These have to line up on the right! 'version': _('Game Version: '), 'statslink': _('Stats by [url={url}]Aligulac[/url]'), # Translators: Link in the sense of a HTTP hyperlink. 'link': _('Link'), }) base.update({ # One of the replacement strings contain another string interpolation, # so do it twice. "postable_tl": TL_HISTORY_TEMPLATE.format(**tl_params).format(**tl_params) }) # }}} return render_to_response('player_results.djhtml', base)
def adjustment(request, player_id, period_id): # {{{ Get objects period = get_object_or_404(Period, id=period_id, computed=True) player = get_object_or_404(Player, id=player_id) rating = get_object_or_404(Rating, player=player, period=period) base = base_ctx("Ranking", "Adjustments", request, context=player) base.update( { "period": period, "player": player, "rating": rating, "prevlink": etn(lambda: player.rating_set.filter(period__lt=period, decay=0).latest("period")), "nextlink": etn(lambda: player.rating_set.filter(period__gt=period, decay=0).earliest("period")), } ) # }}} # {{{ Matches matches = player.get_matchset(related=["rta", "rtb", "pla", "plb", "eventobj"]).filter(period=period) # If there are no matches, we don't need to continue if not matches.exists(): return render_to_response("ratingdetails.djhtml", base) base.update( { "matches": display_matches(matches, fix_left=player, ratings=True), "has_treated": False, "has_nontreated": False, } ) # }}} # {{{ Perform calculations tot_rating = {"M": 0.0, "P": 0.0, "T": 0.0, "Z": 0.0} ngames = {"M": 0.0, "P": 0.0, "T": 0.0, "Z": 0.0} expwins = {"M": 0.0, "P": 0.0, "T": 0.0, "Z": 0.0} nwins = {"M": 0.0, "P": 0.0, "T": 0.0, "Z": 0.0} for m in base["matches"]: if not m["match"].treated: base["has_nontreated"] = True continue base["has_treated"] = True total_score = m["pla"]["score"] + m["plb"]["score"] scale = sqrt(1 + m["pla"]["dev"] ** 2 + m["plb"]["dev"] ** 2) expected = total_score * cdf(m["pla"]["rating"] - m["plb"]["rating"], scale=scale) ngames["M"] += total_score tot_rating["M"] += m["plb"]["rating"] * total_score expwins["M"] += expected nwins["M"] += m["pla"]["score"] vs_races = [m["plb"]["race"]] if m["plb"]["race"] in "PTZ" else "PTZ" weight = 1 / len(vs_races) for r in vs_races: ngames[r] += weight * total_score tot_rating[r] += weight * m["plb"]["rating"] * total_score expwins[r] += weight * expected nwins[r] += weight * m["pla"]["score"] for r in "MPTZ": if ngames[r] > 0: tot_rating[r] /= ngames[r] base.update({"ngames": ngames, "tot_rating": tot_rating, "expwins": expwins, "nwins": nwins}) # }}} return render_to_response("ratingdetails.djhtml", base)
def adjustment(request, player_id, period_id): # {{{ Get objects period = get_object_or_404(Period, id=period_id, computed=True) player = get_object_or_404(Player, id=player_id) rating = get_object_or_404(Rating, player=player, period=period) base = base_ctx('Ranking', 'Adjustments', request, context=player) base.update({ 'period': period, 'player': player, 'rating': rating, 'prevlink': etn(lambda: player.rating_set.filter(period__lt=period, decay=0).latest('period')), 'nextlink': etn(lambda: player.rating_set.filter(period__gt=period, decay=0).earliest('period')), }) # }}} # {{{ Matches matches = player.get_matchset(related=['rta','rtb','pla','plb','eventobj']).filter(period=period) base.update({"title": player.tag}) # If there are no matches, we don't need to continue if not matches.exists(): return render_to_response('ratingdetails.html', base) base.update({ 'matches': display_matches(matches, fix_left=player, ratings=True), 'has_treated': False, 'has_nontreated': False, }) # }}} # {{{ Perform calculations tot_rating = {'M': 0.0, 'P': 0.0, 'T': 0.0, 'Z': 0.0} ngames = {'M': 0.0, 'P': 0.0, 'T': 0.0, 'Z': 0.0} expwins = {'M': 0.0, 'P': 0.0, 'T': 0.0, 'Z': 0.0} nwins = {'M': 0.0, 'P': 0.0, 'T': 0.0, 'Z': 0.0} for m in base['matches']: if not m['match'].treated: base['has_nontreated'] = True continue base['has_treated'] = True total_score = m['pla']['score'] + m['plb']['score'] scale = sqrt(1 + m['pla']['dev']**2 + m['plb']['dev']**2) expected = total_score * cdf(m['pla']['rating'] - m['plb']['rating'], scale=scale) ngames['M'] += total_score tot_rating['M'] += m['plb']['rating'] * total_score expwins['M'] += expected nwins['M'] += m['pla']['score'] vs_races = [m['plb']['race']] if m['plb']['race'] in 'PTZ' else 'PTZ' weight = 1/len(vs_races) for r in vs_races: ngames[r] += weight * total_score tot_rating[r] += weight * m['plb']['rating'] * total_score expwins[r] += weight * expected nwins[r] += weight * m['pla']['score'] for r in 'MPTZ': if ngames[r] > 0: tot_rating[r] /= ngames[r] base.update({ 'ngames': ngames, 'tot_rating': tot_rating, 'expwins': expwins, 'nwins': nwins, }) # }}} return render_to_response('ratingdetails.html', base)
def search(self, adm): # {{{ Check validity (lol) if not self.is_valid(): msgs = [] msgs.append( Message(_('Entered data was invalid, no changes made.'), type=Message.ERROR)) for field, errors in self.errors.items(): for error in errors: msgs.append( Message(error=error, field=self.fields[field].label)) return {'messages': msgs} # }}} matches = (Match.objects.all().prefetch_related( 'message_set').prefetch_related('pla', 'plb', 'period', 'eventobj').annotate( Count('eventobj__match'))) # {{{ All the easy filtering if self.cleaned_data['after'] is not None: matches = matches.filter(date__gte=self.cleaned_data['after']) if self.cleaned_data['before'] is not None: matches = matches.filter(date__lte=self.cleaned_data['before']) if self.cleaned_data['unassigned'] and adm: matches = matches.filter(eventobj__isnull=True) if self.cleaned_data['bestof'] == '3': matches = matches.filter(Q(sca__gte=2) | Q(scb__gte=2)) elif self.cleaned_data['bestof'] == '5': matches = matches.filter(Q(sca__gte=3) | Q(scb__gte=3)) if self.cleaned_data['offline'] != 'both': matches = matches.filter( offline=(self.cleaned_data['offline'] == 'offline')) if self.cleaned_data['game'] != 'all': matches = matches.filter(game=self.cleaned_data['game']) # }}} # {{{ Filter by event if self.cleaned_data['event'] != None: lex = shlex.shlex(self.cleaned_data['event'], posix=True) lex.wordchars += "'" lex.quotes = '"' terms = [s.strip() for s in list(lex) if s.strip() != ''] no_eventobj_q = Q(eventobj__isnull=True) for term in terms: no_eventobj_q &= Q(event__icontains=term) matches = matches.filter(no_eventobj_q | Q(eventobj__isnull=False, eventobj__fullname__iregex=( r"\s".join(r".*{}.*".format(term) for term in terms)))) # }}} ret = {'messages': []} # {{{ Filter by players lines = self.cleaned_data['players'].splitlines() lineno, ok, players = -1, True, [] for line in lines: lineno += 1 if line.strip() == '': continue pls = find_player(query=line, make=False) if not pls.exists(): ret['messages'].append( Message( # Translators: Matches here as in search matches. _("No matches found: '%s'.") % line.strip(), type=Message.ERROR)) ok = False else: if pls.count() > 1: ret['messages'].append( NotUniquePlayerMessage(line.strip(), pls, update=self['players'].auto_id, updateline=lineno, type=Message.WARNING)) players.append(list(pls)) if not ok: return ret pls = [] for p in players: pls += p if len(pls) > 1: matches = matches.filter(pla__in=pls, plb__in=pls) elif len(pls) == 1: matches = matches.filter(Q(pla__in=pls) | Q(plb__in=pls)) # }}} # {{{ Collect data ret['count'] = matches.count() if ret['count'] > 1000: ret['messages'].append( Message(_('Too many results (%i). Please add restrictions.') % ret['count'], type=Message.ERROR)) return ret matches = matches.order_by('-eventobj__latest', '-eventobj__idx', '-date', 'event', 'id') if 1 <= len(pls) <= 2: ret['matches'] = display_matches(matches, date=True, fix_left=pls[0], eventcount=True) ret['sc_my'], ret['sc_op'] = ( sum([m['pla']['score'] for m in ret['matches']]), sum([m['plb']['score'] for m in ret['matches']]), ) ret['msc_my'], ret['msc_op'] = ( sum([ 1 if m['pla']['score'] > m['plb']['score'] else 0 for m in ret['matches'] ]), sum([ 1 if m['plb']['score'] > m['pla']['score'] else 0 for m in ret['matches'] ]), ) ret['left'] = pls[0] if len(pls) == 2: ret['right'] = pls[1] else: ret['matches'] = display_matches(matches, date=True, eventcount=True) return ret
def results_search(request): base = base_ctx('Results', 'Search', request) base.update(csrf(request)) if 'op' in request.POST and request.POST['op'] == 'Modify' and base['adm'] == True: num = 0 if request.POST['event'] != 'nochange' and int(request.POST['event']) != 2: event = Event.objects.get(id=int(request.POST['event'])) else: event = None for key in request.POST: if request.POST[key] != 'y': continue if key[0:6] == 'match-': match = Match.objects.get(id=int(key.split('-')[-1])) if request.POST['event'] != 'nochange': match.eventobj = event base['markevent'] = event if request.POST['date'].strip() != '': match.date = request.POST['date'] base['markdate'] = request.POST['date'] if request.POST['type'] != 'nochange': match.offline = (request.POST['type'] == 'offline') base['markoffline'] = request.POST['type'] if request.POST['game'] != 'nochange': match.game = request.POST['game'] base['markgame'] = request.POST['game'] match.save() num += 1 base['message'] = 'Modified %i matches.' % num if 'op' in request.GET and request.GET['op'] == 'search': matches = Match.objects.all() try: ints = [int(x) for x in request.GET['after'].split('-')] td = datetime.date(ints[0], ints[1], ints[2]) matches = matches.filter(date__gte=td) base['after'] = request.GET['after'] except: pass try: ints = [int(x) for x in request.GET['before'].split('-')] td = datetime.date(ints[0], ints[1], ints[2]) matches = matches.filter(date__lte=td) base['before'] = request.GET['before'] except: pass if 'unassigned' in request.GET and request.GET['unassigned'] == 'yes' and base['adm']: base['unassigned'] = True base['unassigned_get'] = 'yes' matches = matches.filter(eventobj__isnull=True) if 'eventtext' in request.GET and request.GET['eventtext'].strip() != '': base['eventtext'] = request.GET['eventtext'].strip() queries = [f.strip() for f in request.GET['eventtext'].strip().split(' ') if f.strip() != ''] for query in queries: q = Q(eventobj__isnull=True, event__icontains=query) |\ Q(eventobj__isnull=False, eventobj__fullname__icontains=query) matches = matches.filter(q) if 'bo' in request.GET: if request.GET['bo'] == '3': matches = matches.filter(Q(sca__gte=2) | Q(scb__gte=2)) elif request.GET['bo'] == '5': matches = matches.filter(Q(sca__gte=3) | Q(scb__gte=3)) base['bo'] = request.GET['bo'] else: base['bo'] = 'all' if 'offline' in request.GET: if request.GET['offline'] == 'online': matches = matches.filter(offline=0) elif request.GET['offline'] == 'offline': matches = matches.filter(offline=1) base['offline'] = request.GET['offline'] else: base['offline'] = 'both' if 'game' in request.GET: if request.GET['game'] != 'all': matches = matches.filter(game=request.GET['game']) base['game'] = request.GET['game'] else: base['game'] = 'all' players, failures = [], [] base['errs'] = [] base['pls'] = request.GET['players'] for line in request.GET['players'].splitlines(): if line.strip() == '': continue pls = find_player(line.strip().split(' '), make=False) if not pls.exists(): base['errs'].append('No players matching the query \'%s\'.' % line.strip()) else: players.append(pls) if len(base['errs']) > 0: return render_to_response('results_search.html', base) pls = [] for p in players: pls += p if len(pls) > 1: qa, qb = Q(), Q() for p in pls: qa |= Q(pla=p) qb |= Q(plb=p) matches = matches.filter(qa & qb) elif len(pls) == 1: q = Q(pla=pls[0]) | Q(plb=pls[0]) matches = matches.filter(q) base['count'] = matches.count() if base['count'] > 1000: base['errs'].append('Too many results (%i). Please add restrictions.' % base['count']) return render_to_response('results_search.html', base) matches = matches.order_by('-date', 'eventobj__lft', 'event', 'id') if 1 <= len(pls) <= 2: base['matches'] = display_matches(matches, date=True, fix_left=pls[0]) base['sc_my'] = sum([m.pla_score for m in base['matches']]) base['sc_op'] = sum([m.plb_score for m in base['matches']]) base['msc_my'] = sum([(1 if m.pla_score > m.plb_score else 0) for m in base['matches']]) base['msc_op'] = sum([(1 if m.pla_score < m.plb_score else 0) for m in base['matches']]) base['left'] = pls[0] if len(pls) == 2: base['right'] = pls[1] else: base['matches'] = display_matches(matches, date=True) if base['adm']: base['events'] = Event.objects.filter(closed=False, rgt=F('lft')+1).order_by('lft') return render_to_response('results_search.html', base)
def search(self, adm): # {{{ Check validity (lol) if not self.is_valid(): msgs = [] msgs.append(Message(_('Entered data was invalid, no changes made.'), type=Message.ERROR)) for field, errors in self.errors.items(): for error in errors: msgs.append(Message(error=error, field=self.fields[field].label)) return {'messages': msgs} # }}} matches = ( Match.objects.all().prefetch_related('message_set') .prefetch_related('pla', 'plb', 'period', 'eventobj') .annotate(Count('eventobj__match')) ) # {{{ All the easy filtering if self.cleaned_data['after'] is not None: matches = matches.filter(date__gte=self.cleaned_data['after']) if self.cleaned_data['before'] is not None: matches = matches.filter(date__lte=self.cleaned_data['before']) if self.cleaned_data['unassigned'] and adm: matches = matches.filter(eventobj__isnull=True) if self.cleaned_data['bestof'] == '3': matches = matches.filter(Q(sca__gte=2) | Q(scb__gte=2)) elif self.cleaned_data['bestof'] == '5': matches = matches.filter(Q(sca__gte=3) | Q(scb__gte=3)) if self.cleaned_data['offline'] != 'both': matches = matches.filter(offline=(self.cleaned_data['offline']=='offline')) if self.cleaned_data['game'] != 'all': matches = matches.filter(game=self.cleaned_data['game']) # }}} # {{{ Filter by event if self.cleaned_data['event'] != None: lex = shlex.shlex(self.cleaned_data['event'], posix=True) lex.wordchars += "'" lex.quotes = '"' terms = [s.strip() for s in list(lex) if s.strip() != ''] no_eventobj_q = Q(eventobj__isnull=True) for term in terms: no_eventobj_q &= Q(event__icontains=term) matches = matches.filter( no_eventobj_q | Q( eventobj__isnull=False, eventobj__fullname__iregex=( r"\s".join(r".*{}.*".format(term) for term in terms) ) ) ) # }}} ret = {'messages': []} # {{{ Filter by players lines = self.cleaned_data['players'].splitlines() lineno, ok, players = -1, True, [] for line in lines: lineno += 1 if line.strip() == '': continue pls = find_player(query=line, make=False) if not pls.exists(): ret['messages'].append(Message( # Translators: Matches here as in search matches. _("No matches found: '%s'.") % line.strip(), type=Message.ERROR )) ok = False else: if pls.count() > 1: ret['messages'].append(NotUniquePlayerMessage( line.strip(), pls, update=self['players'].auto_id, updateline=lineno, type=Message.WARNING )) players.append(list(pls)) if not ok: return ret pls = [] for p in players: pls += p if len(pls) > 1: matches = matches.filter(pla__in=pls, plb__in=pls) elif len(pls) == 1: matches = matches.filter(Q(pla__in=pls) | Q(plb__in=pls)) # }}} # {{{ Collect data ret['count'] = matches.count() if ret['count'] > 1000: ret['messages'].append(Message( _('Too many results (%i). Please add restrictions.') % ret['count'], type=Message.ERROR )) return ret matches = matches.order_by('-eventobj__latest', '-eventobj__idx', '-date', 'event', 'id') if 1 <= len(pls) <= 2: ret['matches'] = display_matches(matches, date=True, fix_left=pls[0], eventcount=True) ret['sc_my'], ret['sc_op'] = ( sum([m['pla']['score'] for m in ret['matches']]), sum([m['plb']['score'] for m in ret['matches']]), ) ret['msc_my'], ret['msc_op'] = ( sum([1 if m['pla']['score'] > m['plb']['score'] else 0 for m in ret['matches']]), sum([1 if m['plb']['score'] > m['pla']['score'] else 0 for m in ret['matches']]), ) ret['left'] = pls[0] if len(pls) == 2: ret['right'] = pls[1] else: ret['matches'] = display_matches(matches, date=True, eventcount=True) return ret
def player(request, player_id): # {{{ Get player object and base context, generate messages and make changes if needed player = get_object_or_404(Player, id=player_id) base = base_ctx('Ranking', 'Summary', request, context=player) if request.method == 'POST' and 'modplayer' in request.POST and base['adm']: modform = PlayerModForm(request) base['messages'] += modform.update_player(player) else: modform = PlayerModForm(player=player) base['messages'] += generate_messages(player) # }}} # {{{ Various easy data matches = player.get_matchset() recent = matches.filter(date__gte=(date.today() - relativedelta(months=2))) base.update({ 'player': player, 'modform': modform, 'first': etn(lambda: matches.earliest('date')), 'last': etn(lambda: matches.latest('date')), 'totalmatches': matches.count(), 'offlinematches': matches.filter(offline=True).count(), 'aliases': player.alias_set.all(), 'earnings': ntz(player.earnings_set.aggregate(Sum('earnings'))['earnings__sum']), 'team': player.get_current_team(), 'total': count_winloss_player(matches, player), 'vp': count_matchup_player(matches, player, P), 'vt': count_matchup_player(matches, player, T), 'vz': count_matchup_player(matches, player, Z), 'totalf': count_winloss_player(recent, player), 'vpf': count_matchup_player(recent, player, P), 'vtf': count_matchup_player(recent, player, T), 'vzf': count_matchup_player(recent, player, Z), }) base['riv_nem_vic'] = zip_longest(player.rivals, player.nemesis, player.victim) if player.country is not None: base['countryfull'] = transformations.cc_to_cn(player.country) # }}} # {{{ Recent matches matches = player.get_matchset( related=['rta', 'rtb', 'pla', 'plb', 'eventobj'])[0:10] if matches.exists(): base['matches'] = display_matches(matches, fix_left=player, ratings=True) # }}} # {{{ Team memberships team_memberships = list( player.groupmembership_set.filter( group__is_team=True).select_related('group')) team_memberships.sort(key=lambda t: t.id, reverse=True) team_memberships.sort(key=meandate, reverse=True) team_memberships.sort(key=lambda t: t.current, reverse=True) base['teammems'] = team_memberships # }}} # {{{ If the player has at least one rating if player.current_rating: ratings = total_ratings(player.rating_set.filter( period__computed=True)).select_related('period') base.update({ 'highs': ( ratings.latest('rating'), ratings.latest('tot_vp'), ratings.latest('tot_vt'), ratings.latest('tot_vz'), ), 'recentchange': player.get_latest_rating_update(), 'firstrating': ratings.earliest('period'), 'rating': player.current_rating, }) if player.current_rating.decay >= INACTIVE_THRESHOLD: base['messages'].append( Message(msg_inactive % player.tag, 'Inactive', type=Message.INFO)) base['charts'] = base['recentchange'].period_id > base[ 'firstrating'].period_id else: base['messages'].append( Message(_('%s has no rating yet.') % player.tag, type=Message.INFO)) base['charts'] = False # }}} # {{{ If the player has enough games to make a chart if base['charts']: ratings = (total_ratings( player.rating_set.filter( period_id__lte=base['recentchange'].period_id)).select_related( 'period').prefetch_related('prev__rta', 'prev__rtb').order_by('period')) # {{{ Add stories and other extra information earliest = base['firstrating'] latest = base['recentchange'] # Look through team changes teampoints = [] for mem in base['teammems']: if mem.start and earliest.period.end < mem.start < latest.period.end: teampoints.append({ 'date': mem.start, 'rating': interp_rating(mem.start, ratings), 'data': [{ 'date': mem.start, 'team': mem.group, 'jol': _('joins') }], }) if mem.end and earliest.period.end < mem.end < latest.period.end: teampoints.append({ 'date': mem.end, 'rating': interp_rating(mem.end, ratings), 'data': [{ 'date': mem.end, 'team': mem.group, 'jol': _('leaves') }], }) teampoints.sort(key=lambda p: p['date']) # Condense if team changes happened within 14 days cur = 0 while cur < len(teampoints) - 1: if (teampoints[cur + 1]['date'] - teampoints[cur]['date']).days <= 14: teampoints[cur]['data'].append(teampoints[cur + 1]['data'][0]) del teampoints[cur + 1] else: cur += 1 # Sort first by date, then by joined/left for point in teampoints: point['data'].sort(key=lambda a: a['jol'], reverse=True) point['data'].sort(key=lambda a: a['date']) # Look through stories stories = player.story_set.all().select_related('event') for s in stories: if earliest.period.start < s.date < latest.period.start: s.rating = interp_rating(s.date, ratings) else: s.skip = True # }}} base.update({ 'ratings': add_counts(ratings), 'patches': PATCHES, 'stories': stories, 'teampoints': teampoints, }) else: base['messages'].append( Message(msg_nochart % player.tag, type=Message.INFO)) # }}} return render_to_response('player.djhtml', base)
def match(request): base = base_ctx('Inference', 'Predict', request=request) # {{{ Get data, set up and simulate form = SetupForm(request.GET) if not form.is_valid(): return redirect('/inference/') num = form.cleaned_data['bo'][0] dbpl = form.cleaned_data['ps'] sipl = [make_player(p) for p in dbpl] match = MatchSim(num) match.set_players(sipl) match.modify( get_param_range(request, 's1', (0, num), 0), get_param_range(request, 's2', (0, num), 0), ) match.compute() # }}} # {{{ Postprocessing base.update({ 'form': form, 'dbpl': dbpl, 'rta': sipl[0].elo_vs_opponent(sipl[1]), 'rtb': sipl[1].elo_vs_opponent(sipl[0]), 'proba': match.get_tally()[sipl[0]][1], 'probb': match.get_tally()[sipl[1]][1], 'match': match, }) base.update({ 'max': max(base['proba'], base['probb']), 'fav': dbpl[0] if base['proba'] > base['probb'] else dbpl[1], }) resa, resb = [], [] outcomes = [ {'sca': outcome[1], 'scb': outcome[2], 'prob': outcome[0]} for outcome in match.instances_detail() ] resa = [oc for oc in outcomes if oc['sca'] > oc['scb']] resb = [oc for oc in outcomes if oc['scb'] > oc['sca']] if len(resa) < len(resb): resa = [None] * (len(resb) - len(resa)) + resa else: resb = [None] * (len(resa) - len(resb)) + resb base['res'] = list(zip(resa, resb)) # }}} # {{{ Scores and other data thr = date.today() - relativedelta(months=2) pla_matches = dbpl[0].get_matchset() plb_matches = dbpl[1].get_matchset() base['tot_w_a'], base['tot_l_a'] = count_winloss_player(pla_matches, dbpl[0]) base['frm_w_a'], base['frm_l_a'] = count_winloss_player(pla_matches.filter(date__gte=thr), dbpl[0]) base['tot_w_b'], base['tot_l_b'] = count_winloss_player(plb_matches, dbpl[1]) base['frm_w_b'], base['frm_l_b'] = count_winloss_player(plb_matches.filter(date__gte=thr), dbpl[1]) if dbpl[1].race in 'PTZ': base['mu_w_a'], base['mu_l_a'] = count_matchup_player(pla_matches, dbpl[0], dbpl[1].race) base['fmu_w_a'], base['fmu_l_a'] = count_matchup_player( pla_matches.filter(date__gte=thr), dbpl[0], dbpl[1].race ) if dbpl[0].race in 'PTZ': base['mu_w_b'], base['mu_l_b'] = count_matchup_player(plb_matches, dbpl[1], dbpl[0].race) base['fmu_w_b'], base['fmu_l_b'] = count_matchup_player( plb_matches.filter(date__gte=thr), dbpl[1], dbpl[0].race ) wa_a, wb_a = count_winloss_games(Match.objects.filter(pla=dbpl[0], plb=dbpl[1])) wb_b, wa_b = count_winloss_games(Match.objects.filter(pla=dbpl[1], plb=dbpl[0])) base['vs_a'] = wa_a + wa_b base['vs_b'] = wb_a + wb_b base['matches'] = display_matches( Match.objects.filter(Q(pla=dbpl[0], plb=dbpl[1]) | Q(plb=dbpl[0], pla=dbpl[1])) .select_related('period', 'pla', 'plb') .order_by('-date', 'id'), fix_left=dbpl[0], ) # }}} postable_match(base, request) base.update({"title": "{} vs. {}".format(dbpl[0].tag, dbpl[1].tag)}) return render_to_response('pred_match.html', base)
def adjustment(request, player_id, period_id): # {{{ Get objects period = get_object_or_404(Period, id=period_id, computed=True) player = get_object_or_404(Player, id=player_id) rating = get_object_or_404(Rating, player=player, period=period) base = base_ctx('Ranking', 'Adjustments', request, context=player) base.update({ 'period': period, 'player': player, 'rating': rating, 'prevlink': etn(lambda: player.rating_set.filter(period__lt=period, decay=0). latest('period')), 'nextlink': etn(lambda: player.rating_set.filter(period__gt=period, decay=0). earliest('period')), }) # }}} # {{{ Matches matches = player.get_matchset( related=['rta', 'rtb', 'pla', 'plb', 'eventobj']).filter(period=period) # If there are no matches, we don't need to continue if not matches.exists(): return render_to_response('ratingdetails.djhtml', base) base.update({ 'matches': display_matches(matches, fix_left=player, ratings=True), 'has_treated': False, 'has_nontreated': False, }) # }}} # {{{ Perform calculations tot_rating = {'M': 0.0, 'P': 0.0, 'T': 0.0, 'Z': 0.0} ngames = {'M': 0.0, 'P': 0.0, 'T': 0.0, 'Z': 0.0} expwins = {'M': 0.0, 'P': 0.0, 'T': 0.0, 'Z': 0.0} nwins = {'M': 0.0, 'P': 0.0, 'T': 0.0, 'Z': 0.0} for m in base['matches']: if not m['match'].treated: base['has_nontreated'] = True continue base['has_treated'] = True total_score = m['pla']['score'] + m['plb']['score'] scale = sqrt(1 + m['pla']['dev']**2 + m['plb']['dev']**2) expected = total_score * cdf(m['pla']['rating'] - m['plb']['rating'], scale=scale) ngames['M'] += total_score tot_rating['M'] += m['plb']['rating'] * total_score expwins['M'] += expected nwins['M'] += m['pla']['score'] vs_races = [m['plb']['race']] if m['plb']['race'] in 'PTZ' else 'PTZ' weight = 1 / len(vs_races) for r in vs_races: ngames[r] += weight * total_score tot_rating[r] += weight * m['plb']['rating'] * total_score expwins[r] += weight * expected nwins[r] += weight * m['pla']['score'] for r in 'MPTZ': if ngames[r] > 0: tot_rating[r] /= ngames[r] base.update({ 'ngames': ngames, 'tot_rating': tot_rating, 'expwins': expwins, 'nwins': nwins, }) # }}} return render_to_response('ratingdetails.djhtml', base)
def events(request, event_id=None): # Redirect to proper URL if there's a ?goto=... present if 'goto' in request.GET: return redirect('/results/events/' + request.GET['goto']) base = base_ctx('Results', 'By Event', request) base.update(csrf(request)) try: event = Event.objects.get(id=int(event_id)) except: # This is executed for invalid event IDs or the root table ind_bigs = collect(Event.objects.filter(parent__isnull=True, big=True, category='individual').\ select_related('event').order_by('lft'), 2) ind_smalls = Event.objects.filter(parent__isnull=True, big=False, category='individual').\ select_related('event').order_by('name') team_bigs = collect(Event.objects.filter(parent__isnull=True, big=True, category='team').\ select_related('event').order_by('lft'), 2) team_smalls = Event.objects.filter(parent__isnull=True, big=False, category='team').\ select_related('event').order_by('name') freq_bigs = collect(Event.objects.filter(parent__isnull=True, big=True, category='frequent').\ select_related('event').order_by('lft'), 2) freq_smalls = Event.objects.filter(parent__isnull=True, big=False, category='frequent').\ select_related('event').order_by('name') base.update({'ind_bigs': ind_bigs, 'ind_smalls': ind_smalls,\ 'team_bigs': team_bigs, 'team_smalls': team_smalls,\ 'freq_bigs': freq_bigs, 'freq_smalls': freq_smalls}) return render_to_response('events.html', base) # Number of matches (set event to big if too large) matches = Match.objects.filter(eventobj__lft__gte=event.lft, eventobj__rgt__lte=event.rgt) if matches.count() > 200 and not event.big: event.big = True event.save() # Get parent, ancestors and siblings if event.parent != None: siblings = event.parent.event_set.exclude(id=event.id).order_by('lft') else: siblings = None # Make modifications if neccessary if base['adm'] == True: if 'op' in request.POST and request.POST['op'] == 'Modify': if request.POST['type'] != 'nochange': event.change_type(request.POST['type']) if 'siblings' in request.POST.keys() and siblings is not None: for sibling in siblings: sibling.change_type(request.POST['type']) if request.POST['name'] != '' and request.POST['name'] != event.name: event.name = request.POST['name'] event.update_name() event.save() for e in event.get_children(): e.update_name() if request.POST['date'].strip() != 'No change': matches.update(date=request.POST['date']) base['message'] = 'Modified all matches.' if request.POST['offline'] != 'nochange': matches.update(offline=(request.POST['offline'] == 'offline')) base['message'] = 'Modified all matches.' if request.POST['game'] != 'nochange': matches.update(game=request.POST['game']) base['message'] = 'Modified all matches.' if request.POST['homepage'] != event.get_homepage(): event.set_homepage(request.POST['homepage']) if request.POST['tlpd_in_id'] != event.get_tlpd_in_id(): event.set_tlpd_in_id(request.POST['tlpd_in_id']) if request.POST['tlpd_kr_id'] != event.get_tlpd_kr_id(): event.set_tlpd_kr_id(request.POST['tlpd_kr_id']) if request.POST['tl_thread'] != event.get_tl_thread(): event.set_tl_thread(request.POST['tl_thread']) if request.POST['lp_name'] != event.get_lp_name(): event.set_lp_name(request.POST['lp_name']) elif 'add' in request.POST and request.POST['add'] == 'Add': parent = event for q in request.POST['subevent'].strip().split(','): type = request.POST['type'] parent.add_child(q.strip(), type, 'noprint' in request.POST, 'closed' in request.POST) elif 'move' in request.POST and request.POST['move'] == 'Move': eventid = request.POST['moveevent'] newparent = Event.objects.get(id=eventid) if event.lft > newparent.rgt: diff = newparent.rgt - event.lft else: diff = newparent.rgt - event.rgt - 1 event_shift(event, diff) event.set_parent(newparent) event.update_name() for e in event.get_children(): e.update_name() elif 'earnings' in request.POST and request.POST['earnings'] == 'Add': amount = int(request.POST['amount']) currency = request.POST['currency'] players = [] amounts = [] placements = [] for i in range(0, amount): player = request.POST['player-' + str(i)] player = Player.objects.get(id=player) amount = request.POST['amount-' + str(i)] amount = amount.replace(',', '').replace('.', '').replace(' ', '') players.append(player) amounts.append(amount) placements.append(i) success = Earnings.set_earnings(event, players, amounts, currency, placements) if success: base['message'] = 'Updated tournament prizepool.' else: base['message'] = 'There was an error updating the tournament prizepool.' base['event'] = event base['path'] = Event.objects.filter(lft__lte=event.lft, rgt__gte=event.rgt).order_by('lft') base['children'] = Event.objects.filter(parent=event).order_by('lft') if event.parent != None: base['siblings'] = event.parent.event_set.exclude(id=event.id).order_by('lft') # Used for moving events base['surroundingevents'] = event.get_parent(1).get_children().exclude(lft__gte=event.lft, rgt__lte=event.rgt) # Determine WoL/HotS and Online/Offline and event type if matches.values("game").distinct().count() == 1: base['game'] = matches[0].game if base['game'] == 'WoL': base['game'] = 'Wings of Liberty' elif base['game'] == 'HotS': base['game'] = 'Heart of the Swarm' #elif base['game'] = 'LotV': #base['game'] = 'Legacy of the Void' # Get list of players and earnings for prizepools base['players'] = Player.objects.filter(Q(id__in=matches.values('pla')) | Q(id__in=matches.values('plb'))) earnings = Earnings.objects.filter(event=event).order_by('placement') base['earnings'] = earnings base['prizepool'] = earnings.aggregate(Sum('earnings'))['earnings__sum'] base['prizepoolorig'] = earnings.aggregate(Sum('origearnings'))['origearnings__sum'] try: base['prizepoolcur'] = earnings.values('currency')[0]['currency'] except: base['prizepoolcur'] = "USD" # Get list of currencies currencies = [] sortedcurrencies = sorted(ccy.currencydb(), key=operator.itemgetter(0)) for currency in sortedcurrencies: dict = {} dict["name"] = ccy.currency(currency).name dict["code"] = ccy.currency(currency).code currencies.append(dict) base['currencies'] = currencies base['offline'] = None if matches.values("offline").distinct().count() == 1: base['offline'] = matches[0].offline # Statistics base['nmatches'] = matches.count() if base['nmatches'] > 0: qset = matches.aggregate(Sum('sca'), Sum('scb')) base['ngames'] = qset['sca__sum'] + qset['scb__sum'] else: base['ngames'] = 0 # Matchup wins and losses nti = lambda x: 0 if x is None else x qseta = matches.filter(rca='P', rcb='T').aggregate(Sum('sca'), Sum('scb')) qsetb = matches.filter(rcb='P', rca='T').aggregate(Sum('sca'), Sum('scb')) base['pvt_wins'] = nti(qseta['sca__sum']) + nti(qsetb['scb__sum']) base['pvt_loss'] = nti(qsetb['sca__sum']) + nti(qseta['scb__sum']) qseta = matches.filter(rca='P', rcb='Z').aggregate(Sum('sca'), Sum('scb')) qsetb = matches.filter(rcb='P', rca='Z').aggregate(Sum('sca'), Sum('scb')) base['pvz_wins'] = nti(qseta['sca__sum']) + nti(qsetb['scb__sum']) base['pvz_loss'] = nti(qsetb['sca__sum']) + nti(qseta['scb__sum']) qseta = matches.filter(rca='T', rcb='Z').aggregate(Sum('sca'), Sum('scb')) qsetb = matches.filter(rcb='T', rca='Z').aggregate(Sum('sca'), Sum('scb')) base['tvz_wins'] = nti(qseta['sca__sum']) + nti(qsetb['scb__sum']) base['tvz_loss'] = nti(qsetb['sca__sum']) + nti(qseta['scb__sum']) # Dates base['earliest'] = event.get_earliest() base['latest'] = event.get_latest() matches = matches.order_by('-date', '-eventobj__lft', '-id')[0:200] base['matches'] = display_matches(matches) return render_to_response('eventres.html', base)
def events(request, event_id=None): # {{{ Get base context, redirect if necessary if 'goto' in request.GET: return redirect('/results/events/' + request.GET['goto']) base = base_ctx('Results', 'By Event', request) # }}} # {{{ Display the main table if event ID is not given if event_id is None: root_events = (Event.objects.annotate( num_uplinks=Count("uplink")).filter( num_uplinks=1).order_by('name').only('id', 'name', 'big', 'category', 'fullname')) base.update({ 'bigs': (list(root_events.filter(big=True, category=CAT_INDIVIDUAL)) + list(root_events.filter(big=True, category=CAT_TEAM)) + list(root_events.filter(big=True, category=CAT_FREQUENT))), 'smalls': (list( root_events.filter(big=False, category=CAT_INDIVIDUAL).order_by('name')) + list( root_events.filter(big=False, category=CAT_TEAM).order_by('name')) + list( root_events.filter(big=False, category=CAT_FREQUENT).order_by('name'))) }) base['messages'].append( Message(_( 'The events are organized in a hierarchical fashion. Thus, all GSL tournaments ' 'are filed under GSL, all Code S under their respective seasons, all groups under ' 'their respective Code S event, and so on.'), type=Message.INFO)) return render_to_response('events.djhtml', base) # }}} # {{{ Get object, generate messages, and ensure big is set. Find familial relationships. event = get_object_or_404(Event, id=event_id) base['messages'] += generate_messages(event) matches = event.get_matchset() if matches.count() > 200 and not event.big: event.set_big(True) base.update({ 'event': event, 'siblings': event.get_parent().get_immediate_children().exclude( id=event.id) if event.get_parent() else None, 'path': event.get_ancestors(id=True), 'children': event.get_immediate_children(), }) # }}} # {{{ Make forms if base['adm']: def check_form(formname, cl, check): if request.method == 'POST' and check in request.POST: f = cl(request=request, event=event) base['messages'] += f.update_event(event) else: f = cl(event=event) base[formname] = f check_form('form', EventModForm, 'modevent') check_form('addform', AddForm, 'addevent') if event.has_children(): check_form('reorderform', ReorderForm, 'reorder') if event.type == TYPE_EVENT: check_form('ppform', PrizepoolModForm, 'modpp') if not event.has_children() and event.get_immediate_matchset().exists( ): check_form('stform', StoriesForm, 'modstory') # }}} # {{{ Prizepool information for the public total_earnings = Earnings.objects.filter(event__uplink__parent=event) local_earnings = Earnings.objects.filter(event=event) ranked_prize = local_earnings.exclude(placement=0)\ .order_by('-earnings', 'placement') unranked_prize = list( local_earnings.filter(placement=0).order_by('-earnings')) placements = get_placements(event) prize_pool_table = list() for k, g in groupby(ranked_prize, key=lambda x: x.earnings): gl = list(g) prize_pool_table.append((k, placements[k], gl, len(gl))) if len(prize_pool_table) > 0: base['ranked_prize'] = prize_pool_table if len(unranked_prize) > 0: base['unranked_prize'] = unranked_prize currencies = list( {r['currency'] for r in total_earnings.values('currency').distinct()}) base.update({ 'prizepool': total_earnings.aggregate(Sum('earnings'))['earnings__sum'], 'nousdpp': len(currencies) > 1 or len(currencies) == 1 and currencies[0] != 'USD', 'prizepoolorig': [{ 'pp': total_earnings.filter(currency=k).aggregate( Sum('origearnings'))['origearnings__sum'], 'cur': k, } for k in currencies], }) # }}} # {{{ Other easy statistics add_links = request.user.is_authenticated() and request.user.is_staff base.update({ 'game': etn(lambda: dict(GAMES)[matches.values('game').distinct()[0]['game']]), 'nmatches': matches.count(), 'ngames': sum(count_winloss_games(matches)), 'pvp_games': count_mirror_games(matches, 'P'), 'tvt_games': count_mirror_games(matches, 'T'), 'zvz_games': count_mirror_games(matches, 'Z'), 'matches': display_matches( matches.prefetch_related('message_set').prefetch_related( 'pla', 'plb', 'eventobj').annotate(Count('eventobj__match')).order_by( '-eventobj__latest', '-eventobj__idx', '-date', '-id')[0:200], eventcount=True, add_links=add_links), 'nplayers': Player.objects.filter( Q(id__in=matches.values('pla')) | Q(id__in=matches.values('plb'))).count(), }) offlines = list(matches.values('offline').distinct()) if len(offlines) > 1: base['offline'] = _('Both') elif len(offlines) == 1: base['offline'] = _('Offline') if offlines[0]['offline'] else _( 'Online') base['pvt_wins'], base['pvt_loss'] = count_matchup_games(matches, 'P', 'T') base['pvz_wins'], base['pvz_loss'] = count_matchup_games(matches, 'P', 'Z') base['tvz_wins'], base['tvz_loss'] = count_matchup_games(matches, 'T', 'Z') base['tot_mirror'] = base['pvp_games'] + base['tvt_games'] + base[ 'zvz_games'] # }}} return render_to_response('eventres.djhtml', base)
def player(request, player_id): # {{{ Get player object and base context, generate messages and make changes if needed player = get_object_or_404(Player, id=player_id) base = base_ctx('Ranking', 'Summary', request, context=player) if request.method == 'POST' and base['adm']: form = PlayerModForm(request) base['messages'] += form.update_player(player) else: form = PlayerModForm(player=player) base['messages'] += generate_messages(player) # }}} # {{{ Various easy data matches = player.get_matchset() recent = matches.filter(date__gte=(date.today() - relativedelta(months=2))) base.update({ 'player': player, 'form': form, 'first': etn(lambda: matches.earliest('date')), 'last': etn(lambda: matches.latest('date')), 'totalmatches': matches.count(), 'offlinematches': matches.filter(offline=True).count(), 'aliases': player.alias_set.all(), 'earnings': ntz(player.earnings_set.aggregate(Sum('earnings'))['earnings__sum']), 'team': player.get_current_team(), 'total': count_winloss_player(matches, player), 'vp': count_matchup_player(matches, player, P), 'vt': count_matchup_player(matches, player, T), 'vz': count_matchup_player(matches, player, Z), 'totalf': count_winloss_player(recent, player), 'vpf': count_matchup_player(recent, player, P), 'vtf': count_matchup_player(recent, player, T), 'vzf': count_matchup_player(recent, player, Z), }) if player.country is not None: base['countryfull'] = transformations.cc_to_cn(player.country) # }}} # {{{ Recent matches matches = player.get_matchset(related=['rta','rtb','pla','plb','eventobj'])[0:10] if matches.exists(): base['matches'] = display_matches(matches, fix_left=player, ratings=True) # }}} # {{{ Team memberships team_memberships = list(player.groupmembership_set.filter(group__is_team=True).select_related('group')) team_memberships.sort(key=lambda t: t.id, reverse=True) team_memberships.sort(key=meandate, reverse=True) team_memberships.sort(key=lambda t: t.current, reverse=True) base['teammems'] = team_memberships # }}} # {{{ If the player has at least one rating if player.current_rating: ratings = total_ratings(player.rating_set.filter(period__computed=True)).select_related('period') base.update({ 'highs': ( ratings.latest('rating'), ratings.latest('tot_vp'), ratings.latest('tot_vt'), ratings.latest('tot_vz'), ), 'recentchange': player.get_latest_rating_update(), 'firstrating': ratings.earliest('period'), 'rating': player.current_rating, }) if player.current_rating.decay >= INACTIVE_THRESHOLD: base['messages'].append(Message(msg_inactive % player.tag, 'Inactive', type=Message.INFO)) base['charts'] = base['recentchange'].period_id > base['firstrating'].period_id else: base['messages'].append(Message('%s has no rating yet.' % player.tag, type=Message.INFO)) base['charts'] = False # }}} # {{{ If the player has enough games to make a chart if base['charts']: ratings = ( total_ratings(player.rating_set.filter(period_id__lte=base['recentchange'].period_id)) .select_related('period__end') .prefetch_related('prev__rta', 'prev__rtb') .order_by('period') ) # {{{ Add stories and other extra information earliest = base['firstrating'] latest = base['recentchange'] # Look through team changes teampoints = [] for mem in base['teammems']: if mem.start and earliest.period.end < mem.start < latest.period.end: teampoints.append({ 'date': mem.start, 'rating': interp_rating(mem.start, ratings), 'data': [{'date': mem.start, 'team': mem.group, 'jol': 'joins'}], }) if mem.end and earliest.period.end < mem.end < latest.period.end: teampoints.append({ 'date': mem.end, 'rating': interp_rating(mem.end, ratings), 'data': [{'date': mem.end, 'team': mem.group, 'jol': 'leaves'}], }) teampoints.sort(key=lambda p: p['date']) # Condense if team changes happened within 14 days cur = 0 while cur < len(teampoints) - 1: if (teampoints[cur+1]['date'] - teampoints[cur]['date']).days <= 14: teampoints[cur]['data'].append(teampoints[cur+1]['data'][0]) del teampoints[cur+1] else: cur += 1 # Sort first by date, then by joined/left for point in teampoints: point['data'].sort(key=lambda a: a['jol'], reverse=True) point['data'].sort(key=lambda a: a['date']) # Look through stories stories = player.story_set.all().select_related('event__fullname') for s in stories: if earliest.period.start < s.date < latest.period.start: s.rating = interp_rating(s.date, ratings) else: s.skip = True # }}} base.update({ 'ratings': add_counts(ratings), 'patches': PATCHES, 'stories': stories, 'teampoints': teampoints, }) else: base['messages'].append(Message(msg_nochart % player.tag, type=Message.INFO)) # }}} base.update({"title": player.tag}) return render_to_response('player.html', base)
def rating_details(request, player_id, period_id): period_id = int(period_id) player_id = int(player_id) period = get_object_or_404(Period, id=period_id, computed=True) player = get_object_or_404(Player, id=player_id, rating__period=period) rating = get_object_or_404(Rating, player=player, period=period) base = base_ctx('Ranking', 'Adjustments', request, context=player) try: nextlink = Rating.objects.filter(player=player, period__id__gt=period_id,\ decay=0).order_by('period__id')[0] except: nextlink = None try: prevlink = Rating.objects.filter(player=player, period__id__lt=period_id,\ decay=0).order_by('-period__id')[0] except: prevlink = None races = ['P','T','Z'] prev = rating.get_prev() if prev != None: prevrat = [prev.get_rating(), {}] prevdev = [prev.get_dev(), {}] for r in races: prevrat[1][r] = prev.get_totalrating(r) prevdev[1][r] = prev.get_totaldev(r) else: prevrat = [0., {'P': 0., 'T': 0., 'Z': 0.}] prevdev = [RATINGS_INIT_DEV, {'P': RATINGS_INIT_DEV, 'T': RATINGS_INIT_DEV, 'Z': RATINGS_INIT_DEV}] matches = Match.objects.filter(Q(pla=player) | Q(plb=player)).filter(period=period)\ .select_related('pla__rating').select_related('plb__rating').order_by('-date', '-id') if not matches.exists(): base.update({'period': period, 'player': player, 'prevlink': prevlink, 'nextlink': nextlink}) return render_to_response('ratingdetails.html', base) matches = display_matches(matches, fix_left=player, ratings=True) tot_rating = [0.0, {'P': 0.0, 'T': 0.0, 'Z': 0.0}] ngames = [0, {'P': 0, 'T': 0, 'Z': 0}] nwins = [0, {'P': 0, 'T': 0, 'Z': 0}] nlosses = [0, {'P': 0, 'T': 0, 'Z': 0}] expwins = [0.0, {'P': 0.0, 'T': 0.0, 'Z': 0.0}] treated = False nontreated = False for m in matches: if not m.treated: nontreated = True continue treated = True tot_rating[0] += m.plb_rating * (m.pla_score + m.plb_score) ngames[0] += m.pla_score + m.plb_score nwins[0] += m.pla_score nlosses[0] += m.plb_score scale = sqrt(1 + m.pla_dev**2 + m.pla_dev**2) races = [m.plb_race] if m.plb_race in ['P','T','Z'] else ['P','T','Z'] weight = float(1)/len(races) for sr in races: ew = (m.pla_score + m.plb_score) * cdf(m.pla_rating - m.plb_rating, scale=scale) expwins[0] += weight * ew expwins[1][sr] += weight * ew tot_rating[1][sr] += weight * m.plb_rating * (m.pla_score + m.plb_score) ngames[1][sr] += weight * (m.pla_score + m.plb_score) nwins[1][sr] += weight * m.pla_score nlosses[1][sr] += weight * m.plb_score base.update({'period': period, 'player': player, 'rating': rating, 'matches': matches, 'treated': treated,\ 'nontreated': nontreated, 'prevlink': prevlink, 'nextlink': nextlink}) if not treated: return render_to_response('ratingdetails.html', base) else: tot_rating[0] /= ngames[0] for r in ['P','T','Z']: if ngames[1][r] > 0: tot_rating[1][r] /= ngames[1][r] explosses = [ngames[0]-expwins[0], {}] exppctg = [expwins[0]/ngames[0]*100, {}] pctg = [float(nwins[0])/ngames[0]*100, {}] diff = [rating.rating-prevrat[0], {}] modded = False for r in ['P','T','Z']: explosses[1][r] = ngames[1][r] - expwins[1][r] if ngames[1][r] > 0: exppctg[1][r] = expwins[1][r]/ngames[1][r]*100 pctg[1][r] = float(nwins[1][r])/ngames[1][r]*100 diff[1][r] = rating.get_totalrating(r) - prevrat[1][r] if (nwins[1][r] != 0) != (nlosses[1][r] != 0): modded = True base.update({'tot_rating': tot_rating, 'ngames': ngames, 'nwins': nwins, 'nlosses': nlosses,\ 'prevrat': prevrat, 'pctg': pctg,\ 'exppctg': exppctg, 'diff': diff, 'expwins': expwins, 'explosses': explosses,\ 'prevdev': prevdev, 'modded': modded}) return render_to_response('ratingdetails.html', base)
def results(request, player_id): # {{{ Get objects player = get_object_or_404(Player, id=player_id) base = base_ctx('Ranking', 'Match history', request, context=player) base['player'] = player # }}} # {{{ Filtering matches = player.get_matchset(related=['pla','plb','eventobj']) form = ResultsFilterForm(request.GET) base['form'] = form form.is_valid() q = Q() for r in form.cleaned_data['race'].upper(): q |= Q(pla=player, rcb=r) | Q(plb=player, rca=r) matches = matches.filter(q) if form.cleaned_data['country'] == 'foreigners': matches = matches.exclude(Q(pla=player, plb__country='KR') | Q(plb=player, pla__country='KR')) elif form.cleaned_data['country'] != 'all': matches = matches.filter( Q(pla=player, plb__country=form.cleaned_data['country']) | Q(plb=player, pla__country=form.cleaned_data['country']) ) if form.cleaned_data['bestof'] != 'all': sc = int(form.cleaned_data['bestof'])//2 + 1 matches = matches.filter(Q(sca__gte=sc) | Q(scb__gte=sc)) if form.cleaned_data['offline'] != 'both': matches = matches.filter(offline=(form.cleaned_data['offline']=='offline')) if form.cleaned_data['game'] != 'all': matches = matches.filter(game=form.cleaned_data['game']) if form.cleaned_data['after'] is not None: matches = matches.filter(date__gte=form.cleaned_data['after']) if form.cleaned_data['before'] is not None: matches = matches.filter(date__lte=form.cleaned_data['before']) # }}} # {{{ Statistics matches = display_matches(matches, fix_left=player) base['matches'] = matches base.update({ 'sc_my': sum(m['pla']['score'] for m in base['matches']), 'sc_op': sum(m['plb']['score'] for m in base['matches']), 'msc_my': sum(1 for m in base['matches'] if m['pla']['score'] > m['plb']['score']), 'msc_op': sum(1 for m in base['matches'] if m['plb']['score'] > m['pla']['score']), }) # }}} # {{{ TL Postable has_after = form.cleaned_data['after'] is not None has_before = form.cleaned_data['before'] is not None if not has_after and not has_before: match_date = "" elif not has_after: # and has_before match_date = " before {}".format(form.cleaned_data['before']) elif not has_before: # and has_after match_date = " after {}".format(form.cleaned_data['after']) else: match_date = " between {} and {}".format(form.cleaned_data['after'], form.cleaned_data['before']) match_filter = "" def switcher(race): if race == "S": return "R" elif race == "s": return "r" return race def win(match): return match['pla']['score'] >= match['plb']['score'] def format_match(d): # TL only recognizes lower case country codes :( if d["pla"]["country"] is not None: d["pla_country_formatted"] = ":{}:".format(d["pla"]["country"].lower()) else: d["pla_country_formatted"] = "" if d["plb"]["country"] is not None: d["plb_country_formatted"] = ":{}:".format(d["plb"]["country"].lower()) else: d["plb_country_formatted"] = "" # and no race switchers d["pla_race"] = switcher(d["pla"]["race"]) d["plb_race"] = switcher(d["plb"]["race"]) # Check who won temp = { "plaws": "", "plawe": "", "plbws": "", "plbwe": "" } if win(d): temp["plaws"] = "[b]" temp["plawe"] = "[/b]" else: temp["plbws"] = "[b]" temp["plbwe"] = "[/b]" d.update(temp) d["pla_id"] = d["pla"]["id"] d["pla_tag"] = d["pla"]["tag"] d["pla_score"] = d["pla"]["score"] d["plb_id"] = d["plb"]["id"] d["plb_tag"] = d["plb"]["tag"] d["plb_score"] = d["plb"]["score"] return TL_HISTORY_MATCH_TEMPLATE.format(**d) recent_matches = matches[:min(10, len(matches))] recent = "\n".join(format_match(m) for m in recent_matches) recent_form = " ".join("W" if win(m) else "L" for m in reversed(recent_matches)) # Get the parameters and remove those with None value get_params = dict((k, form.cleaned_data[k]) for k in form.cleaned_data if form.cleaned_data[k] is not None) country = "" if player.country is not None: country = ":{}:".format(player.country.lower()) tl_params = { "player_tag": player.tag, "player_country_formatted": country, "player_race": switcher(player.race), "filter": match_filter, "date": match_date, "recent": recent, "pid": player_id, "get": urlencode(get_params), "url": "http://aligulac.com" } tl_params.update({ "sc_my": base["sc_my"], "sc_op": base["sc_op"], "msc_my": base["msc_my"], "msc_op": base["msc_op"], "form": recent_form }) def calc_percent(s): f, a = float(int(tl_params[s+"_my"])), int(tl_params[s+"_op"]) return round(100 * f / (f+a), 2) tl_params.update({ "sc_percent": calc_percent("sc"), "msc_percent": calc_percent("msc") }) tl_params.update(get_params) # Final clean up if tl_params["bestof"] != "all": tl_params["bestof"] = "Bo{}+".format(tl_params["bestof"]) if set(tl_params["race"]) == set('ptzr'): tl_params["race"] = "all" base.update({ "postable_tl": TL_HISTORY_TEMPLATE.format(**tl_params) }) # }}} base.update({"title": player.tag}) return render_to_response('player_results.html', base)
def player(request, player_id): # {{{ Get player object and base context, generate messages and make changes if needed player = get_object_or_404(Player, id=player_id) base = base_ctx("Ranking", "Summary", request, context=player) if request.method == "POST" and "modplayer" in request.POST and base["adm"]: modform = PlayerModForm(request) base["messages"] += modform.update_player(player) else: modform = PlayerModForm(player=player) base["messages"] += generate_messages(player) # }}} # {{{ Various easy data matches = player.get_matchset() recent = matches.filter(date__gte=(date.today() - relativedelta(months=2))) base.update( { "player": player, "modform": modform, "first": etn(lambda: matches.earliest("date")), "last": etn(lambda: matches.latest("date")), "totalmatches": matches.count(), "offlinematches": matches.filter(offline=True).count(), "aliases": player.alias_set.all(), "earnings": ntz(player.earnings_set.aggregate(Sum("earnings"))["earnings__sum"]), "team": player.get_current_team(), "total": count_winloss_player(matches, player), "vp": count_matchup_player(matches, player, P), "vt": count_matchup_player(matches, player, T), "vz": count_matchup_player(matches, player, Z), "totalf": count_winloss_player(recent, player), "vpf": count_matchup_player(recent, player, P), "vtf": count_matchup_player(recent, player, T), "vzf": count_matchup_player(recent, player, Z), } ) riv = player.rivals or [] nem = player.nemesis or [] vic = player.victim or [] base["riv_nem_vic"] = zip_longest(riv, nem, vic) if player.country is not None: base["countryfull"] = transformations.cc_to_cn(player.country) # }}} # {{{ Recent matches matches = player.get_matchset(related=["rta", "rtb", "pla", "plb", "eventobj"])[0:10] if matches.exists(): base["matches"] = display_matches(matches, fix_left=player, ratings=True) # }}} # {{{ Team memberships team_memberships = list(player.groupmembership_set.filter(group__is_team=True).select_related("group")) team_memberships.sort(key=lambda t: t.id, reverse=True) team_memberships.sort(key=meandate, reverse=True) team_memberships.sort(key=lambda t: t.current, reverse=True) base["teammems"] = team_memberships # }}} # {{{ If the player has at least one rating if player.current_rating: ratings = total_ratings(player.rating_set.filter(period__computed=True)).select_related("period") base.update( { "highs": ( ratings.latest("rating"), ratings.latest("tot_vp"), ratings.latest("tot_vt"), ratings.latest("tot_vz"), ), "recentchange": player.get_latest_rating_update(), "firstrating": ratings.earliest("period"), "rating": player.current_rating, } ) if player.current_rating.decay >= INACTIVE_THRESHOLD: base["messages"].append(Message(msg_inactive % player.tag, "Inactive", type=Message.INFO)) base["charts"] = base["recentchange"].period_id > base["firstrating"].period_id else: base["messages"].append(Message(_("%s has no rating yet.") % player.tag, type=Message.INFO)) base["charts"] = False # }}} # {{{ If the player has enough games to make a chart if base["charts"]: ratings = ( total_ratings(player.rating_set.filter(period_id__lte=base["recentchange"].period_id)) .select_related("period__end") .prefetch_related("prev__rta", "prev__rtb") .order_by("period") ) # {{{ Add stories and other extra information earliest = base["firstrating"] latest = base["recentchange"] # Look through team changes teampoints = [] for mem in base["teammems"]: if mem.start and earliest.period.end < mem.start < latest.period.end: teampoints.append( { "date": mem.start, "rating": interp_rating(mem.start, ratings), "data": [{"date": mem.start, "team": mem.group, "jol": _("joins")}], } ) if mem.end and earliest.period.end < mem.end < latest.period.end: teampoints.append( { "date": mem.end, "rating": interp_rating(mem.end, ratings), "data": [{"date": mem.end, "team": mem.group, "jol": _("leaves")}], } ) teampoints.sort(key=lambda p: p["date"]) # Condense if team changes happened within 14 days cur = 0 while cur < len(teampoints) - 1: if (teampoints[cur + 1]["date"] - teampoints[cur]["date"]).days <= 14: teampoints[cur]["data"].append(teampoints[cur + 1]["data"][0]) del teampoints[cur + 1] else: cur += 1 # Sort first by date, then by joined/left for point in teampoints: point["data"].sort(key=lambda a: a["jol"], reverse=True) point["data"].sort(key=lambda a: a["date"]) # Look through stories stories = player.story_set.all().select_related("event__fullname") for s in stories: if earliest.period.start < s.date < latest.period.start: s.rating = interp_rating(s.date, ratings) else: s.skip = True # }}} base.update({"ratings": add_counts(ratings), "patches": PATCHES, "stories": stories, "teampoints": teampoints}) else: base["messages"].append(Message(msg_nochart % player.tag, type=Message.INFO)) # }}} return render_to_response("player.djhtml", base)