mirror of
				https://gitlab.com/animath/si/plateforme-corres2math.git
				synced 2025-11-04 11:52:27 +01:00 
			
		
		
		
	💚 Install libmagic in CI
This commit is contained in:
		@@ -4,7 +4,7 @@ from django import forms
 | 
			
		||||
from django.core.exceptions import ValidationError
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
 | 
			
		||||
from .models import Participation, Team
 | 
			
		||||
from .models import Participation, Team, Video
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TeamForm(forms.ModelForm):
 | 
			
		||||
@@ -42,3 +42,9 @@ class ParticipationForm(forms.ModelForm):
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = Participation
 | 
			
		||||
        fields = ('problem',)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class UploadVideoForm(forms.ModelForm):
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = Video
 | 
			
		||||
        fields = ('link',)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,6 @@
 | 
			
		||||
import re
 | 
			
		||||
 | 
			
		||||
from django.core.exceptions import ObjectDoesNotExist
 | 
			
		||||
from django.core.validators import RegexValidator
 | 
			
		||||
from django.db import models
 | 
			
		||||
from django.db.models import Index
 | 
			
		||||
@@ -63,10 +66,10 @@ class Participation(models.Model):
 | 
			
		||||
        verbose_name=_("problem number"),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    solution = models.ForeignKey(
 | 
			
		||||
    solution = models.OneToOneField(
 | 
			
		||||
        "participation.Video",
 | 
			
		||||
        on_delete=models.SET_NULL,
 | 
			
		||||
        related_name="+",
 | 
			
		||||
        related_name="participation_solution",
 | 
			
		||||
        null=True,
 | 
			
		||||
        default=None,
 | 
			
		||||
        verbose_name=_("solution video"),
 | 
			
		||||
@@ -81,10 +84,10 @@ class Participation(models.Model):
 | 
			
		||||
        verbose_name=_("received participation"),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    synthesis = models.ForeignKey(
 | 
			
		||||
    synthesis = models.OneToOneField(
 | 
			
		||||
        "participation.Video",
 | 
			
		||||
        on_delete=models.SET_NULL,
 | 
			
		||||
        related_name="+",
 | 
			
		||||
        related_name="participation_synthesis",
 | 
			
		||||
        null=True,
 | 
			
		||||
        default=None,
 | 
			
		||||
        verbose_name=_("synthesis video"),
 | 
			
		||||
@@ -99,12 +102,6 @@ class Participation(models.Model):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Video(models.Model):
 | 
			
		||||
    participation = models.ForeignKey(
 | 
			
		||||
        "participation.Participation",
 | 
			
		||||
        on_delete=models.CASCADE,
 | 
			
		||||
        verbose_name=_("participation"),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    link = models.URLField(
 | 
			
		||||
        verbose_name=_("link"),
 | 
			
		||||
        help_text=_("The full video link."),
 | 
			
		||||
@@ -117,6 +114,24 @@ class Video(models.Model):
 | 
			
		||||
        help_text=_("The video got the validation of the administrators."),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def participation(self):
 | 
			
		||||
        try:
 | 
			
		||||
            return self.participation_solution
 | 
			
		||||
        except ObjectDoesNotExist:
 | 
			
		||||
            return self.participation_synthesis
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def platform(self):
 | 
			
		||||
        if "youtube.com" in self.link or "youtu.be" in self.link:
 | 
			
		||||
            return "youtube"
 | 
			
		||||
        return "unknown"
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def youtube_code(self):
 | 
			
		||||
        return re.compile("(https?://|)(www\\.|)(youtube\\.com/watch\\?v=|youtu\\.be/)([a-zA-Z0-9-_]*)?.*?")\
 | 
			
		||||
            .match("https://www.youtube.com/watch?v=73nsrixx7eI").group(4)
 | 
			
		||||
 | 
			
		||||
    def __str__(self):
 | 
			
		||||
        return _("Video of team {name} ({trigram})")\
 | 
			
		||||
            .format(name=self.participation.team.name, trigram=self.participation.team.trigram)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,10 @@
 | 
			
		||||
from participation.models import Participation
 | 
			
		||||
from participation.models import Participation, Video
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def create_team_participation(instance, **_):
 | 
			
		||||
    Participation.objects.get_or_create(team=instance)
 | 
			
		||||
    participation = Participation.objects.get_or_create(team=instance)[0]
 | 
			
		||||
    if not participation.solution:
 | 
			
		||||
        participation.solution = Video.objects.create()
 | 
			
		||||
    if not participation.synthesis:
 | 
			
		||||
        participation.synthesis = Video.objects.create()
 | 
			
		||||
    participation.save()
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,61 @@
 | 
			
		||||
{% extends "base.html" %}
 | 
			
		||||
 | 
			
		||||
{% load i18n %}
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
{% trans "any" as any %}
 | 
			
		||||
<div class="row mt-4">
 | 
			
		||||
    <div class="col-xl-4">
 | 
			
		||||
    <div class="card bg-light shadow">
 | 
			
		||||
        <div class="card-header text-center">
 | 
			
		||||
            <h4>{% trans "Participation of team" %} {{ participation.team.name }} ({{ participation.team.trigram }})</h4>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="card-body">
 | 
			
		||||
            <dl class="row">
 | 
			
		||||
                <dt class="col-sm-6 text-right">{% trans "Chosen problem:" %}</dt>
 | 
			
		||||
                <dd class="col-sm-6">{{ participation.get_problem_display }}</dd>
 | 
			
		||||
            </dl>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="card-footer text-center">
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="col-xl-8">
 | 
			
		||||
    <div class="card bg-light shadow">
 | 
			
		||||
        <div class="card-header text-center">
 | 
			
		||||
            <h4>{% trans "Participation of team" %} {{ participation.team.name }} ({{ participation.team.trigram }})</h4>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="card-body">
 | 
			
		||||
            {% trans "No video sent" as novideo %}
 | 
			
		||||
            {% trans "Video link:" %} <a href="{{ participation.solution.link|default:"#" }}" target="_blank">{{ participation.solution.link|default:novideo }}</a>
 | 
			
		||||
            <button class="btn btn-primary" data-toggle="modal" data-target="#uploadVideoModal">{% trans "Upload" %}</button>
 | 
			
		||||
            {% if participation.solution.platform == "youtube" %}
 | 
			
		||||
                {% include "participation/youtube_iframe.html" with youtube_code=participation.solution.youtube_code %}
 | 
			
		||||
            {% else %}
 | 
			
		||||
                <div class="alert alert-danger">
 | 
			
		||||
                {% trans "This video platform is not supported yet." %}
 | 
			
		||||
                </div>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
{% trans "Upload video" as modal_title %}
 | 
			
		||||
{% trans "Upload" as modal_button %}
 | 
			
		||||
{% url "participation:upload_video" pk=participation.solution_id as modal_action %}
 | 
			
		||||
{% include "base_modal.html" with modal_id="uploadVideo" %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block extrajavascript %}
 | 
			
		||||
    <script>
 | 
			
		||||
        $(document).ready(function() {
 | 
			
		||||
            $('button[data-target="#uploadVideoModal"]').click(function() {
 | 
			
		||||
                let modalBody = $("#uploadVideoModal div.modal-body");
 | 
			
		||||
                if (!modalBody.html().trim())
 | 
			
		||||
                    modalBody.load("{% url "participation:upload_video" pk=participation.solution_id %} #form-content");
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    </script>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
							
								
								
									
										14
									
								
								apps/participation/templates/participation/upload_video.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								apps/participation/templates/participation/upload_video.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
{% extends "base.html" %}
 | 
			
		||||
 | 
			
		||||
{% load crispy_forms_filters i18n %}
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
    <form method="post">
 | 
			
		||||
        <div id="form-content">
 | 
			
		||||
            {% csrf_token %}
 | 
			
		||||
            {{ form|crispy }}
 | 
			
		||||
        </div>
 | 
			
		||||
        <button class="btn btn-success" type="submit">{% trans "Upload" %}</button>
 | 
			
		||||
    </form>
 | 
			
		||||
{% endblock content %}
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,8 @@
 | 
			
		||||
<div style="position: relative; width: 100%; padding-bottom: 56.25%;">
 | 
			
		||||
    <iframe src="https://www.youtube.com/embed/{{ youtube_code }}"
 | 
			
		||||
            frameborder="0"
 | 
			
		||||
            style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"
 | 
			
		||||
            allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
 | 
			
		||||
            allowfullscreen>
 | 
			
		||||
    </iframe>
 | 
			
		||||
</div>
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
from django.urls import path
 | 
			
		||||
 | 
			
		||||
from .views import CreateTeamView, JoinTeamView, MyTeamDetailView, TeamDetailView, TeamUpdateView
 | 
			
		||||
from .views import CreateTeamView, JoinTeamView, MyParticipationDetailView, MyTeamDetailView, ParticipationDetailView,\
 | 
			
		||||
    TeamDetailView, TeamUpdateView, UploadVideoView
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
app_name = "participation"
 | 
			
		||||
@@ -11,4 +12,7 @@ urlpatterns = [
 | 
			
		||||
    path("team/", MyTeamDetailView.as_view(), name="my_team_detail"),
 | 
			
		||||
    path("team/<int:pk>/", TeamDetailView.as_view(), name="team_detail"),
 | 
			
		||||
    path("team/<int:pk>/update/", TeamUpdateView.as_view(), name="update_team"),
 | 
			
		||||
    path("detail/", MyParticipationDetailView.as_view(), name="my_participation_detail"),
 | 
			
		||||
    path("detail/<int:pk>/", ParticipationDetailView.as_view(), name="participation_detail"),
 | 
			
		||||
    path("detail/upload-video/<int:pk>/", UploadVideoView.as_view(), name="upload_video"),
 | 
			
		||||
]
 | 
			
		||||
 
 | 
			
		||||
@@ -5,8 +5,8 @@ from django.urls import reverse_lazy
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
from django.views.generic import CreateView, DetailView, FormView, RedirectView, UpdateView
 | 
			
		||||
 | 
			
		||||
from .forms import JoinTeamForm, ParticipationForm, TeamForm
 | 
			
		||||
from .models import Team
 | 
			
		||||
from .forms import JoinTeamForm, ParticipationForm, TeamForm, UploadVideoForm
 | 
			
		||||
from .models import Participation, Team, Video
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CreateTeamView(LoginRequiredMixin, CreateView):
 | 
			
		||||
@@ -99,3 +99,27 @@ class TeamUpdateView(LoginRequiredMixin, UpdateView):
 | 
			
		||||
 | 
			
		||||
    def get_success_url(self):
 | 
			
		||||
        return reverse_lazy("participation:team_detail", args=(self.object.pk,))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MyParticipationDetailView(LoginRequiredMixin, RedirectView):
 | 
			
		||||
    def get_redirect_url(self, *args, **kwargs):
 | 
			
		||||
        user = self.request.user
 | 
			
		||||
        registration = user.registration
 | 
			
		||||
        if registration.participates:
 | 
			
		||||
            if registration.team:
 | 
			
		||||
                return reverse_lazy("participation:participation_detail", args=(registration.team.participation.id,))
 | 
			
		||||
            raise PermissionDenied(_("You are not in a team."))
 | 
			
		||||
        raise PermissionDenied(_("You don't participate, so you don't have any team."))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ParticipationDetailView(LoginRequiredMixin, DetailView):
 | 
			
		||||
    model = Participation
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class UploadVideoView(LoginRequiredMixin, UpdateView):
 | 
			
		||||
    model = Video
 | 
			
		||||
    form_class = UploadVideoForm
 | 
			
		||||
    template_name = "participation/upload_video.html"
 | 
			
		||||
 | 
			
		||||
    def get_success_url(self):
 | 
			
		||||
        return reverse_lazy("participation:participation_detail", args=(self.object.participation.pk,))
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user