|
1 |
| - |
| 1 | +import json |
2 | 2 |
|
3 | 3 | from django.http.request import HttpRequest
|
4 | 4 | from django.http.response import HttpResponse
|
5 | 5 | from ctfpad.decorators import only_if_authenticated_user
|
6 | 6 | from django.contrib import messages
|
7 | 7 | from django.shortcuts import render, get_object_or_404, redirect
|
8 |
| -from django.views.generic import ListView, DetailView, UpdateView, DeleteView, CreateView |
| 8 | +from django.views.generic import ListView, DetailView, UpdateView, DeleteView, CreateView, FormView |
9 | 9 | from django.urls import reverse, reverse_lazy
|
10 | 10 | from django.contrib.auth.mixins import LoginRequiredMixin
|
11 | 11 | from django.contrib.messages.views import SuccessMessageMixin
|
|
15 | 15 | ChallengeUpdateForm,
|
16 | 16 | ChallengeSetFlagForm,
|
17 | 17 | ChallengeFileCreateForm,
|
| 18 | + ChallengeImportForm, |
18 | 19 | )
|
19 |
| -from ctfpad.models import Challenge, Ctf |
| 20 | +from ctfpad.models import Challenge, Ctf, ChallengeCategory |
20 | 21 | from ctftools.settings import HEDGEDOC_URL
|
21 | 22 |
|
22 | 23 | from ctfpad.helpers import (
|
@@ -69,6 +70,60 @@ def get_success_url(self):
|
69 | 70 | return reverse("ctfpad:challenges-detail", kwargs={'pk': self.object.pk})
|
70 | 71 |
|
71 | 72 |
|
| 73 | +class ChallengeImportView(LoginRequiredMixin, FormView): |
| 74 | + model = Challenge |
| 75 | + template_name = "ctfpad/challenges/import.html" |
| 76 | + login_url = "/users/login/" |
| 77 | + redirect_field_name = "redirect_to" |
| 78 | + form_class = ChallengeImportForm |
| 79 | + success_message = "Challenges were successfully imported!" |
| 80 | + |
| 81 | + def get(self, request, *args, **kwargs): |
| 82 | + self.initial["ctf"] = self.kwargs.get("ctf") |
| 83 | + form = self.form_class(initial=self.initial) |
| 84 | + return render(request, self.template_name, {'form': form}) |
| 85 | + |
| 86 | + def form_valid(self, form): |
| 87 | + ctf_id = self.kwargs.get("ctf") |
| 88 | + ctf = Ctf.objects.get(pk=ctf_id) |
| 89 | + data = form.cleaned_data['data'] |
| 90 | + |
| 91 | + try: |
| 92 | + for challenge in data: |
| 93 | + category, created = ChallengeCategory.objects.get_or_create(name=challenge["category"].strip().lower()) |
| 94 | + points = 0 |
| 95 | + description = "" |
| 96 | + |
| 97 | + if form.cleaned_data['format'] == 'CTFd': |
| 98 | + points = challenge.get("value") |
| 99 | + elif form.cleaned_data['format'] == 'rCTF': |
| 100 | + points = challenge.get("points") |
| 101 | + description = challenge.get("description") |
| 102 | + |
| 103 | + defaults = { |
| 104 | + "name": challenge.get("name"), |
| 105 | + "points": points, |
| 106 | + "category": category, |
| 107 | + "description": description, |
| 108 | + "ctf": ctf, |
| 109 | + } |
| 110 | + |
| 111 | + Challenge.objects.update_or_create( |
| 112 | + defaults=defaults, |
| 113 | + name=challenge.get("name"), |
| 114 | + ctf=ctf, |
| 115 | + ) |
| 116 | + |
| 117 | + messages.success(self.request, "Import successful!") |
| 118 | + return super().form_valid(form) |
| 119 | + except Exception as e: |
| 120 | + messages.error(self.request, f"Error: {str(e)}") |
| 121 | + return self.form_invalid(form) |
| 122 | + |
| 123 | + def get_success_url(self): |
| 124 | + return reverse("ctfpad:ctfs-detail", kwargs={'pk': self.initial["ctf"]}) |
| 125 | + |
| 126 | + |
72 | 127 | class ChallengeDetailView(LoginRequiredMixin, DetailView):
|
73 | 128 | model = Challenge
|
74 | 129 | template_name = "ctfpad/challenges/detail.html"
|
@@ -101,7 +156,7 @@ def form_valid(self, form):
|
101 | 156 | if "solvers" in form.cleaned_data:
|
102 | 157 |
|
103 | 158 | if (len(form.cleaned_data["solvers"]) > 0 and not form.cleaned_data["flag"]) or \
|
104 |
| - (len(form.cleaned_data["solvers"]) == 0 and form.cleaned_data["flag"]): |
| 159 | + (len(form.cleaned_data["solvers"]) == 0 and form.cleaned_data["flag"]): |
105 | 160 | messages.error(
|
106 | 161 | self.request, "Cannot set flag without solver(s)")
|
107 | 162 | return redirect("ctfpad:challenges-detail", self.object.id)
|
|
0 commit comments