From 6ecb94eab5836635efb2a655abe3f1506b40226e Mon Sep 17 00:00:00 2001 From: Danhia Date: Sun, 17 Sep 2023 20:39:13 +0200 Subject: [PATCH] added speed bonus points for events --- src/accounts/views/connection.py | 1 - src/ctfs/migrations/0009_ctf_flags_bonus.py | 18 ++++++++ src/ctfs/models.py | 1 + src/events/admin.py | 7 ++- src/events/migrations/0011_bonus_points.py | 28 ++++++++++++ .../migrations/0012_auto_20230917_2038.py | 24 ++++++++++ src/events/models.py | 12 +++-- src/events/templates/events/ctf_info.html | 8 +++- src/events/templates/events/profile.html | 2 + src/events/views/events.py | 45 +++++++++++++++---- src/home/views.py | 1 - 11 files changed, 132 insertions(+), 15 deletions(-) create mode 100644 src/ctfs/migrations/0009_ctf_flags_bonus.py create mode 100644 src/events/migrations/0011_bonus_points.py create mode 100644 src/events/migrations/0012_auto_20230917_2038.py diff --git a/src/accounts/views/connection.py b/src/accounts/views/connection.py index b441b35..19ea53f 100644 --- a/src/accounts/views/connection.py +++ b/src/accounts/views/connection.py @@ -87,7 +87,6 @@ def connect_discord(request): @login_required def authorize_discord(request): if request.user.userprofileinfo.discord_id: - print("Already") return bad_request(request, "Already connected") try: token = oauth.discord.authorize_access_token(request) diff --git a/src/ctfs/migrations/0009_ctf_flags_bonus.py b/src/ctfs/migrations/0009_ctf_flags_bonus.py new file mode 100644 index 0000000..c93799f --- /dev/null +++ b/src/ctfs/migrations/0009_ctf_flags_bonus.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.11 on 2023-09-17 17:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ctfs', '0008_auto_20220215_1713'), + ] + + operations = [ + migrations.AddField( + model_name='ctf_flags', + name='bonus', + field=models.PositiveSmallIntegerField(default=0), + ), + ] diff --git a/src/ctfs/models.py b/src/ctfs/models.py index 50a418b..7c31b62 100644 --- a/src/ctfs/models.py +++ b/src/ctfs/models.py @@ -45,6 +45,7 @@ class CTF_flags(models.Model): user = models.ForeignKey(User, unique=False, on_delete=models.CASCADE) ctf = models.ForeignKey(CTF, unique=False, on_delete=models.CASCADE) flag_date = models.DateTimeField('Flag date') + bonus = models.PositiveSmallIntegerField(default=0) class Meta: ordering = ['-flag_date'] diff --git a/src/events/admin.py b/src/events/admin.py index 8d61ab2..e4d542f 100644 --- a/src/events/admin.py +++ b/src/events/admin.py @@ -1,5 +1,5 @@ from django.contrib import admin -from .models import Event, EventPlayer, Team +from .models import Event, EventPlayer, Team, Bonus @admin.register(Event) class event(admin.ModelAdmin): @@ -27,3 +27,8 @@ class team(admin.ModelAdmin): list_filter = ('event',) # search list search_fields = ['name'] + +@admin.register(Bonus) +class bonus(admin.ModelAdmin): + #list display + list_display = ['points', 'absolute'] diff --git a/src/events/migrations/0011_bonus_points.py b/src/events/migrations/0011_bonus_points.py new file mode 100644 index 0000000..65a2cac --- /dev/null +++ b/src/events/migrations/0011_bonus_points.py @@ -0,0 +1,28 @@ +# Generated by Django 3.2.11 on 2023-09-17 17:00 + +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('events', '0010_event_campus'), + ] + + operations = [ + migrations.CreateModel( + name='Bonus', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('absolute', models.BooleanField(default=True)), + ('points', models.CharField(max_length=100, validators=[django.core.validators.int_list_validator])), + ], + ), + migrations.AddField( + model_name='event', + name='bonus', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='events.bonus'), + ), + ] diff --git a/src/events/migrations/0012_auto_20230917_2038.py b/src/events/migrations/0012_auto_20230917_2038.py new file mode 100644 index 0000000..625641a --- /dev/null +++ b/src/events/migrations/0012_auto_20230917_2038.py @@ -0,0 +1,24 @@ +# Generated by Django 3.2.11 on 2023-09-17 18:38 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('events', '0011_bonus_points'), + ] + + operations = [ + migrations.AlterField( + model_name='event', + name='bonus', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='events.bonus'), + ), + migrations.AlterField( + model_name='eventplayer', + name='team', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='events.team'), + ), + ] diff --git a/src/events/models.py b/src/events/models.py index 12124d2..4bf3423 100644 --- a/src/events/models.py +++ b/src/events/models.py @@ -1,10 +1,17 @@ from django.db import models from django.contrib.auth.models import User from django.contrib.auth.models import timezone +from django.core.validators import int_list_validator import uuid from accounts.models import Campus # Create your models here. +class Bonus(models.Model): + absolute = models.BooleanField(default=True) + points = models.CharField(validators=[int_list_validator], max_length=100) + def __str__(self): + return self.points + class Event(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) name = models.CharField(max_length=200) @@ -19,6 +26,7 @@ class Event(models.Model): auto_match = models.BooleanField(default=False) dynamic = models.BooleanField(default=False) campus = models.ManyToManyField(Campus, blank=True) + bonus = models.ForeignKey(Bonus, null=True, on_delete=models.SET_NULL, blank=True) def __str__(self): return self.name @@ -37,8 +45,6 @@ class EventPlayer(models.Model): event = models.ForeignKey(Event, on_delete=models.CASCADE) score = models.PositiveIntegerField(default=0, db_index=True) last_submission_date = models.DateTimeField('Last Submission Date', default=timezone.now) - team = models.ForeignKey(Team, on_delete=models.CASCADE, null=True) + team = models.ForeignKey(Team, on_delete=models.CASCADE, null=True, blank=True) class Meta: ordering = ['-score', 'last_submission_date', 'user__username'] - - diff --git a/src/events/templates/events/ctf_info.html b/src/events/templates/events/ctf_info.html index aca18ef..3513148 100644 --- a/src/events/templates/events/ctf_info.html +++ b/src/events/templates/events/ctf_info.html @@ -21,7 +21,10 @@ diff --git a/src/events/templates/events/profile.html b/src/events/templates/events/profile.html index 873f61c..737a135 100644 --- a/src/events/templates/events/profile.html +++ b/src/events/templates/events/profile.html @@ -22,6 +22,7 @@ {% trans "Challenge Name" %} {% trans "Category" %} {% trans "Points" %} + {% trans "Bonus" %} {% trans "Date" %} @@ -31,6 +32,7 @@ {{ s.ctf.name }} {{ s.ctf.category.name}} {{ s.ctf.points }} + {{ s.bonus }} {{ s.flag_date|date:"Y-m-d H:i:s" }} {% endfor %} diff --git a/src/events/views/events.py b/src/events/views/events.py index a372932..80c64f8 100644 --- a/src/events/views/events.py +++ b/src/events/views/events.py @@ -41,6 +41,31 @@ def actualize_points(ctf): player.team.score -= diff player.team.save() +def compute_bonus_points(ctf): + if not ctf.event.bonus: + return 0 + + solves = CTF_flags.objects.filter(ctf=ctf) + bonuses = ctf.event.bonus.points.split(',') + + if len(solves) >= len(bonuses): + return 0 + else: + if ctf.event.bonus.absolute == True: + return int(bonuses[len(solves)]) + else: + return int(bonuses[len(solves)]) * ctf.points // 100 + +def format_bonus_points(ctf): + if not ctf.event.bonus: + return None + + bonuses = ctf.event.bonus.points.split(',') + if ctf.event.bonus.absolute == True: + return ''.join([b + ', ' for b in bonuses])[:-2] + return ''.join([str(ctf.points * int(b) // 100) + ', ' for b in bonuses])[:-2] + + # Create your views here. def events(request): list_events = Event.objects.filter().order_by('-end_date', 'start_date') @@ -60,6 +85,7 @@ def chall_event_info(request, event_slug, chall_slug): notsub = False noteam = False player = None + bonus = 0 if request.user.is_authenticated and not request.user.is_staff: player = EventPlayer.objects.filter(event=event_info, user=request.user) if not player: @@ -80,6 +106,8 @@ def chall_event_info(request, event_slug, chall_slug): notsub = True if request.GET.get('NoTeam'): noteam = True + bonus = request.GET.get('Bonus') + bonus_points = format_bonus_points(ctf_info) solved_challs = CTF_flags.objects.filter(ctf=ctf_info).order_by('flag_date') solved_list = [] for s in solved_challs: @@ -89,7 +117,7 @@ def chall_event_info(request, event_slug, chall_slug): solved_list.append([s.user, s.flag_date]) description = get_description_by_lang(ctf_info) return render(request, 'events/ctf_info.html', { 'ctf' : ctf_info, 'event':event_info, 'solved_list': solved_list, 'description': description, 'eventisover': eventisover, 'alreadyflag': alreadyflag, - 'congrat': congrat, 'wrongflag': wrongflag, 'errorform': errorform, 'notsub': notsub, 'noteam':noteam}) + 'congrat': congrat, 'wrongflag': wrongflag, 'errorform': errorform, 'notsub': notsub, 'noteam':noteam, 'bonus':bonus, 'bonus_points':bonus_points}) def event(request, event_slug): event_info = get_object_or_404(Event, slug=event_slug) @@ -183,20 +211,21 @@ def submit_event_flag(request, event_slug, chall_slug): if form.is_valid(): if ctf_info.flag == request.POST.get('flag'): - new = CTF_flags(user = request.user, ctf = ctf_info, flag_date = timezone.now()) + bonus = compute_bonus_points(ctf_info) + new = CTF_flags(user = request.user, ctf = ctf_info, flag_date = timezone.now(), bonus = bonus) new.save() if ctf_info.points > 0: player.last_submission_date = timezone.now() - player.score += ctf_info.points + player.score += (ctf_info.points + bonus) player.save() if player.team: if ctf_info.points > 0: player.team.last_submission_date = timezone.now() - player.team.score += ctf_info.points + player.team.score += (ctf_info.points + bonus) player.team.save() if ev.dynamic: actualize_points(ctf_info) - response['Location'] += '?Congrat=1' + response['Location'] += '?Congrat=1&Bonus=' + str(bonus) return response else: response['Location'] += '?WrongFlag=1' @@ -278,7 +307,7 @@ def profile(request, user_name, event_slug): 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 + somme += (flag.ctf.points + flag.bonus) pointDatas[cat.name].append([flag.flag_date.timestamp() * 1000, somme]) solves = CTF_flags.objects.filter(user=user_obj, ctf__event=event_info).order_by('-flag_date') @@ -286,10 +315,10 @@ def profile(request, user_name, event_slug): somme = 0 solved.append([event_info.start_date.timestamp() * 1000, 0]) for s in solves.reverse(): - somme += s.ctf.points + somme += (s.ctf.points + s.bonus) solved.append([s.flag_date.timestamp() * 1000,somme]) return render(request,'events/profile.html', {'user':user_obj, 'solves':solves,'solved':solved,'catsDatas': catsDatas, 'pointDatas': pointDatas, - 'rank': rank, 'score' : somme, 'cats':cats, 'event': event_info}) + 'rank': rank, 'score' : player.score, 'cats':cats, 'event': event_info}) diff --git a/src/home/views.py b/src/home/views.py index 6221457..98fed33 100644 --- a/src/home/views.py +++ b/src/home/views.py @@ -35,7 +35,6 @@ def home(request): lang_code = request.session[LANGUAGE_SESSION_KEY] url_translated = translate_url(request.path, lang_code) if request.path != url_translated: - print("%s\n%s" % (request.path, url_translated)) response = HttpResponseRedirect(url_translated) return response news = new.objects.order_by('-pub_date')[:5]