From 818be801b2c99699ba03ab26fb6d9822e76bf751 Mon Sep 17 00:00:00 2001 From: Danhia Date: Sun, 16 Jan 2022 22:18:39 +0100 Subject: [PATCH] split views.py in events + new field in events model for automatching --- .../migrations/0007_event_auto_match.py | 18 ++ src/events/models.py | 1 + src/events/templates/events/create_team.html | 2 + src/events/templates/events/join_team.html | 2 + src/events/utils.py | 2 +- src/events/views/__init__.py | 2 + src/events/{views.py => views/events.py} | 170 +---------------- src/events/views/teams.py | 176 ++++++++++++++++++ 8 files changed, 204 insertions(+), 169 deletions(-) create mode 100644 src/events/migrations/0007_event_auto_match.py create mode 100644 src/events/views/__init__.py rename src/events/{views.py => views/events.py} (60%) create mode 100644 src/events/views/teams.py diff --git a/src/events/migrations/0007_event_auto_match.py b/src/events/migrations/0007_event_auto_match.py new file mode 100644 index 0000000..80a5799 --- /dev/null +++ b/src/events/migrations/0007_event_auto_match.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.5 on 2022-01-16 21:09 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('events', '0006_auto_20220114_2319'), + ] + + operations = [ + migrations.AddField( + model_name='event', + name='auto_match', + field=models.BooleanField(default=False), + ), + ] diff --git a/src/events/models.py b/src/events/models.py index 57091bc..7f2f120 100644 --- a/src/events/models.py +++ b/src/events/models.py @@ -15,6 +15,7 @@ class Event(models.Model): password = models.CharField(max_length=200, blank=True) slug = models.SlugField(max_length=55) team_size = models.PositiveIntegerField(default=1) + auto_match = models.BooleanField(default=False) def __str__(self): return self.name diff --git a/src/events/templates/events/create_team.html b/src/events/templates/events/create_team.html index 72e0ec6..6ca877d 100644 --- a/src/events/templates/events/create_team.html +++ b/src/events/templates/events/create_team.html @@ -46,6 +46,7 @@ {% trans "Create Team" %} {% trans "Join Team" %} + {% if event.auto_match %} + {% endif %} {% endblock %} \ No newline at end of file diff --git a/src/events/templates/events/join_team.html b/src/events/templates/events/join_team.html index 2bfea69..005ac19 100644 --- a/src/events/templates/events/join_team.html +++ b/src/events/templates/events/join_team.html @@ -51,6 +51,7 @@ {% trans "Join Team" %} {% trans "Create Team" %} + {% if event.auto_match %} + {% endif %} {% endblock %} \ No newline at end of file diff --git a/src/events/utils.py b/src/events/utils.py index 274148d..69a9792 100644 --- a/src/events/utils.py +++ b/src/events/utils.py @@ -3,7 +3,7 @@ from random import choice, randint colors = ['blue', 'red', 'yellow', 'green', 'black', 'white', 'purple', 'orange', 'brown', 'fuchsia', 'gold', 'pink', 'cyan', 'magenta', 'pearl'] -animals = ['tiger', 'bee', 'dog', 'cat', 'otter', 'lizard', 'horse', 'mouse', 'butterfly', 'dolphin', 'elephant', 'falcon', 'goat' +animals = ['tiger', 'bee', 'dog', 'cat', 'otter', 'lizard', 'horse', 'mouse', 'butterfly', 'dolphin', 'elephant', 'falcon', 'goat', 'cow', 'lion', 'ostrich'] def get_random_name(): diff --git a/src/events/views/__init__.py b/src/events/views/__init__.py new file mode 100644 index 0000000..1c79547 --- /dev/null +++ b/src/events/views/__init__.py @@ -0,0 +1,2 @@ +from .events import * +from .teams import * \ No newline at end of file diff --git a/src/events/views.py b/src/events/views/events.py similarity index 60% rename from src/events/views.py rename to src/events/views/events.py index fb9edb8..7037a9e 100644 --- a/src/events/views.py +++ b/src/events/views/events.py @@ -1,16 +1,12 @@ from django.shortcuts import render, get_object_or_404, redirect from django.contrib.auth.decorators import login_required from django.contrib.auth.models import timezone -from .forms import submit_flag, TeamUpdateForm -from .models import Event, EventPlayer, Team +from ..forms import submit_flag +from ..models import Event, EventPlayer, Team from ctfs.models import CTF, CTF_flags, Category from django.utils.translation import get_language from django.contrib.auth.models import User -from accounts.models import UserProfileInfo -from django.db.models import Q from django.utils.translation import gettext_lazy as _ -from .utils import get_random_name -from random import randint def get_description_by_lang(ctf): lang = get_language() @@ -222,47 +218,6 @@ def subscribe_to_event(request, event_slug): return render(request, 'events/create_team.html', {'event' : ev, 'logged': True, 'wrongpwd': False, 'registered' : True, 'notexist' : False}) return redirect('events:event_info', event_slug=event_slug) -@login_required -def create_team(request, event_slug): - response = redirect('events:create_team', event_slug=event_slug) - ev = get_object_or_404(Event, slug=event_slug) - if request.method == 'POST': - if request.user.is_authenticated and ev.team_size > 1: - if Team.objects.filter(name=request.POST.get('teamname'), event=ev).exists(): - return render(request, 'events/create_team.html', {'event' : ev, 'logged': True, 'wrongpwd': False, 'registered' : True, 'exist' : True}) - new = Team(name=request.POST.get('teamname'), password=request.POST.get('password'), event=ev) - new.save() - player = EventPlayer.objects.get(user=request.user, event=ev) - player.team = new - player.save() - return redirect('events:event_info', event_slug=event_slug) - -@login_required -def join_team(request, event_slug): - response = redirect('events:join_team', event_slug=event_slug) - ev = get_object_or_404(Event, slug=event_slug) - if request.method == 'POST': - if request.user.is_authenticated and ev.team_size > 1: - try: - team = Team.objects.get(name=request.POST.get('teamname'), event=ev) - except: - team = None - if team is None: - return render(request, 'events/join_team.html', {'event' : ev, 'logged': True, 'wrongpwd': True, 'registered' : True, 'notexist' : True}) - else: - members = EventPlayer.objects.filter(team=team) - if request.POST.get('password') != team.password: - return render(request, 'events/join_team.html', {'event' : ev, 'logged': True, 'wrongpwd': True, 'registered' : True, 'notexist' : False}) - if members.count() >= ev.team_size: - return render(request, 'events/join_team.html', {'event' : ev, 'logged': True, 'wrongpwd': False, 'registered' : True, 'notexist' : False, 'max' : True}) - else: - player = EventPlayer.objects.get(user=request.user, event=ev) - player.team = team - player.save() - else: - return render(request, 'events/join_team.html', {'event' : ev, 'logged': True, 'wrongpwd': False, 'registered' : True, 'notexist' : False}) - return redirect('events:event_info', event_slug=event_slug) - @login_required def profile(request, user_name, event_slug): catsDatas = [] @@ -302,125 +257,4 @@ def profile(request, user_name, event_slug): return render(request,'accounts/profile.html', {'user':user_obj, 'solves':solves,'solved':solved,'catsDatas': catsDatas, 'pointDatas': pointDatas, 'rank': rank, 'score' : somme, 'cats':cats}) -@login_required -def team_info(request, name, event_slug): - event_info = get_object_or_404(Event, slug=event_slug) - team = Team.objects.get(name=name, event=event_info) - catsDatas = [] - - players = EventPlayer.objects.filter(team=team, event=event_info) - users = [p.user for p in players] - all_teams = list(Team.objects.filter(event=event_info).order_by('-score', 'last_submission_date', 'name')) - rank = all_teams.index(get_object_or_404(Team, id=team.id, event=event_info)) + 1 - all_cats = Category.objects.all() - cats = [cat for cat in all_cats if CTF.objects.filter(category__name=cat.name, event=event_info)] - pointDatas = {} - - for cat in cats: - # prepare categories - solved_count = 0 - solved = [] - max_count = CTF.objects.filter(category__name=cat.name, event=event_info).count() - somme = 0 - pointDatas[cat.name] = [[event_info.start_date.timestamp()*1000, 0]] - for user_obj in users: - # get datas - solved_count += CTF_flags.objects.filter(user=user_obj, ctf__event=event_info , ctf__category__name=cat.name).count() - solved += CTF_flags.objects.filter(user=user_obj, ctf__category__name=cat.name, ctf__event=event_info).order_by('flag_date') - percent = (solved_count / max_count) * 100 - catsDatas.append([cat.name, solved_count, max_count, '{:.0f}'.format(percent)]) - for flag in solved: - somme += flag.ctf.points - pointDatas[cat.name].append([flag.flag_date.timestamp() * 1000, somme]) - - query = Q() - for user_obj in users: - query |= Q(user=user_obj) - query &= Q(ctf__event=event_info) - - solves = CTF_flags.objects.filter(query).order_by('-flag_date') - solved = [] - somme = 0 - solved.append([event_info.start_date.timestamp() * 1000, 0]) - for s in solves.reverse(): - somme += s.ctf.points - solved.append([s.flag_date.timestamp() * 1000,somme]) - - return render(request,'events/team.html', {'users':users, 'solves':solves,'solved':solved,'catsDatas': catsDatas, 'pointDatas': pointDatas, - 'rank': rank, 'team':team, 'score':somme, 'event':event_info, 'cats':cats}) - -@login_required -def manage_team(request, event_slug): - event_info = get_object_or_404(Event, slug=event_slug) - player = EventPlayer.objects.get(user=request.user, event=event_info) - members = EventPlayer.objects.filter(team=player.team, event=event_info) - - if request.method == 'POST': - tname = player.team.name - p_form = TeamUpdateForm(request.POST, instance=player.team) - error = None - success = None - if p_form.is_valid(): - pname = p_form.cleaned_data['name'] - if pname == tname: - pass - else: - if Team.objects.filter(name=pname, event=event_info).exists(): - error = _("Name already taken.") - ppassword = p_form.cleaned_data['password'] - if error is None: - p_form.save() - success = _("Updated.") - - context={'p_form': p_form, 'error':error, 'success' : success, 'player':player, 'members':members} - return render(request, 'events/manage_team.html', context) - else: - p_form = TeamUpdateForm(instance=player.team) - context={'p_form': p_form, 'player':player, 'members':members} - return render(request, 'events/manage_team.html',context) - - -@login_required -def leave_team(request, event_slug): - event_info = get_object_or_404(Event, slug=event_slug) - player = EventPlayer.objects.get(user=request.user, event=event_info) - team = Team.objects.get(event=event_info, name=player.team.name) - - team.score -= player.score - team.save() - player.team = None - solved = CTF_flags.objects.filter(user=player.user, ctf__event=event_info) - player.score = 0 - solved.delete() - player.save() - - members = EventPlayer.objects.filter(team=team, event=event_info) - if members.count() == 0: - team.delete() - - return render(request, 'events/create_team.html', {'event' : event_info, 'logged': True, 'wrongpwd': False, 'registered' : True, 'notexist' : False}) - -@login_required -def find_team(request, event_slug): - event_info = get_object_or_404(Event, slug=event_slug) - teams = Team.objects.filter(event=event_info, auto=True) - team = None - player = EventPlayer.objects.get(user=request.user, event=event_info) - - for t in teams: - if EventPlayer.objects.filter(team=t, event=event_info).count() < event_info.team_size: - team = t - break - - if team is None: - teamname = get_random_name() - while Team.objects.filter(name=teamname, event=event_info).exists(): - teamname = get_random_name() - team = Team(name=teamname, password="".join([str(randint(0,10)) for _ in range(16)]), event=event_info, auto=True) - team.save() - - player.team = team - player.save() - - return redirect('events:event_info', event_slug=event_slug) diff --git a/src/events/views/teams.py b/src/events/views/teams.py new file mode 100644 index 0000000..af3e2a0 --- /dev/null +++ b/src/events/views/teams.py @@ -0,0 +1,176 @@ +from django.shortcuts import render, get_object_or_404, redirect +from django.contrib.auth.decorators import login_required +from ..forms import TeamUpdateForm +from ..models import Event, EventPlayer, Team +from ctfs.models import CTF, CTF_flags, Category +from django.contrib.auth.models import User +from django.db.models import Q +from django.utils.translation import gettext_lazy as _ +from ..utils import get_random_name +from random import randint + +@login_required +def create_team(request, event_slug): + response = redirect('events:create_team', event_slug=event_slug) + ev = get_object_or_404(Event, slug=event_slug) + if request.method == 'POST': + if request.user.is_authenticated and ev.team_size > 1: + if Team.objects.filter(name=request.POST.get('teamname'), event=ev).exists(): + return render(request, 'events/create_team.html', {'event' : ev, 'logged': True, 'wrongpwd': False, 'registered' : True, 'exist' : True}) + new = Team(name=request.POST.get('teamname'), password=request.POST.get('password'), event=ev) + new.save() + player = EventPlayer.objects.get(user=request.user, event=ev) + player.team = new + player.save() + return redirect('events:event_info', event_slug=event_slug) + +@login_required +def join_team(request, event_slug): + response = redirect('events:join_team', event_slug=event_slug) + ev = get_object_or_404(Event, slug=event_slug) + if request.method == 'POST': + if request.user.is_authenticated and ev.team_size > 1: + try: + team = Team.objects.get(name=request.POST.get('teamname'), event=ev) + except: + team = None + if team is None: + return render(request, 'events/join_team.html', {'event' : ev, 'logged': True, 'wrongpwd': True, 'registered' : True, 'notexist' : True}) + else: + members = EventPlayer.objects.filter(team=team) + if request.POST.get('password') != team.password: + return render(request, 'events/join_team.html', {'event' : ev, 'logged': True, 'wrongpwd': True, 'registered' : True, 'notexist' : False}) + if members.count() >= ev.team_size: + return render(request, 'events/join_team.html', {'event' : ev, 'logged': True, 'wrongpwd': False, 'registered' : True, 'notexist' : False, 'max' : True}) + else: + player = EventPlayer.objects.get(user=request.user, event=ev) + player.team = team + player.save() + else: + return render(request, 'events/join_team.html', {'event' : ev, 'logged': True, 'wrongpwd': False, 'registered' : True, 'notexist' : False}) + return redirect('events:event_info', event_slug=event_slug) + +@login_required +def team_info(request, name, event_slug): + event_info = get_object_or_404(Event, slug=event_slug) + team = Team.objects.get(name=name, event=event_info) + + catsDatas = [] + + players = EventPlayer.objects.filter(team=team, event=event_info) + users = [p.user for p in players] + all_teams = list(Team.objects.filter(event=event_info).order_by('-score', 'last_submission_date', 'name')) + rank = all_teams.index(get_object_or_404(Team, id=team.id, event=event_info)) + 1 + all_cats = Category.objects.all() + cats = [cat for cat in all_cats if CTF.objects.filter(category__name=cat.name, event=event_info)] + pointDatas = {} + + for cat in cats: + # prepare categories + solved_count = 0 + solved = [] + max_count = CTF.objects.filter(category__name=cat.name, event=event_info).count() + somme = 0 + pointDatas[cat.name] = [[event_info.start_date.timestamp()*1000, 0]] + for user_obj in users: + # get datas + solved_count += CTF_flags.objects.filter(user=user_obj, ctf__event=event_info , ctf__category__name=cat.name).count() + solved += CTF_flags.objects.filter(user=user_obj, ctf__category__name=cat.name, ctf__event=event_info).order_by('flag_date') + percent = (solved_count / max_count) * 100 + catsDatas.append([cat.name, solved_count, max_count, '{:.0f}'.format(percent)]) + for flag in solved: + somme += flag.ctf.points + pointDatas[cat.name].append([flag.flag_date.timestamp() * 1000, somme]) + + query = Q() + for user_obj in users: + query |= Q(user=user_obj) + query &= Q(ctf__event=event_info) + + solves = CTF_flags.objects.filter(query).order_by('-flag_date') + solved = [] + somme = 0 + solved.append([event_info.start_date.timestamp() * 1000, 0]) + for s in solves.reverse(): + somme += s.ctf.points + solved.append([s.flag_date.timestamp() * 1000,somme]) + + return render(request,'events/team.html', {'users':users, 'solves':solves,'solved':solved,'catsDatas': catsDatas, 'pointDatas': pointDatas, + 'rank': rank, 'team':team, 'score':somme, 'event':event_info, 'cats':cats}) + +@login_required +def manage_team(request, event_slug): + event_info = get_object_or_404(Event, slug=event_slug) + player = EventPlayer.objects.get(user=request.user, event=event_info) + members = EventPlayer.objects.filter(team=player.team, event=event_info) + + if request.method == 'POST': + tname = player.team.name + p_form = TeamUpdateForm(request.POST, instance=player.team) + error = None + success = None + if p_form.is_valid(): + pname = p_form.cleaned_data['name'] + if pname == tname: + pass + else: + if Team.objects.filter(name=pname, event=event_info).exists(): + error = _("Name already taken.") + ppassword = p_form.cleaned_data['password'] + if error is None: + p_form.save() + success = _("Updated.") + + context={'p_form': p_form, 'error':error, 'success' : success, 'player':player, 'members':members} + return render(request, 'events/manage_team.html', context) + else: + p_form = TeamUpdateForm(instance=player.team) + context={'p_form': p_form, 'player':player, 'members':members} + return render(request, 'events/manage_team.html',context) + + +@login_required +def leave_team(request, event_slug): + event_info = get_object_or_404(Event, slug=event_slug) + player = EventPlayer.objects.get(user=request.user, event=event_info) + team = Team.objects.get(event=event_info, name=player.team.name) + + team.score -= player.score + team.save() + player.team = None + solved = CTF_flags.objects.filter(user=player.user, ctf__event=event_info) + player.score = 0 + solved.delete() + player.save() + + members = EventPlayer.objects.filter(team=team, event=event_info) + if members.count() == 0: + team.delete() + + return render(request, 'events/create_team.html', {'event' : event_info, 'logged': True, 'wrongpwd': False, 'registered' : True, 'notexist' : False}) + +@login_required +def find_team(request, event_slug): + event_info = get_object_or_404(Event, slug=event_slug) + teams = Team.objects.filter(event=event_info, auto=True) + team = None + player = EventPlayer.objects.get(user=request.user, event=event_info) + + if event_info.auto_match == False: + return redirect('events:event_info', event_slug=event_slug) + for t in teams: + if EventPlayer.objects.filter(team=t, event=event_info).count() < event_info.team_size: + team = t + break + + if team is None: + teamname = get_random_name() + while Team.objects.filter(name=teamname, event=event_info).exists(): + teamname = get_random_name() + team = Team(name=teamname, password="".join([str(randint(0,10)) for _ in range(16)]), event=event_info, auto=True) + team.save() + + player.team = team + player.save() + + return redirect('events:event_info', event_slug=event_slug) \ No newline at end of file