1
0
mirror of https://gitlab.com/animath/si/plateforme.git synced 2025-05-17 22:52:46 +00:00

Compare commits

..

No commits in common. "758f714096430300e0e5a47058af1eb22cfc20e1" and "aac4fc59e62c94bfeee47c4b54340c6fa0475338" have entirely different histories.

6 changed files with 7 additions and 115 deletions

View File

@ -40,17 +40,7 @@ class Command(BaseCommand):
for pool in pools.all():
if options['verbosity'] >= 1:
self.stdout.write(f"Parsing notation sheet for pool {pool.short_name} for {tournament}")
try:
pool.parse_spreadsheet()
except Exception as e:
if options['verbosity'] >= 1:
self.stderr.write(
self.style.ERROR(f"Error while parsing pool {pool.short_name} for {tournament.name}: {e}"))
finally:
sleep(3) # Three calls = 3s sleep
pool.parse_spreadsheet()
sleep(3) # Three calls = 3s sleep
try:
tournament.parse_tweaks_spreadsheets()
except Exception as e:
if options['verbosity'] >= 1:
self.stderr.write(self.style.ERROR(f"Error while parsing tweaks for {tournament.name}: {e}"))
tournament.parse_tweaks_spreadskeets()

View File

@ -1,61 +0,0 @@
# Copyright (C) 2024 by Animath
# SPDX-License-Identifier: GPL-3.0-or-later
from hashlib import sha1
from django.conf import settings
from django.contrib.sites.models import Site
from django.core.management import BaseCommand
from django.urls import reverse
from django.utils import timezone
from django.utils.timezone import localtime
import gspread
from ...models import Tournament
class Command(BaseCommand):
def add_arguments(self, parser):
parser.add_argument(
'--tournament', '-t', help="Tournament name to update (if not set, all tournaments will be updated)",
)
def handle(self, *args, **options):
tournaments = Tournament.objects.all() if not options['tournament'] \
else Tournament.objects.filter(name=options['tournament']).all()
gc = gspread.service_account_from_dict(settings.GOOGLE_SERVICE_CLIENT)
http_client = gc.http_client
http_client.login()
site = Site.objects.get(pk=settings.SITE_ID)
now = localtime(timezone.now())
tomorrow = now + timezone.timedelta(days=1)
tomorrow -= timezone.timedelta(hours=now.hour, minutes=now.minute, seconds=now.second,
microseconds=now.microsecond)
for tournament in tournaments:
if options['verbosity'] >= 1:
self.stdout.write(f"Renewing Google Drive notifications for {tournament}")
if not tournament.notes_sheet_id:
if options['verbosity'] >= 1:
self.stdout.write(
self.style.WARNING(f"No spreadsheet found for {tournament}. Please create it first"))
continue
channel_id = sha1(f"{tournament.name}-{timezone.now().date()}-{site.domain}".encode()).hexdigest()
url = f"https://www.googleapis.com/drive/v3/files/{tournament.notes_sheet_id}/watch?supportsAllDrives=true"
notif_path = reverse('participation:tournament_gsheet_notifications', args=[tournament.pk])
notif_url = f"https://{site.domain}{notif_path}"
body = {
"id": channel_id,
"type": "web_hook",
"address": notif_url,
"expiration": str(int(1000 * tomorrow.timestamp())),
}
try:
http_client.request(method="POST", endpoint=url, json=body).raise_for_status()
except Exception as e:
self.stderr.write(self.style.ERROR(f"Error while renewing notifications for {tournament.name}: {e}"))

View File

@ -606,7 +606,7 @@ class Tournament(models.Model):
body = {"requests": format_requests}
worksheet.client.batch_update(spreadsheet.id, body)
def parse_tweaks_spreadsheets(self):
def parse_tweaks_spreadskeets(self):
if not self.pools.exists():
# Draw has not been done yet
return

View File

@ -4,8 +4,8 @@
from django.urls import path
from django.views.generic import TemplateView
from .views import CreateTeamView, FinalNotationSheetTemplateView, GSheetNotificationsView, JoinTeamView, \
MyParticipationDetailView, MyTeamDetailView, NotationSheetsArchiveView, NoteUpdateView, ParticipationDetailView, \
from .views import CreateTeamView, FinalNotationSheetTemplateView, JoinTeamView, MyParticipationDetailView, \
MyTeamDetailView, NotationSheetsArchiveView, NoteUpdateView, ParticipationDetailView, \
PassageDetailView, PassageUpdateView, PoolCreateView, PoolDetailView, PoolJuryView, PoolNotesTemplateView, \
PoolPresideJuryView, PoolRemoveJuryView, PoolUpdateView, PoolUploadNotesView, \
ScaleNotationSheetTemplateView, SolutionsDownloadView, SolutionUploadView, SynthesisUploadView, \
@ -46,8 +46,6 @@ urlpatterns = [
name="tournament_syntheses"),
path("tournament/<int:tournament_id>/notation/sheets/", NotationSheetsArchiveView.as_view(),
name="tournament_notation_sheets"),
path("tournament/<int:pk>/notation/notifications/", GSheetNotificationsView.as_view(),
name="tournament_gsheet_notifications"),
path("tournament/<int:pk>/publish-notes/<int:round>/", TournamentPublishNotesView.as_view(),
name="tournament_publish_notes"),
path("tournament/<int:pk>/harmonize/<int:round>/", TournamentHarmonizeView.as_view(),

View File

@ -1,10 +1,7 @@
# Copyright (C) 2020 by Animath
# SPDX-License-Identifier: GPL-3.0-or-later
import asyncio
from concurrent.futures import ThreadPoolExecutor
import csv
from hashlib import sha1
from io import BytesIO
import os
import subprocess
@ -26,9 +23,7 @@ from django.template.loader import render_to_string
from django.urls import reverse_lazy
from django.utils import timezone
from django.utils.crypto import get_random_string
from django.utils.decorators import method_decorator
from django.utils.translation import gettext_lazy as _
from django.views.decorators.csrf import csrf_exempt
from django.views.generic import CreateView, DetailView, FormView, RedirectView, TemplateView, UpdateView, View
from django.views.generic.detail import SingleObjectMixin
from django.views.generic.edit import FormMixin, ProcessFormView
@ -1879,33 +1874,6 @@ class NotationSheetsArchiveView(VolunteerMixin, DetailView):
return response
@method_decorator(csrf_exempt, name='dispatch')
class GSheetNotificationsView(View):
async def post(self, request, *args, **kwargs):
if not await Tournament.objects.filter(pk=kwargs['pk']).aexists():
return HttpResponse(status=404)
tournament = await Tournament.objects.prefetch_related('participations', 'pools').aget(pk=kwargs['pk'])
request.site.domain = "test.ynerant.fr"
expected_channel_id = sha1(f"{tournament.name}{timezone.now().date()}{request.site.domain}".encode()) \
.hexdigest()
if request.headers['X-Goog-Channel-ID'] != expected_channel_id:
raise ValueError(f"Invalid channel ID: {request.headers['X-Goog-Channel-ID']}")
if request.headers['X-Goog-Resource-State'] != 'update' \
or 'content' not in request.headers['X-Goog-Changed'].split(','):
return HttpResponse(status=204)
# Run the parsing in dedicated executors since it takes time
executor = ThreadPoolExecutor()
async for pool in tournament.pools.prefetch_related('participations', 'passages__notes', 'juries').all():
asyncio.get_event_loop().run_in_executor(executor, pool.parse_spreadsheet)
asyncio.get_event_loop().run_in_executor(executor, tournament.parse_tweaks_spreadsheets)
return HttpResponse(status=204)
class PassageDetailView(LoginRequiredMixin, DetailView):
model = Passage

View File

@ -16,10 +16,7 @@
30 6 * * 1 cd /code && python manage.py remind_payments &> /dev/null
# Check notation sheets every 15 minutes from 08:00 to 23:00 on fridays to mondays in april and may
# */15 8-23 * 4-5 5,6,7,1 cd /code && python manage.py parse_notation_sheets -v 0
# Update Google Drive notifications daily
0 0 * * * cd /code && python manage.py renew_gdrive_notifications &> /dev/null
*/15 8-23 * 4-5 5,6,7,1 cd /code && python manage.py parse_notation_sheets -v 0
# Clean temporary files
30 * * * * rm -rf /tmp/*