From c882d1ac7a77ae3773a85252f48c417c34ff23ab Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sun, 20 Sep 2020 22:31:37 +0200 Subject: [PATCH] Restart the project in Django --- .gitignore | 45 ++- .htaccess | 4 - Dockerfile | 52 ++- README.md | 64 ++++ apps/api/__init__.py | 1 + apps/api/apps.py | 10 + apps/api/serializers.py | 15 + apps/api/urls.py | 18 + apps/api/viewsets.py | 17 + ...torisation de droit à l'image - majeur.pdf | Bin 95130 -> 0 bytes ...torisation de droit à l'image - mineur.pdf | Bin 95602 -> 0 bytes assets/favicon.ico | Bin 8794 -> 0 bytes assets/style.css | 47 --- corres2math.cron | 5 + corres2math/__init__.py | 0 corres2math/asgi.py | 16 + corres2math/inputs.py | 322 +++++++++++++++++ corres2math/middlewares.py | 93 +++++ corres2math/settings.py | 202 +++++++++++ corres2math/settings_dev.py | 5 + corres2math/settings_prod.py | 30 ++ corres2math/static/favicon.ico | Bin 0 -> 7302 bytes {assets => corres2math/static}/logo.png | Bin corres2math/urls.py | 35 ++ corres2math/wsgi.py | 16 + dispatcher.php | 95 ----- entrypoint.sh | 12 + locale/fr/LC_MESSAGES/django.po | 270 ++++++++++++++ manage.py | 21 ++ nginx_corres2math.conf | 19 + requirements.txt | 15 + server_files/403.php | 16 - server_files/404.php | 16 - server_files/classes/Document.php | 91 ----- server_files/classes/Phase.php | 68 ---- server_files/classes/Question.php | 185 ---------- server_files/classes/Reason.php | 41 --- server_files/classes/Role.php | 41 --- server_files/classes/SchoolClass.php | 54 --- server_files/classes/Team.php | 261 -------------- server_files/classes/User.php | 335 ------------------ server_files/classes/ValidationStatus.php | 41 --- server_files/classes/Video.php | 132 ------- server_files/config.php | 227 ------------ server_files/controllers/admins.php | 8 - server_files/controllers/ajouter_admin.php | 56 --- server_files/controllers/ajouter_equipe.php | 75 ---- server_files/controllers/calendrier.php | 76 ---- .../controllers/commenter_echange.php | 77 ---- server_files/controllers/confirmer_mail.php | 25 -- server_files/controllers/connexion.php | 170 --------- server_files/controllers/deconnexion.php | 14 - server_files/controllers/envoyer_video.php | 72 ---- server_files/controllers/equipe.php | 112 ------ server_files/controllers/exporter_donnees.php | 42 --- server_files/controllers/index.php | 16 - server_files/controllers/informations.php | 117 ------ server_files/controllers/inscription.php | 84 ----- server_files/controllers/ma_participation.php | 23 -- server_files/controllers/mon_compte.php | 177 --------- server_files/controllers/mon_equipe.php | 112 ------ server_files/controllers/poser_questions.php | 137 ------- server_files/controllers/probleme.php | 26 -- server_files/controllers/profiles.php | 9 - server_files/controllers/rejoindre_equipe.php | 71 ---- .../controllers/repondre_questions.php | 126 ------- .../controllers/suivi_correspondances.php | 141 -------- server_files/controllers/view_file.php | 51 --- server_files/model.php | 326 ----------------- server_files/services/mail.php | 256 ------------- .../services/mail_templates/add_admin.html | 22 -- .../services/mail_templates/add_team.html | 17 - .../mail_templates/change_email_address.html | 16 - .../mail_templates/change_password.html | 18 - .../mail_templates/confirm_email.html | 18 - .../mail_templates/forgotten_password.html | 20 -- .../services/mail_templates/join_team.html | 17 - .../services/mail_templates/new_answer.html | 19 - .../services/mail_templates/new_video.html | 18 - .../services/mail_templates/register.html | 16 - .../mail_templates/request_validation.html | 19 - .../mail_templates/unvalidate_team.html | 21 -- .../mail_templates/validate_team.html | 18 - .../mail_templates/video_accepted_answer.html | 21 -- .../video_accepted_solution.html | 21 -- .../mail_templates/video_rejected_answer.html | 23 -- .../video_rejected_solution.html | 23 -- server_files/utils.php | 48 --- server_files/views/admins.php | 67 ---- server_files/views/ajouter_admin.php | 43 --- server_files/views/ajouter_equipe.php | 78 ---- server_files/views/calendrier.php | 138 -------- server_files/views/commenter_echange.php | 131 ------- server_files/views/connexion.php | 65 ---- server_files/views/envoyer_video.php | 87 ----- server_files/views/equipe.php | 134 ------- server_files/views/exporter_donnees.php | 33 -- server_files/views/footer.php | 18 - server_files/views/header.php | 177 --------- server_files/views/index.html | 54 --- server_files/views/index.php | 76 ---- server_files/views/informations.php | 119 ------- server_files/views/inscription.php | 153 -------- server_files/views/ma_participation.php | 132 ------- server_files/views/mon_compte.php | 177 --------- server_files/views/mon_equipe.php | 135 ------- server_files/views/poser_questions.php | 98 ----- server_files/views/probleme.php | 82 ----- server_files/views/profiles.php | 63 ---- server_files/views/rejoindre_equipe.php | 39 -- server_files/views/repondre_questions.php | 93 ----- server_files/views/suivi_correspondances.php | 180 ---------- setup/create_database.sql | 146 -------- setup/msmtprc | 18 - templates/400.html | 8 + templates/403.html | 13 + templates/404.html | 13 + templates/500.html | 8 + templates/amount_input.html | 11 + templates/autocomplete_model.html | 9 + templates/base.html | 154 ++++++++ templates/index.html | 6 + .../email_validation_complete.html | 27 ++ .../email_validation_email_sent.html | 18 + templates/registration/logged_out.html | 10 + templates/registration/login.html | 25 ++ .../mails/email_validation_email.html | 36 ++ .../mails/email_validation_email.txt | 13 + .../registration/password_change_done.html | 9 + .../registration/password_change_form.html | 13 + .../registration/password_reset_complete.html | 12 + .../registration/password_reset_confirm.html | 17 + .../registration/password_reset_done.html | 10 + .../registration/password_reset_form.html | 13 + templates/registration/signup.html | 17 + 135 files changed, 1694 insertions(+), 6995 deletions(-) delete mode 100644 .htaccess create mode 100644 README.md create mode 100644 apps/api/__init__.py create mode 100644 apps/api/apps.py create mode 100644 apps/api/serializers.py create mode 100644 apps/api/urls.py create mode 100644 apps/api/viewsets.py delete mode 100644 assets/Autorisation de droit à l'image - majeur.pdf delete mode 100644 assets/Autorisation de droit à l'image - mineur.pdf delete mode 100644 assets/favicon.ico delete mode 100644 assets/style.css create mode 100644 corres2math.cron create mode 100644 corres2math/__init__.py create mode 100644 corres2math/asgi.py create mode 100644 corres2math/inputs.py create mode 100644 corres2math/middlewares.py create mode 100644 corres2math/settings.py create mode 100644 corres2math/settings_dev.py create mode 100644 corres2math/settings_prod.py create mode 100644 corres2math/static/favicon.ico rename {assets => corres2math/static}/logo.png (100%) create mode 100644 corres2math/urls.py create mode 100644 corres2math/wsgi.py delete mode 100644 dispatcher.php create mode 100755 entrypoint.sh create mode 100644 locale/fr/LC_MESSAGES/django.po create mode 100755 manage.py create mode 100644 nginx_corres2math.conf create mode 100644 requirements.txt delete mode 100644 server_files/403.php delete mode 100644 server_files/404.php delete mode 100644 server_files/classes/Document.php delete mode 100644 server_files/classes/Phase.php delete mode 100644 server_files/classes/Question.php delete mode 100644 server_files/classes/Reason.php delete mode 100644 server_files/classes/Role.php delete mode 100644 server_files/classes/SchoolClass.php delete mode 100644 server_files/classes/Team.php delete mode 100644 server_files/classes/User.php delete mode 100644 server_files/classes/ValidationStatus.php delete mode 100644 server_files/classes/Video.php delete mode 100644 server_files/config.php delete mode 100644 server_files/controllers/admins.php delete mode 100644 server_files/controllers/ajouter_admin.php delete mode 100644 server_files/controllers/ajouter_equipe.php delete mode 100644 server_files/controllers/calendrier.php delete mode 100644 server_files/controllers/commenter_echange.php delete mode 100644 server_files/controllers/confirmer_mail.php delete mode 100644 server_files/controllers/connexion.php delete mode 100644 server_files/controllers/deconnexion.php delete mode 100644 server_files/controllers/envoyer_video.php delete mode 100644 server_files/controllers/equipe.php delete mode 100644 server_files/controllers/exporter_donnees.php delete mode 100644 server_files/controllers/index.php delete mode 100644 server_files/controllers/informations.php delete mode 100644 server_files/controllers/inscription.php delete mode 100644 server_files/controllers/ma_participation.php delete mode 100644 server_files/controllers/mon_compte.php delete mode 100644 server_files/controllers/mon_equipe.php delete mode 100644 server_files/controllers/poser_questions.php delete mode 100644 server_files/controllers/probleme.php delete mode 100644 server_files/controllers/profiles.php delete mode 100644 server_files/controllers/rejoindre_equipe.php delete mode 100644 server_files/controllers/repondre_questions.php delete mode 100644 server_files/controllers/suivi_correspondances.php delete mode 100644 server_files/controllers/view_file.php delete mode 100644 server_files/model.php delete mode 100644 server_files/services/mail.php delete mode 100644 server_files/services/mail_templates/add_admin.html delete mode 100644 server_files/services/mail_templates/add_team.html delete mode 100644 server_files/services/mail_templates/change_email_address.html delete mode 100644 server_files/services/mail_templates/change_password.html delete mode 100644 server_files/services/mail_templates/confirm_email.html delete mode 100644 server_files/services/mail_templates/forgotten_password.html delete mode 100644 server_files/services/mail_templates/join_team.html delete mode 100644 server_files/services/mail_templates/new_answer.html delete mode 100644 server_files/services/mail_templates/new_video.html delete mode 100644 server_files/services/mail_templates/register.html delete mode 100644 server_files/services/mail_templates/request_validation.html delete mode 100644 server_files/services/mail_templates/unvalidate_team.html delete mode 100644 server_files/services/mail_templates/validate_team.html delete mode 100644 server_files/services/mail_templates/video_accepted_answer.html delete mode 100644 server_files/services/mail_templates/video_accepted_solution.html delete mode 100644 server_files/services/mail_templates/video_rejected_answer.html delete mode 100644 server_files/services/mail_templates/video_rejected_solution.html delete mode 100644 server_files/utils.php delete mode 100644 server_files/views/admins.php delete mode 100644 server_files/views/ajouter_admin.php delete mode 100644 server_files/views/ajouter_equipe.php delete mode 100644 server_files/views/calendrier.php delete mode 100644 server_files/views/commenter_echange.php delete mode 100644 server_files/views/connexion.php delete mode 100644 server_files/views/envoyer_video.php delete mode 100644 server_files/views/equipe.php delete mode 100644 server_files/views/exporter_donnees.php delete mode 100644 server_files/views/footer.php delete mode 100644 server_files/views/header.php delete mode 100644 server_files/views/index.html delete mode 100644 server_files/views/index.php delete mode 100644 server_files/views/informations.php delete mode 100644 server_files/views/inscription.php delete mode 100644 server_files/views/ma_participation.php delete mode 100644 server_files/views/mon_compte.php delete mode 100644 server_files/views/mon_equipe.php delete mode 100644 server_files/views/poser_questions.php delete mode 100644 server_files/views/probleme.php delete mode 100644 server_files/views/profiles.php delete mode 100644 server_files/views/rejoindre_equipe.php delete mode 100644 server_files/views/repondre_questions.php delete mode 100644 server_files/views/suivi_correspondances.php delete mode 100644 setup/create_database.sql delete mode 100644 setup/msmtprc create mode 100644 templates/400.html create mode 100644 templates/403.html create mode 100644 templates/404.html create mode 100644 templates/500.html create mode 100644 templates/amount_input.html create mode 100644 templates/autocomplete_model.html create mode 100644 templates/base.html create mode 100644 templates/index.html create mode 100644 templates/registration/email_validation_complete.html create mode 100644 templates/registration/email_validation_email_sent.html create mode 100644 templates/registration/logged_out.html create mode 100644 templates/registration/login.html create mode 100644 templates/registration/mails/email_validation_email.html create mode 100644 templates/registration/mails/email_validation_email.txt create mode 100644 templates/registration/password_change_done.html create mode 100644 templates/registration/password_change_form.html create mode 100644 templates/registration/password_reset_complete.html create mode 100644 templates/registration/password_reset_confirm.html create mode 100644 templates/registration/password_reset_done.html create mode 100644 templates/registration/password_reset_form.html create mode 100644 templates/registration/signup.html diff --git a/.gitignore b/.gitignore index 62c8935..b08ff60 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,44 @@ -.idea/ \ No newline at end of file +# Byte-compiled / optimized / DLL files +dist +build +__pycache__ +*.py[cod] +*$py.class +*.swp +*.egg-info +_build +.tox +.coverage +coverage + +# Translations +*.mo +*.pot + +# Jupyter Notebook +.ipynb_checkpoints + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# PyCharm project settings +.idea + +# VSCode project settings +.vscode + +# Local data +secrets.py +*.log +media/ +# Virtualenv +env/ +venv/ +db.sqlite3 + +# Don't git personal data +import_olddb/ diff --git a/.htaccess b/.htaccess deleted file mode 100644 index 73496ca..0000000 --- a/.htaccess +++ /dev/null @@ -1,4 +0,0 @@ -Options +FollowSymlinks -Options -Indexes -RewriteEngine On -RewriteRule ^(.*)$ dispatcher.php?path=$1 [QSA,L] diff --git a/Dockerfile b/Dockerfile index c550e95..ba9dfc8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,39 +1,31 @@ -FROM php:7.3-apache as plateforme-builder +FROM python:3-alpine -# Enabling apache rewrite mod -RUN a2enmod rewrite +ENV PYTHONUNBUFFERED 1 -RUN apt clean && apt update && apt upgrade -y +# Install LaTeX requirements +RUN apk add --no-cache gettext texlive nginx gcc libc-dev libffi-dev postgresql-dev mariadb-connector-c-dev -# Install MySQL drivers -RUN docker-php-ext-install pdo_mysql \ - && docker-php-ext-enable pdo_mysql +RUN apk add --no-cache bash -# Install zip utilities -RUN apt install -y libzip-dev zip \ - && docker-php-ext-configure zip --with-libzip \ - && docker-php-ext-install zip \ - && docker-php-ext-enable zip +RUN mkdir /code +WORKDIR /code +COPY requirements.txt /code/requirements.txt +RUN pip install -r requirements.txt --no-cache-dir -# Setup locales -RUN apt install locales locales-all -y && locale-gen fr_FR.UTF-8 -ENV LANG fr_FR.UTF-8 -ENV LANGUAGE fr_FR:fr -ENV LC_ALL fr_FR.UTF-8 +COPY . /code/ -# Setup timezone -RUN echo Europe/Paris > /etc/timezone \ - && ln -sf /usr/share/zoneinfo/Europe/Paris /etc/localtime \ - && dpkg-reconfigure -f noninteractive tzdata +# Configure nginx +RUN mkdir /run/nginx +RUN ln -sf /dev/stdout /var/log/nginx/access.log && ln -sf /dev/stderr /var/log/nginx/error.log +RUN ln -sf /code/nginx_corres2math.conf /etc/nginx/conf.d/corres2math.conf +RUN rm /etc/nginx/conf.d/default.conf -# Setup mailing -RUN apt install -yq msmtp ca-certificates -COPY setup/msmtprc /etc/msmtprc -RUN echo "sendmail_path=msmtp -t" >> /usr/local/etc/php/conf.d/php-sendmail.ini +RUN cp /code/corres2math.cron /etc/crontabs/corres2math -# Setting environment -ENV CORRES2MATH_LOCAL_PATH /var/www/html -ENV CORRES2MATH_MAIL_DOMAIN correspondances-maths.fr -ENV CORRES2MATH_URL_BASE https://inscription.correspondances-maths.fr +# With a bashrc, the shell is better +RUN ln -s /code/.bashrc /root/.bashrc -RUN chmod 0777 /var/www/html +ENTRYPOINT ["/code/entrypoint.sh"] +EXPOSE 80 + +CMD ["./manage.py", "shell_plus", "--ptpython"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..151f731 --- /dev/null +++ b/README.md @@ -0,0 +1,64 @@ +# Plateforme d'inscription des Correspondances des Jeunes Mathématicien·nes + +La plateforme des Correspondances des Jeunes Mathématicien·nes est née pour la seconde édition en 2019 de l'action. +D'abord codée en PHP, elle a subi une refonte totale en Python, à l'aide du framework Web [Django](https://www.djangoproject.com/). + +Cette plateforme permet aux participants et encadrants de s'inscrire et de déposer leurs autorisations nécessaires. +Ils pourront ensuite déposer leurs solutions et notes de synthèse pour le premier tour en temps voulu. La plateforme +offre également un accès pour les organisateurs et les jurys leur permettant de communiquer avec les équipes et de +récupérer les documents nécessaires. + +Un wiki plus détaillé arrivera ultérieurement. L'interface organisateur et jury est vouée à être plus poussée. + +L'instance de production est disponible à l'adresse [inscription.correspondances-maths.fr](https://inscription.correspondances-maths.fr). + +## Installation + +Le plus simple pour installer la plateforme est d'utiliser l'image Docker incluse, qui fait tourner un serveur Nginx +exposé sur le port 80 avec le serveur Django. Ci-dessous une configuration Docker-Compose, à adapter selon vos besoins : + +```yaml + inscription-corres2math: + build: ./inscription-corres2math + links: + - postgres + ports: + - "80:80" + env_file: + - ./inscription-corres2math.env + volumes: + # - ./inscription-corres2math:/code + - ./inscription-corres2math/media:/code/media +``` + +Le volume `/code` n'est à ajouter uniquement en développement, et jamais en production. + +Il faut remplir les variables d'environnement suivantes : + +```env +CORRES2MATH_STAGE= # dev ou prod +DJANGO_DB_TYPE= # MySQL, PostgreSQL ou SQLite (par défaut) +DJANGO_DB_HOST= # Hôte de la base de données +DJANGO_DB_NAME= # Nom de la base de données +DJANGO_DB_USER= # Utilisateur de la base de données +DJANGO_DB_PASSWORD= # Mot de passe pour accéder à la base de données +SMTP_HOST= # Hôte SMTP pour l'envoi de mails +SMTP_PORT=465 # Port du serveur SMTP +SMTP_HOST_USER= # Utilisateur du compte SMTP +SMTP_HOST_PASSWORD= # Mot de passe du compte SMTP +FROM_EMAIL=contact@correspondances-maths.fr # Nom de l'expéditeur des mails +SERVER_EMAIL=contact@correspondances-maths.fr # Adresse e-mail expéditrice +``` + +Si le type de base de données sélectionné est SQLite, la variable `DJANGO_DB_HOST` sera utilisée en guise de chemin vers +le fichier de base de données (par défaut, `db.sqlite3`). + +En développement, il est recommandé d'utiliser SQLite pour des raisons de simplicité. Les paramètres de mail ne seront +pas utilisés, et les mails qui doivent être envoyés seront envoyés dans la console. + +En production, il est recommandé de ne pas utiliser SQLite pour des raisons de performances. + +La dernière différence entre le développment et la production est qu'en développement, chaque modification d'un fichier +est détectée et le serveur se relance automatiquement dès lors. + +Une fois le site lancé, le premier compte créé sera un compte administrateur. \ No newline at end of file diff --git a/apps/api/__init__.py b/apps/api/__init__.py new file mode 100644 index 0000000..08884cb --- /dev/null +++ b/apps/api/__init__.py @@ -0,0 +1 @@ +default_app_config = 'api.apps.APIConfig' diff --git a/apps/api/apps.py b/apps/api/apps.py new file mode 100644 index 0000000..6e03468 --- /dev/null +++ b/apps/api/apps.py @@ -0,0 +1,10 @@ +from django.apps import AppConfig +from django.utils.translation import gettext_lazy as _ + + +class APIConfig(AppConfig): + """ + Manage the inscription through a JSON API. + """ + name = 'api' + verbose_name = _('API') diff --git a/apps/api/serializers.py b/apps/api/serializers.py new file mode 100644 index 0000000..4e28d20 --- /dev/null +++ b/apps/api/serializers.py @@ -0,0 +1,15 @@ +from django.contrib.auth.models import User +from rest_framework import serializers + +class UserSerializer(serializers.ModelSerializer): + """ + Serialize a User object into JSON. + """ + class Meta: + model = User + exclude = ( + 'username', + 'password', + 'groups', + 'user_permissions', + ) diff --git a/apps/api/urls.py b/apps/api/urls.py new file mode 100644 index 0000000..c2bbfbf --- /dev/null +++ b/apps/api/urls.py @@ -0,0 +1,18 @@ +from django.conf.urls import url, include +from rest_framework import routers + +from .viewsets import UserViewSet + +# Routers provide an easy way of automatically determining the URL conf. +# Register each app API router and user viewset +router = routers.DefaultRouter() +router.register('user', UserViewSet) + +app_name = 'api' + +# Wire up our API using automatic URL routing. +# Additionally, we include login URLs for the browsable API. +urlpatterns = [ + url('^', include(router.urls)), + url('^api-auth/', include('rest_framework.urls', namespace='rest_framework')), +] diff --git a/apps/api/viewsets.py b/apps/api/viewsets.py new file mode 100644 index 0000000..ad6c669 --- /dev/null +++ b/apps/api/viewsets.py @@ -0,0 +1,17 @@ +from django.contrib.auth.models import User +from django_filters.rest_framework import DjangoFilterBackend +from rest_framework.filters import SearchFilter +from rest_framework.viewsets import ModelViewSet + +from .serializers import UserSerializer + + +class UserViewSet(ModelViewSet): + """ + Display list of users. + """ + queryset = User.objects.all() + serializer_class = UserSerializer + filter_backends = [DjangoFilterBackend, SearchFilter] + filterset_fields = ['id', 'first_name', 'last_name', 'email', 'is_superuser', 'is_staff', 'is_active', ] + search_fields = ['$first_name', '$last_name', ] diff --git a/assets/Autorisation de droit à l'image - majeur.pdf b/assets/Autorisation de droit à l'image - majeur.pdf deleted file mode 100644 index b6d8d98170ec40701a482a8dc9a36521e75bcac1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 95130 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 B#Kiyr diff --git a/assets/Autorisation de droit à l'image - mineur.pdf b/assets/Autorisation de droit à l'image - mineur.pdf deleted file mode 100644 index ea380cb2c161588c5877cebafc623d8ab40a5700..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 95602 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 diff --git a/assets/favicon.ico b/assets/favicon.ico deleted file mode 100644 index 8f01ebb0c8841391ffb3ff858ab96d2630c3674c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8794 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 User: + return getattr(_thread_locals, USER_ATTR_NAME, None) + + +def get_current_session() -> SessionStore: + return getattr(_thread_locals, SESSION_ATTR_NAME, None) + + +def get_current_ip() -> str: + return getattr(_thread_locals, IP_ATTR_NAME, None) + + +def get_current_authenticated_user(): + current_user = get_current_user() + if isinstance(current_user, AnonymousUser): + return None + return current_user + + +class SessionMiddleware(object): + """ + This middleware get the current user with his or her IP address on each request. + """ + + def __init__(self, get_response): + self.get_response = get_response + + def __call__(self, request): + if "_fake_user_id" in request.session: + request.user = User.objects.get(pk=request.session["_fake_user_id"]) + + user = request.user + if 'HTTP_X_FORWARDED_FOR' in request.META: + ip = request.META.get('HTTP_X_FORWARDED_FOR') + else: + ip = request.META.get('REMOTE_ADDR') + + _set_current_user_and_ip(user, request.session, ip) + response = self.get_response(request) + _set_current_user_and_ip(None, None, None) + + return response + + +class TurbolinksMiddleware(object): + """ + Send the `Turbolinks-Location` header in response to a visit that was redirected, + and Turbolinks will replace the browser's topmost history entry. + """ + + def __init__(self, get_response): + self.get_response = get_response + + def __call__(self, request): + response = self.get_response(request) + + is_turbolinks = request.META.get('HTTP_TURBOLINKS_REFERRER') + is_response_redirect = response.has_header('Location') + + if is_turbolinks: + if is_response_redirect: + location = response['Location'] + prev_location = request.session.pop('_turbolinks_redirect_to', None) + if prev_location is not None: + # relative subsequent redirect + if location.startswith('.'): + location = prev_location.split('?')[0] + location + request.session['_turbolinks_redirect_to'] = location + else: + if request.session.get('_turbolinks_redirect_to'): + location = request.session.pop('_turbolinks_redirect_to') + response['Turbolinks-Location'] = location + return response diff --git a/corres2math/settings.py b/corres2math/settings.py new file mode 100644 index 0000000..fcfe553 --- /dev/null +++ b/corres2math/settings.py @@ -0,0 +1,202 @@ +""" +Django settings for corres2math project. + +Generated by 'django-admin startproject' using Django 3.0.5. + +For more information on this file, see +https://docs.djangoproject.com/en/3.0/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/3.0/ref/settings/ +""" + +import os +import sys + +from django.utils.translation import gettext_lazy as _ + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +PROJECT_DIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) +APPS_DIR = os.path.realpath(os.path.join(BASE_DIR, "apps")) +sys.path.append(APPS_DIR) + +ADMINS = [("Yohann D'ANELLO", "yohann.danello@animath.fr")] + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = '6$wl1=ehfoiymin3m3i-wyx5d3t=1h7g4(j2izn*my)*yiq#he' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +SITE_ID = 1 + +ALLOWED_HOSTS = ['*'] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.sites', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'django.forms', + + 'bootstrap_datepicker_plus', + 'crispy_forms', + 'django_extensions', + 'django_tables2', + 'mailer', + 'polymorphic', + 'rest_framework', + 'rest_framework.authtoken', +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'django.middleware.locale.LocaleMiddleware', + 'django.contrib.sites.middleware.CurrentSiteMiddleware', + 'corres2math.middlewares.SessionMiddleware', + 'corres2math.middlewares.TurbolinksMiddleware', +] + +ROOT_URLCONF = 'corres2math.urls' + +LOGIN_REDIRECT_URL = "index" + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [os.path.join(BASE_DIR, 'templates')] + , + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +FORM_RENDERER = 'django.forms.renderers.TemplatesSetting' + +WSGI_APPLICATION = 'corres2math.wsgi.application' + + +# Password validation +# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + +PASSWORD_HASHERS = [ + 'django.contrib.auth.hashers.PBKDF2PasswordHasher', + 'django.contrib.auth.hashers.BCryptPasswordHasher', +] + +REST_FRAMEWORK = { + 'DEFAULT_PERMISSION_CLASSES': [ + 'rest_framework.permissions.IsAdminUser' + ], + 'DEFAULT_AUTHENTICATION_CLASSES': [ + 'rest_framework.authentication.SessionAuthentication', + 'rest_framework.authentication.TokenAuthentication', + ], + 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', + 'PAGE_SIZE': 50, +} + +# Internationalization +# https://docs.djangoproject.com/en/3.0/topics/i18n/ + +LANGUAGE_CODE = 'en' + +LANGUAGES = [ + ('en', _('English')), + ('fr', _('French')), +] + +TIME_ZONE = 'Europe/Paris' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + +LOCALE_PATHS = [os.path.join(BASE_DIR, "locale")] + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/3.0/howto/static-files/ + +STATIC_URL = '/static/' + +STATICFILES_DIRS = [ + os.path.join(BASE_DIR, "corres2math/static"), +] + +STATIC_ROOT = os.path.join(BASE_DIR, "static") + +MEDIA_URL = '/media/' + +MEDIA_ROOT = os.path.join(BASE_DIR, "media") + +CRISPY_TEMPLATE_PACK = 'bootstrap4' + +DJANGO_TABLES2_TEMPLATE = 'django_tables2/bootstrap4.html' + +_db_type = os.getenv('DJANGO_DB_TYPE', 'sqlite').lower() + +if _db_type == 'mysql' or _db_type.startswith('postgres') or _db_type == 'psql': + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.mysql' if _db_type == 'mysql' else 'django.db.backends.postgresql_psycopg2', + 'NAME': os.environ.get('DJANGO_DB_NAME', 'corres2math'), + 'USER': os.environ.get('DJANGO_DB_USER', 'corres2math'), + 'PASSWORD': os.environ.get('DJANGO_DB_PASSWORD', 'CHANGE_ME_IN_ENV_SETTINGS'), + 'HOST': os.environ.get('DJANGO_DB_HOST', 'localhost'), + 'PORT': os.environ.get('DJANGO_DB_PORT', ''), # Use default port + } + } +else: + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASE_DIR, os.getenv('DJANGO_DB_HOST', 'db.sqlite3')), + } + } + +if os.getenv("CORRES2MATH_STAGE", "dev") == "prod": + from .settings_prod import * +else: + from .settings_dev import * diff --git a/corres2math/settings_dev.py b/corres2math/settings_dev.py new file mode 100644 index 0000000..a52990e --- /dev/null +++ b/corres2math/settings_dev.py @@ -0,0 +1,5 @@ +# Database +# https://docs.djangoproject.com/en/3.0/ref/settings/#databases + +EMAIL_BACKEND = 'mailer.backend.DbBackend' +MAILER_EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' diff --git a/corres2math/settings_prod.py b/corres2math/settings_prod.py new file mode 100644 index 0000000..539eb41 --- /dev/null +++ b/corres2math/settings_prod.py @@ -0,0 +1,30 @@ +import os + +# Break it, fix it! +DEBUG = False + +# Mandatory ! +ALLOWED_HOSTS = ['inscription.correspondances-maths.fr', 'plateforme.correspondances-maths.fr'] + +SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', 'CHANGE_ME_IN_ENV_SETTINGS') + +# Emails +EMAIL_BACKEND = 'mailer.backend.DbBackend' +MAILER_EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' +EMAIL_USE_SSL = True +EMAIL_HOST = os.getenv("SMTP_HOST") +EMAIL_PORT = os.getenv("SMTP_PORT") +EMAIL_HOST_USER = os.getenv("SMTP_HOST_USER") +EMAIL_HOST_PASSWORD = os.getenv("SMTP_HOST_PASSWORD") + +DEFAULT_FROM_EMAIL = os.getenv('FROM_EMAIL', 'Contact Correspondances ') +SERVER_EMAIL = os.getenv('SERVER_EMAIL', 'contact@correspondances-maths.fr') + +# Security settings +SECURE_CONTENT_TYPE_NOSNIFF = False +SECURE_BROWSER_XSS_FILTER = False +SESSION_COOKIE_SECURE = False +CSRF_COOKIE_SECURE = False +CSRF_COOKIE_HTTPONLY = False +X_FRAME_OPTIONS = 'DENY' +SESSION_COOKIE_AGE = 60 * 60 * 3 diff --git a/corres2math/static/favicon.ico b/corres2math/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..69e1a320383638a9d14adfb2d56f02b2a4c65815 GIT binary patch literal 7302 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 hi~N7_Cz|N?5%MVCD^9f-ZVON^J#C{q#kU $file) { - if (preg_match('#' . $route . '#', $path, $matches)) { - for ($i = 1; $i < sizeof($file); ++$i) - $_GET[$file[$i]] = $matches[$i]; - - if (!preg_match("#php$#", $file[0])) { - header("Content-Type: " . $file[1]); - readfile($file[0]); - exit(); - } - - /** @noinspection PhpIncludeInspection */ - require $file[0]; - exit(); - } -} - -require_once "server_files/404.php"; diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100755 index 0000000..0029acc --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +python manage.py compilemessages +python manage.py migrate + +nginx + +if [ "$CORRES2MATH_STAGE" = "prod" ]; then + gunicorn -b 0.0.0.0:8000 --workers=2 --threads=4 --worker-class=gthread corres2math.wsgi --access-logfile '-' --error-logfile '-'; +else + ./manage.py runserver 0.0.0.0:8000; +fi diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po new file mode 100644 index 0000000..4b42e94 --- /dev/null +++ b/locale/fr/LC_MESSAGES/django.po @@ -0,0 +1,270 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Corres2math\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-09-20 22:31+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Yohann D'ANELLO \n" +"Language-Team: LANGUAGE \n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: apps/api/apps.py:10 +msgid "API" +msgstr "API" + +#: corres2math/settings.py:144 +msgid "English" +msgstr "Anglais" + +#: corres2math/settings.py:145 +msgid "French" +msgstr "Français" + +#: templates/400.html:6 +msgid "Bad request" +msgstr "Requête invalide" + +#: templates/400.html:7 +msgid "" +"Sorry, your request was bad. Don't know what could be wrong. An email has " +"been sent to webmasters with the details of the error. You can now watch " +"some videos." +msgstr "" +"Désolé, votre requête est invalide. Aucune idée de ce qui a pu se passer. Un " +"email a été envoyé aux administrateurs avec les détails de l'erreur. Vous " +"pouvez désormais retourner voir des vidéos." + +#: templates/403.html:6 +msgid "Permission denied" +msgstr "Permission refusée" + +#: templates/403.html:7 +msgid "You don't have the right to perform this request." +msgstr "Vous n'avez pas le droit d'effectuer cette requête." + +#: templates/403.html:10 templates/404.html:10 +msgid "Exception message:" +msgstr "Message d'erreur :" + +#: templates/404.html:6 +msgid "Page not found" +msgstr "Page non trouvée" + +#: templates/404.html:7 +#, python-format +msgid "" +"The requested path %(request_path)s was not found on the server." +msgstr "" +"Le chemin demandé %(request_path)s n'a pas été trouvé sur le " +"serveur." + +#: templates/500.html:6 +msgid "Server error" +msgstr "Erreur du serveur" + +#: templates/500.html:7 +msgid "" +"Sorry, an error occurred when processing your request. An email has been " +"sent to webmasters with the detail of the error, and this will be fixed " +"soon. You can now watch some videos." +msgstr "" +"Désolé, une erreur est survenue lors du traitement de votre requête. Aucune " +"idée de ce qui a pu se passer. Un email a été envoyé aux administrateurs " +"avec les détails de l'erreur. Vous pouvez désormais retourner voir des " +"vidéos." + +#: templates/base.html:70 +msgid "Home" +msgstr "Accueil" + +#: templates/base.html:74 +msgid "Make a gift" +msgstr "Faire un don" + +#: templates/base.html:78 +msgid "Administration" +msgstr "Administration" + +#: templates/base.html:85 +msgid "Return to admin view" +msgstr "Retourner à l'interface administrateur" + +#: templates/base.html:90 templates/registration/login.html:7 +#: templates/registration/login.html:8 templates/registration/login.html:22 +#: templates/registration/password_reset_complete.html:10 +msgid "Log in" +msgstr "Connexion" + +#: templates/base.html:94 +msgid "Log out" +msgstr "Déconnexion" + +#: templates/base.html:118 +msgid "Contact us" +msgstr "Nous contacter" + +#: templates/base.html:141 +msgid "Back to top" +msgstr "Retour en haut" + +#: templates/registration/email_validation_complete.html:15 +msgid "Your email have successfully been validated." +msgstr "Votre email a été validé avec succès." + +#: templates/registration/email_validation_complete.html:18 +#, python-format +msgid "You can now log in." +msgstr "Vous pouvez désormais vous connecter." + +#: templates/registration/email_validation_complete.html:22 +msgid "" +"The link was invalid. The token may have expired. Please send us an email to " +"activate your account." +msgstr "" +"Le lien est invalide. Le jeton a peut-être expiré. Merci de nous envoyer un " +"mail pour activer votre compte." + +#: templates/registration/email_validation_email_sent.html:10 +msgid "Account activation" +msgstr "Activation du compte" + +#: templates/registration/email_validation_email_sent.html:14 +msgid "" +"An email has been sent. Please click on the link to activate your account." +msgstr "" +"Un email a été envoyé. Merci de cliquer sur le lien pour activer votre " +"compte." + +#: templates/registration/logged_out.html:8 +msgid "Thanks for spending some quality time with the Web site today." +msgstr "Merci d'avoir utilisé la plateforme des Correspondances." + +#: templates/registration/logged_out.html:9 +msgid "Log in again" +msgstr "Se reconnecter" + +#: templates/registration/login.html:13 +#, python-format +msgid "" +"You are authenticated as %(user)s, but are not authorized to access this " +"page. Would you like to login to a different account?" +msgstr "" +"Vous êtes connectés en tant que %(user)s, mais n'êtes pas autorisés à " +"accéder à cette page. Voulez-vous vous reconnecter avec un autre compte ?" + +#: templates/registration/login.html:23 +msgid "Forgotten your password or username?" +msgstr "Mot de passe oublié ?" + +#: templates/registration/mails/email_validation_email.html:12 +#: templates/registration/mails/email_validation_email.txt:3 +msgid "Hi" +msgstr "Bonjour" + +#: templates/registration/mails/email_validation_email.html:16 +#: templates/registration/mails/email_validation_email.txt:5 +msgid "" +"You recently registered on the Correspondances platform. Please click on the " +"link below to confirm your registration." +msgstr "" + +#: templates/registration/mails/email_validation_email.html:26 +#: templates/registration/mails/email_validation_email.txt:9 +msgid "" +"This link is only valid for a couple of days, after that you will need to " +"contact us to validate your email." +msgstr "" + +#: templates/registration/mails/email_validation_email.html:30 +#: templates/registration/mails/email_validation_email.txt:11 +msgid "Thanks" +msgstr "Merci" + +#: templates/registration/mails/email_validation_email.html:35 +#: templates/registration/mails/email_validation_email.txt:13 +msgid "The CNO." +msgstr "" + +#: templates/registration/password_change_done.html:8 +msgid "Your password was changed." +msgstr "Votre mot de passe a été changé." + +#: templates/registration/password_change_form.html:9 +msgid "" +"Please enter your old password, for security's sake, and then enter your new " +"password twice so we can verify you typed it in correctly." +msgstr "" +"Merci d'entrer votre ancien mot de passe pour des raisons de sécurité, et " +"d'entrer votre nouveau mot de passe deux fois afin de s'assurer que vous " +"l'ayez tapé correctement." + +#: templates/registration/password_change_form.html:11 +#: templates/registration/password_reset_confirm.html:12 +msgid "Change my password" +msgstr "Changer mon mot de passe" + +#: templates/registration/password_reset_complete.html:8 +msgid "Your password has been set. You may go ahead and log in now." +msgstr "Votre mot de passe a été changé. Vous pouvez désormais vous connecter." + +#: templates/registration/password_reset_confirm.html:9 +msgid "" +"Please enter your new password twice so we can verify you typed it in " +"correctly." +msgstr "" +"Merci d'entrer votre nouveau mot de passe deux fois afin de vérifier que " +"vous l'ayez tapé correctement." + +#: templates/registration/password_reset_confirm.html:15 +msgid "" +"The password reset link was invalid, possibly because it has already been " +"used. Please request a new password reset." +msgstr "" +"Le lien de réinitialisation du mot de passe est invalide, probablement parce " +"qu'il a déjà été utilisé. Merci de demander une nouvelle réinitialisation du " +"mot de passe." + +#: templates/registration/password_reset_done.html:8 +msgid "" +"We've emailed you instructions for setting your password, if an account " +"exists with the email you entered. You should receive them shortly." +msgstr "" +"Nous vous avons envoyé un email contenant des instructions pour définir " +"votre mot de passe, si un compte existe avec l'adresse mail que vous avez " +"entrée. Vous devriez le recevoir très rapidement." + +#: templates/registration/password_reset_done.html:9 +msgid "" +"If you don't receive an email, please make sure you've entered the address " +"you registered with, and check your spam folder." +msgstr "" +"Si vous ne recevez pas de mail, merci de vous assurer que vous avez entré " +"l'adresse mail avec laquelle vous êtes inscrits, et de vérifier vos " +"courriers indésirables." + +#: templates/registration/password_reset_form.html:8 +msgid "" +"Forgotten your password? Enter your email address below, and we'll email " +"instructions for setting a new one." +msgstr "" +"Mot de passe oublié ? Entrez votre adresse mail ci-dessous, et nous vous " +"enverrons un mail avec les instructions pour en définir un nouveau." + +#: templates/registration/password_reset_form.html:11 +msgid "Reset my password" +msgstr "Réinitialiser mon mot de passe" + +#: templates/registration/signup.html:5 templates/registration/signup.html:8 +#: templates/registration/signup.html:14 +msgid "Sign up" +msgstr "Inscription" diff --git a/manage.py b/manage.py new file mode 100755 index 0000000..c481888 --- /dev/null +++ b/manage.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'corres2math.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/nginx_corres2math.conf b/nginx_corres2math.conf new file mode 100644 index 0000000..e4b01f0 --- /dev/null +++ b/nginx_corres2math.conf @@ -0,0 +1,19 @@ +upstream corres2math { + server 127.0.0.1:8000; +} + +server { + listen 80; + server_name corres2math; + + location / { + proxy_pass http://corres2math; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Host $host; + proxy_redirect off; + } + + location /static { + alias /code/static/; + } +} diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..c3358c4 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,15 @@ +bcrypt +Django~=3.0 +django-allauth +django-bootstrap-datepicker-plus +django-crispy-forms +django-extensions +django-filter +django-mailer +django-polymorphic +django-tables2 +djangorestframework +django-rest-polymorphic +psycopg2-binary +ptpython +gunicorn \ No newline at end of file diff --git a/server_files/403.php b/server_files/403.php deleted file mode 100644 index 72127d0..0000000 --- a/server_files/403.php +++ /dev/null @@ -1,16 +0,0 @@ - - -
-

- Vous n'êtes pas autorisé à accéder à cette page. -

-
- - - -
-

- Cette page n'existe pas. -

-
- -prepare("SELECT * FROM `documents` WHERE `file_id` = ?;"); - $req->execute([htmlspecialchars($id)]); - $data = $req->fetch(); - - if ($data === false) - return null; - - return self::fromData($data); - } - - public static function fromData($data) - { - $doc = new Document(); - $doc->fill($data); - return $doc; - } - - private function fill($data) - { - $this->file_id = $data["file_id"]; - $this->user_id = $data["user"]; - $this->team_id = $data["team"]; - $this->problem = $data["problem"]; - $this->uploaded_at = $data["uploaded_at"]; - $this->version = isset($data["version"]) ? $data["version"] : 1; - } - - public function getFileId() - { - return $this->file_id; - } - - public function getUserId() - { - return $this->user_id; - } - - public function getTeamId() - { - return $this->team_id; - } - - public function getProblem() - { - return $this->problem; - } - - public function getUploadedAt() - { - return $this->uploaded_at; - } - - public function getVersion() - { - return $this->version; - } - - - - public static function getAllDocuments($problem, $team_id = -1) - { - global $DB; - $req = $DB->query("SELECT * FROM `documents` AS `t1` " - . "INNER JOIN (SELECT `user`, `problem`, MAX(`uploaded_at`) AS `last_upload`, COUNT(`team`) AS `version` FROM `documents` GROUP BY `problem`, `user`) `t2` " - . "ON `t1`.`user` = `t2`.`user` AND `t1`.`problem` = `t2`.`problem` " - . "WHERE `t1`.`uploaded_at` = `t2`.`last_upload` AND `t1`.`problem` = $problem " . ($team_id >= 0 ? "AND `team` = $team_id" : "") . " ORDER BY `t1`.`user`;"); - - $docs = []; - - while (($data = $req->fetch()) !== false) - $docs[] = Document::fromData($data); - - return $docs; - } -} diff --git a/server_files/classes/Phase.php b/server_files/classes/Phase.php deleted file mode 100644 index 7cb6669..0000000 --- a/server_files/classes/Phase.php +++ /dev/null @@ -1,68 +0,0 @@ -getStartPhase1Date()) - return self::INSCRIPTION; - - if ($date < $CONFIG->getEndPhase1Date()) - return self::PHASE1; - - if ($date < $CONFIG->getStartPhase2Date()) - return self::PHASE12; - - if ($date < $CONFIG->getEndPhase2Date()) - return self::PHASE2; - - if ($date < $CONFIG->getStartPhase3Date()) - return self::PHASE23; - - if ($date < $CONFIG->getEndPhase3Date()) - return self::PHASE3; - - if ($date < $CONFIG->getStartPhase4Date()) - return self::PHASE34; - - if ($date < $CONFIG->getEndPhase4Date()) - return self::PHASE4; - - return self::END; - } - - public static function getTranslatedName($phase) - { - switch ($phase) - { - case self::INSCRIPTION: - return "Inscription"; - case self::PHASE1: - return "Phase 1 (soumission des vidéos)"; - case self::PHASE2: - return "Phase 2 (questions)"; - case self::PHASE3: - return "Phase 3 (réponses)"; - case self::PHASE4: - return "Phase 4 (vidéo de réponse)"; - case self::END: - return "Les Correspondances sont terminées"; - default: - return "Entre deux phases"; - } - } -} \ No newline at end of file diff --git a/server_files/classes/Question.php b/server_files/classes/Question.php deleted file mode 100644 index f31fe3c..0000000 --- a/server_files/classes/Question.php +++ /dev/null @@ -1,185 +0,0 @@ -prepare("SELECT * FROM `questions` WHERE `id` = ?;"); - $req->execute(htmlspecialchars($id)); - $data = $req->fetch(); - - if ($data === false) - return null; - - $question = new Question(); - $question->fill($data); - return $question; - } - - public static function fromAttachedFile($attached_file) - { - global $DB; - - $req = $DB->prepare("SELECT * FROM `questions` WHERE `attached_file` = ? OR `attached_file_answer` = ?;"); - $req->execute([htmlspecialchars($attached_file), htmlspecialchars($attached_file)]); - $data = $req->fetch(); - - if ($data === false) - return null; - - $question = new Question(); - $question->fill($data); - return $question; - } - - public function fill($data) - { - foreach ($data as $key => $value) - $this->$key = $value; - } - - public static function getQuestions(Team $from, Team $to) - { - global $DB; - - ensure($from->getProblem() == $to->getProblem(), "Les deux équipes doivent travailler sur le même problème."); - - $req = $DB->prepare("SELECT * FROM `questions` WHERE `from` = ? AND `to` = ? ORDER BY `from`, `number`;"); - $req->execute([$from->getId(), $to->getId()]); - - $questions = []; - - while (($data = $req->fetch()) !== false) { - $question = new Question(); - $question->fill($data); - $questions[] = $question; - } - - if (sizeof($questions) == 0) { - $req = $DB->prepare("INSERT INTO `questions`(`from`, `to`, `problem`, `number`, `question`) VALUES (?, ?, ?, ?, ?);"); - $req->execute([$from->getId(), $to->getId(), $from->getProblem(), 0, ""]); - for ($i = 1; $i <= 6; ++$i) { - $req = $DB->prepare("INSERT INTO `questions`(`from`, `to`, `problem`, `number`, `question`) VALUES (?, ?, ?, ?, ?);"); - $req->execute([$from->getId(), $to->getId(), $from->getProblem(), $i, self::DEFAULT_QUESTIONS[$i - 1]]); - } - return self::getQuestions($from, $to); - } - - return $questions; - } - - public static function getQuestionsTo(Team $to) - { - global $DB, $YEAR; - $id = $to->getId(); - $req = $DB->query("SELECT `id` from `teams` WHERE (`video_team1` = $id OR `video_team2` = $id) AND `year` = $YEAR;"); - - $questions = []; - - while (($data = $req->fetch()) !== false) - $questions[] = self::getQuestions(Team::fromId($data["id"]), $to); - - return $questions; - } - - public function getId() - { - return $this->id; - } - - public function getFrom() - { - return $this->from; - } - - public function getTo() - { - return $this->to; - } - - public function getProblem() - { - return $this->problem; - } - - public function getNumber() - { - return $this->number; - } - - public function getQuestion() - { - return $this->question; - } - - public function setQuestion($question) - { - global $DB; - $this->question = $question; - $req = $DB->prepare("UPDATE `questions` SET `question` = ? WHERE `id` = ?;"); - $req->execute([$question, $this->id]); - } - - public function getAttachedFile() - { - return $this->attached_file; - } - - public function setAttachedFile($attached_file) - { - global $DB; - $this->attached_file = $attached_file; - $req = $DB->prepare("UPDATE `questions` SET `attached_file` = ? WHERE `id` = ?;"); - $req->execute([$attached_file, $this->id]); - } - - public function getAnswer() - { - return $this->answer; - } - - public function setAnswer($answer) - { - global $DB; - $this->answer = $answer; - $req = $DB->prepare("UPDATE `questions` SET `answer` = ? WHERE `id` = ?;"); - $req->execute([$answer, $this->id]); - } - - public function getAttachedFileAnswer() - { - return $this->attached_file_answer; - } - - public function setAttachedFileAnswer($attached_file) - { - global $DB; - $this->attached_file_answer = $attached_file; - $req = $DB->prepare("UPDATE `questions` SET `attached_file_answer` = ? WHERE `id` = ?;"); - $req->execute([$attached_file, $this->id]); - } -} \ No newline at end of file diff --git a/server_files/classes/Reason.php b/server_files/classes/Reason.php deleted file mode 100644 index dece59f..0000000 --- a/server_files/classes/Reason.php +++ /dev/null @@ -1,41 +0,0 @@ -prepare("SELECT * FROM `teams` WHERE `id` = ?;"); - $req->execute([htmlspecialchars($id)]); - $data = $req->fetch(); - - if ($data === false) - return null; - - $team = new Team(); - $team->fill($data); - return $team; - } - - /** - * @param $trigram - * @return Team|null - */ - public static function fromTrigram($trigram) - { - global $DB, $YEAR; - $req = $DB->prepare("SELECT * FROM `teams` WHERE `trigram` = ? AND `year` = $YEAR;"); - $req->execute([htmlspecialchars($trigram)]); - $data = $req->fetch(); - - if ($data === false) - return null; - - $team = new Team(); - $team->fill($data); - return $team; - } - - public static function fromAccessCode($access_code) - { - global $DB, $YEAR; - $req = $DB->prepare("SELECT * FROM `teams` WHERE `access_code` = ? AND `year` = $YEAR;"); - $req->execute([htmlspecialchars($access_code)]); - $data = $req->fetch(); - - if ($data === false) - return null; - - $team = new Team(); - $team->fill($data); - return $team; - } - - public static function getAllTeams($problem = -1, $only_validated = false, $only_with_solutions = true) - { - global $DB, $YEAR; - $req = $DB->prepare("SELECT * FROM `teams` WHERE " . ($problem < 0 ? "" : "`problem` = ? AND ") . ($only_validated ? "`validation_status` = 'VALIDATED' AND " : "") . "`year` = $YEAR;"); - $req->execute([htmlspecialchars($problem)]); - - $teams = []; - - while (($data = $req->fetch()) != false) { - $team = new Team(); - $team->fill($data); - $sol = $team->getSolution(); - if ($sol != null && $sol->getValidation() == ValidationStatus::VALIDATED - 1) - $teams[] = $team; - } - - return $teams; - } - - private function fill($data) - { - $this->id = $data["id"]; - $this->name = $data["name"]; - $this->trigram = $data["trigram"]; - $this->problem = $data["problem"]; - $this->encadrant = $data["encadrant"]; - $this->participants = [$data["participant_1"], $data["participant_2"], $data["participant_3"], $data["participant_4"], $data["participant_5"]]; - $this->inscription_date = $data["inscription_date"]; - $this->allow_publish = $data["allow_publish"] ? 1 : 0; - $this->validation_status = ValidationStatus::fromName($data["validation_status"]); - $this->video_team_ids = [$data["video_team1"], $data["video_team2"]]; - $this->access_code = $data["access_code"]; - $this->year = $data["year"]; - } - - public function getId() - { - return $this->id; - } - - public function getName() - { - return $this->name; - } - - public function setName($name) - { - global $DB; - $this->name = $name; - $DB->prepare("UPDATE `teams` SET `name` = ? WHERE `id` = ?;")->execute([$name, $this->id]); - } - - public function getTrigram() - { - return $this->trigram; - } - - public function setTrigram($trigram) - { - global $DB; - $this->trigram = $trigram; - $DB->prepare("UPDATE `teams` SET `trigram` = ? WHERE `id` = ?;")->execute([$trigram, $this->id]); - } - - public function getProblem() - { - return $this->problem; - } - - public function setProblem($problem) - { - global $DB; - $this->problem = $problem; - $DB->prepare("UPDATE `teams` SET `problem` = ? WHERE `id` = ?;")->execute([$problem, $this->id]); - } - - public function getEncadrantId() - { - return $this->encadrant; - } - - public function setEncadrant($encadrant) - { - global $DB; - $this->encadrant = $encadrant; - /** @noinspection SqlResolve */ - $DB->prepare("UPDATE `teams` SET `encadrant` = ? WHERE `id` = ?;")->execute([$encadrant, $this->id]); - } - - public function getParticipants() - { - return $this->participants; - } - - public function setParticipant($i, $participant) - { - global $DB; - $this->participants[$i - 1] = $participant; - /** @noinspection SqlResolve */ - $DB->prepare("UPDATE `teams` SET `participant_$i` = ? WHERE `id` = ?;")->execute([$participant, $this->id]); - } - - public function getInscriptionDate() - { - return $this->inscription_date; - } - - public function allowPublish() - { - return $this->allow_publish; - } - - public function setAllowPublish($allow_publish) - { - global $DB; - $this->allow_publish = $allow_publish; - $DB->prepare("UPDATE `teams` SET `allow_publish` = ? WHERE `id` = ?;")->execute([$allow_publish ? 1 : 0, $this->id]); - } - - public function getValidationStatus() - { - return $this->validation_status; - } - - public function setValidationStatus($status) - { - global $DB; - $this->validation_status = $status; - $DB->prepare("UPDATE `teams` SET `validation_status` = ? WHERE `id` = ?;")->execute([ValidationStatus::getName($status), $this->id]); - } - - public function getSolution() - { - return Video::getVideo(Reason::SOLUTION, $this); - } - - public function getVideoTeamIds() - { - return $this->video_team_ids; - } - - public function setVideoTeamIds($video_team_ids) - { - global $DB; - ensure(sizeof($video_team_ids) == 2, "Une équipe doit recevoir exactement deux vidéos."); - $this->video_team_ids = $video_team_ids; - $DB->prepare("UPDATE `teams` SET `video_team1` = ?, `video_team2` = ? WHERE `id` = ?;")->execute([$video_team_ids[0], $video_team_ids[1], $this->id]); - } - - public function getAccessCode() - { - return $this->access_code; - } - - public function getYear() - { - return $this->year; - } - - public function getAllDocuments() - { - global $DB; - $req = $DB->query("SELECT * FROM `documents` AS `t1` " - . "INNER JOIN (SELECT `team`, MAX(`uploaded_at`) AS `last_upload`, COUNT(`user`) AS `version` FROM `documents` GROUP BY `problem`, `user`, `team`) `t2` " - . "ON `t1`.`team` = `t2`.`team` " - . "WHERE `t1`.`uploaded_at` = `t2`.`last_upload` AND `t1`.`team` = $this->id;"); - - $docs = []; - - while (($data = $req->fetch()) !== false) - $docs[] = Document::fromData($data); - - return $docs; - } - - public function getAllEmails() - { - $emails = []; - if ($this->getEncadrantId() != null) - $emails[] = User::fromId($this->getEncadrantId())->getEmail(); - - foreach ($this->getParticipants() as $participantId) { - if ($participantId != 0) - $emails[] = User::fromId($participantId)->getEmail(); - } - - return $emails; - } -} diff --git a/server_files/classes/User.php b/server_files/classes/User.php deleted file mode 100644 index b81bd99..0000000 --- a/server_files/classes/User.php +++ /dev/null @@ -1,335 +0,0 @@ -prepare("SELECT * FROM `users` WHERE `id` = ?;"); - $req->execute([htmlspecialchars($id)]); - $data = $req->fetch(); - - if ($data === false) - return null; - - $user = new User(); - $user->fill($data); - return $user; - } - - public static function fromEmail($email) - { - global $DB, $YEAR; - $req = $DB->prepare("SELECT * FROM `users` WHERE `email` = ? AND `year` = $YEAR;"); - $req->execute([htmlspecialchars($email)]); - $data = $req->fetch(); - - if ($data === false) - return null; - - $user = new User(); - $user->fill($data); - return $user; - } - - public static function getAdmins() - { - global $DB, $YEAR; - $admins = []; - $req = $DB->query("SELECT * FROM `users` WHERE `role` = 'ADMIN' AND `year` = $YEAR;"); - - while (($data = $req->fetch()) !== false) { - $admin = new User(); - $admin->fill($data); - $admins[] = $admin; - } - - return $admins; - } - - public static function getAllUsers() - { - global $DB, $YEAR; - $orphans = []; - $req = $DB->query("SELECT * FROM `users` WHERE `role` != 'ADMIN' AND `year` = $YEAR ORDER BY `role`, `inscription_date`;"); - - while (($data = $req->fetch()) !== false) { - $orphan = new User(); - $orphan->fill($data); - $orphans[] = $orphan; - } - - return $orphans; - } - - public static function getOrphanUsers() - { - global $DB, $YEAR; - $orphans = []; - $req = $DB->query("SELECT * FROM `users` WHERE `role` != 'ADMIN' AND `team_id` IS NULL " - . "AND NOT EXISTS (SELECT 1 FROM `teams` WHERE `encadrant` = `users`.`id`) " - . "AND `year` = $YEAR ORDER BY `role`, `inscription_date`;"); - - while (($data = $req->fetch()) !== false) { - $orphan = new User(); - $orphan->fill($data); - $orphans[] = $orphan; - } - - return $orphans; - } - - private function fill($data) - { - $this->id = $data["id"]; - $this->email = $data["email"]; - $this->pwd_hash = $data["pwd_hash"]; - $this->surname = $data["surname"]; - $this->first_name = $data["first_name"]; - $this->school = $data["school"]; - $this->city = $data["city"]; - $this->country = $data["country"]; - $this->class = SchoolClass::fromName($data["class"]); - $this->description = $data["description"]; - $this->role = Role::fromName($data["role"]); - $this->team_id = $data["team_id"]; - $this->year = $data["year"]; - $this->confirm_email = $data["confirm_email"]; - $this->forgotten_password = $data["forgotten_password"]; - $this->inscription_date = $data["inscription_date"]; - $this->receive_animath_mails = $data["receive_animath_mails"]; - } - - public function getEmail() - { - return $this->email; - } - - public function setEmail($email) - { - global $DB; - $this->email = $email; - $DB->prepare("UPDATE `users` SET `email` = ? WHERE `id` = ?;")->execute([$email, $this->getId()]); - } - - public function getId() - { - return $this->id; - } - - public function checkPassword($password) - { - return password_verify($password, $this->pwd_hash); - } - - public function setPassword($password) - { - $this->setPasswordHash(password_hash($password, PASSWORD_BCRYPT)); - } - - private function setPasswordHash($password_hash) - { - global $DB; - $this->pwd_hash = $password_hash; - $DB->prepare("UPDATE `users` SET `pwd_hash` = ? WHERE `id` = ?;")->execute([$password_hash, $this->getId()]); - } - - public function getSurname() - { - return $this->surname; - } - - public function setSurname($surname) - { - global $DB; - $this->surname = $surname; - $DB->prepare("UPDATE `users` SET `surname` = ? WHERE `id` = ?;")->execute([$surname, $this->getId()]); - } - - public function getFirstName() - { - return $this->first_name; - } - - public function setFirstName($first_name) - { - global $DB; - $this->first_name = $first_name; - $DB->prepare("UPDATE `users` SET `first_name` = ? WHERE `id` = ?;")->execute([$first_name, $this->getId()]); - } - - public function getSchool() - { - return $this->school; - } - - public function setSchool($school) - { - global $DB; - $this->school = $school; - $DB->prepare("UPDATE `users` SET `school` = ? WHERE `id` = ?;")->execute([$school, $this->getId()]); - } - - public function getCity() - { - return $this->city; - } - - public function setCity($city) - { - global $DB; - $this->city = $city; - $DB->prepare("UPDATE `users` SET `city` = ? WHERE `id` = ?;")->execute([$city, $this->getId()]); - } - - public function getCountry() - { - return $this->country; - } - - public function setCountry($country) - { - global $DB; - $this->country = $country; - $DB->prepare("UPDATE `users` SET `country` = ? WHERE `id` = ?;")->execute([$country, $this->getId()]); - } - - public function getClass() - { - return $this->class; - } - - public function setClass($class) - { - global $DB; - $this->class = $class; - $DB->prepare("UPDATE `users` SET `class` = ? WHERE `id` = ?;")->execute([SchoolClass::getName($class), $this->getId()]); - } - - public function getDescription() - { - return $this->description; - } - - public function setDescription($desc) - { - global $DB; - $this->description = $desc; - $DB->prepare("UPDATE `users` SET `description` = ? WHERE `id` = ?;")->execute([$desc, $this->getId()]); - } - - public function getRole() - { - return $this->role; - } - - public function setRole($role) - { - global $DB; - $this->role = $role; - $DB->prepare("UPDATE `users` SET `role` = ? WHERE `id` = ?;")->execute([Role::getName($role), $this->getId()]); - } - - public function getTeamId() - { - return $this->team_id; - } - - public function setTeamId($team_id) - { - global $DB; - $this->team_id = $team_id; - $DB->prepare("UPDATE `users` SET `team_id` = ? WHERE `id` = ?;")->execute([$team_id, $this->getId()]); - } - - public function getConfirmEmailToken() - { - return $this->confirm_email; - } - - public function setConfirmEmailToken($token) - { - global $DB; - $this->confirm_email = $token; - $DB->prepare("UPDATE `users` SET `confirm_email` = ? WHERE `id` = ?;")->execute([$token, $this->getId()]); - } - - public function getForgottenPasswordToken() - { - return $this->forgotten_password; - } - - public function setForgottenPasswordToken($token) - { - global $DB; - $this->forgotten_password = $token; - $DB->prepare("UPDATE `users` SET `forgotten_password` = ? WHERE `id` = ?;")->execute([$token, $this->getId()]); - } - - public function getInscriptionDate() - { - return $this->inscription_date; - } - - public function doReceiveAnimathMails() - { - return $this->receive_animath_mails; - } - - public function setReceiveAnimathMails($receive_animath_mails) - { - global $DB; - $this->receive_animath_mails = $receive_animath_mails; - $DB->prepare("UPDATE `users` SET `receive_animath_mails` = ? WHERE `id` = ?;")->execute([$receive_animath_mails ? 1 : 0, $this->getId()]); - } - - public function getAllDocuments() - { - global $DB; - $req = $DB->query("SELECT * FROM `documents` AS `t1` " - . "INNER JOIN (SELECT `user`, MAX(`uploaded_at`) AS `last_upload`, COUNT(`team`) AS `version` FROM `documents` GROUP BY `problem`, `user`) `t2` " - . "ON `t1`.`user` = `t2`.`user` " - . "WHERE `t1`.`uploaded_at` = `t2`.`last_upload` AND `t1`.`user` = $this->id;"); - - $docs = []; - - while (($data = $req->fetch()) !== false) - $docs[] = Document::fromData($data); - - return $docs; - } - - // Seulement pour les encadrants - public function getTeams() - { - global $DB; - $req = $DB->query("SELECT `id` FROM `teams` WHERE `encadrant` = $this->id OR `participant_1` = $this->id OR `participant_2` = $this->id OR `participant_3` = $this->id OR `participant_4` = $this->id OR `participant_5` = $this->id;"); - - $teams = []; - - while (($data =$req->fetch()) !== false) - $teams[] = Team::fromId($data["id"]); - - return $teams; - } -} \ No newline at end of file diff --git a/server_files/classes/ValidationStatus.php b/server_files/classes/ValidationStatus.php deleted file mode 100644 index 459d7ad..0000000 --- a/server_files/classes/ValidationStatus.php +++ /dev/null @@ -1,41 +0,0 @@ -prepare("SELECT * FROM `videos` WHERE `id` = ?;"); - $req->execute([htmlspecialchars($id)]); - $data = $req->fetch(); - - if ($data === false) - return null; - - $video = new Video(); - $video->fill($data); - return $video; - } - - public static function getVideos($reason, $problem, $validation_min = -1, $team_id = -1) - { - global $DB, $YEAR; - $req = $DB->query("SELECT * FROM `videos` AS `t1` " - . "INNER JOIN (SELECT `team`, `problem`, `reason`, MAX(`uploaded_at`) AS `last_upload`, COUNT(`team`) AS `version` FROM `videos` " - . "WHERE `validation` >= $validation_min AND `year` = $YEAR GROUP BY `problem`, `reason`, `team`) `t2` " - . "ON `t1`.`team` = `t2`.`team` AND `t1`.`reason` = `t2`.`reason` AND `t1`.`problem` = `t2`.`problem` " - . "WHERE `t1`.`uploaded_at` = `t2`.`last_upload` AND `t1`.`problem` = $problem AND `t1`.`reason` = '" . Reason::getName($reason) . "'" - . ($team_id >= 0 ? " AND `t1`.`team` = $team_id" : "") - . " AND `validation` >= $validation_min AND `year` = $YEAR ORDER BY `t1`.`problem`, `t1`.`reason`;"); - - $videos = []; - - while (($data = $req->fetch()) !== false) { - $video = new Video(); - $video->fill($data); - $videos[] = $video; - } - - return $videos; - } - - /** - * @param int $reason - * @param Team $team - * @param int $validation_min - * @return Video|null - */ - public static function getVideo($reason, Team $team, $validation_min = -1) { - $videos = self::getVideos($reason, $team->getProblem(), $validation_min, $team->getId()); - if (sizeof($videos) == 0) - return null; - else - return $videos[0]; - } - - private function fill($data) - { - foreach ($data as $key => $value) - $this->$key = $value; - - $this->reason = Reason::fromName($this->reason); - } - - public function getId() - { - return $this->id; - } - - public function getTeam() - { - return $this->team; - } - - public function getProblem() - { - return $this->problem; - } - - public function getLink() - { - return $this->link; - } - - public function getReason() - { - return $this->reason; - } - - public function getValidation() - { - return $this->validation; - } - - public function setValidation($validation) - { - global $DB; - $this->validation = $validation; - $DB->exec("UPDATE `videos` SET `validation` = $validation WHERE `id` = $this->id;"); - } - - public function getUploadedAt() - { - return $this->uploaded_at; - } - - public function getYear() - { - return $this->year; - } - - public function getVersion() - { - return $this->version; - } -} \ No newline at end of file diff --git a/server_files/config.php b/server_files/config.php deleted file mode 100644 index 155f878..0000000 --- a/server_files/config.php +++ /dev/null @@ -1,227 +0,0 @@ - PDO::ERRMODE_EXCEPTION)); -} -catch (Exception $ex) { - die("Erreur lors de la connexion à la base de données : " . $ex->getMessage()); -} - -$CONFIG = new Config(); -$CONFIG->initDB(); -$CONFIG->loadConfigValues(); - -class Config -{ - private $inscription_date; - private $start_phase1_date; - private $end_phase1_date; - private $start_phase2_date; - private $end_phase2_date; - private $start_phase3_date; - private $end_phase3_date; - private $start_phase4_date; - private $end_phase4_date; - private $index_page; - private $views; - - public function initDB() - { - global $DB, $LOCAL_PATH, $YEAR; - - $index_template_page = htmlspecialchars(file_get_contents($LOCAL_PATH . "/server_files/views/index.html")); - - $DB->exec("SET GLOBAL time_zone = 'Europe/Paris';"); - $DB->prepare("INSERT IGNORE INTO `config`(`key`, `value`) - VALUES ('inscription_date_$YEAR', CURRENT_TIMESTAMP + INTERVAL 2 DAY), - ('start_phase1_date_$YEAR', CURRENT_TIMESTAMP + INTERVAL 1 DAY), - ('end_phase1_date_$YEAR', CURRENT_TIMESTAMP + INTERVAL 3 DAY), - ('start_phase2_date_$YEAR', CURRENT_TIMESTAMP + INTERVAL 4 DAY), - ('end_phase2_date_$YEAR', CURRENT_TIMESTAMP + INTERVAL 5 DAY), - ('start_phase3_date_$YEAR', CURRENT_TIMESTAMP + INTERVAL 6 DAY), - ('end_phase3_date_$YEAR', CURRENT_TIMESTAMP + INTERVAL 7 DAY), - ('start_phase4_date_$YEAR', CURRENT_TIMESTAMP + INTERVAL 8 DAY), - ('end_phase4_date_$YEAR', CURRENT_TIMESTAMP + INTERVAL 9 DAY), - ('index_page_$YEAR', ?), - ('views_$YEAR', 0);")->execute([$index_template_page]); - } - - public function loadConfigValues() - { - global $DB, $YEAR; - - $req = $DB->query("SELECT * FROM `config` WHERE `key` REGEXP '$YEAR';"); - - while (($data = $req->fetch()) !== false) { - $key = substr($data["key"], 0, -5); - $this->$key = $data["value"]; - } - } - - public function getInscriptionDate() - { - return $this->inscription_date; - } - - public function setInscriptionDate($inscription_date) - { - global $DB, $YEAR; - $DB->exec("UPDATE `config` SET `value` = '$inscription_date' WHERE `key` = 'inscription_date_$YEAR'"); - - $this->inscription_date = $inscription_date; - } - - public function getStartPhase1Date() - { - return $this->start_phase1_date; - } - - public function setStartPhase1Date($start_phase1_date) - { - global $DB, $YEAR; - $DB->exec("UPDATE `config` SET `value` = '$start_phase1_date' WHERE `key` = 'start_phase1_date_$YEAR'"); - - $this->start_phase1_date = $start_phase1_date; - } - - public function getEndPhase1Date() - { - return $this->end_phase1_date; - } - - public function setEndPhase1Date($end_phase1_date) - { - global $DB, $YEAR; - $DB->exec("UPDATE `config` SET `value` = '$end_phase1_date' WHERE `key` = 'end_phase1_date_$YEAR'"); - - $this->end_phase1_date = $end_phase1_date; - } - - public function getStartPhase2Date() - { - return $this->start_phase2_date; - } - - public function setStartPhase2Date($start_phase2_date) - { - global $DB, $YEAR; - $DB->exec("UPDATE `config` SET `value` = '$start_phase2_date' WHERE `key` = 'start_phase2_date_$YEAR'"); - - $this->start_phase2_date = $start_phase2_date; - } - - public function getEndPhase2Date() - { - return $this->end_phase2_date; - } - - public function setEndPhase2Date($end_phase2_date) - { - global $DB, $YEAR; - $DB->exec("UPDATE `config` SET `value` = '$end_phase2_date' WHERE `key` = 'end_phase2_date_$YEAR'"); - - $this->end_phase2_date = $end_phase2_date; - } - - public function getStartPhase3Date() - { - return $this->start_phase3_date; - } - - public function setStartPhase3Date($start_phase3_date) - { - global $DB, $YEAR; - $DB->exec("UPDATE `config` SET `value` = '$start_phase3_date' WHERE `key` = 'start_phase3_date_$YEAR'"); - - $this->start_phase3_date = $start_phase3_date; - } - - public function getEndPhase3Date() - { - return $this->end_phase3_date; - } - - public function setEndPhase3Date($end_phase3_date) - { - global $DB, $YEAR; - $DB->exec("UPDATE `config` SET `value` = '$end_phase3_date' WHERE `key` = 'end_phase3_date_$YEAR'"); - - $this->end_phase3_date = $end_phase3_date; - } - - public function getStartPhase4Date() - { - return $this->start_phase4_date; - } - - public function setStartPhase4Date($start_phase4_date) - { - global $DB, $YEAR; - $DB->exec("UPDATE `config` SET `value` = '$start_phase4_date' WHERE `key` = 'start_phase4_date_$YEAR'"); - - $this->start_phase4_date = $start_phase4_date; - } - - public function getEndPhase4Date() - { - return $this->end_phase4_date; - } - - public function setEndPhase4Date($end_phase4_date) - { - global $DB, $YEAR; - $DB->exec("UPDATE `config` SET `value` = '$end_phase4_date' WHERE `key` = 'end_phase4_date_$YEAR'"); - - $this->end_phase4_date = $end_phase4_date; - } - - public function getIndexPage() - { - return $this->index_page; - } - - public function setIndexPage($index_page) - { - global $DB, $YEAR; - $DB->prepare("UPDATE `config` SET `value` = ? WHERE `key` = 'index_page_$YEAR'")->execute([$index_page]); - - $this->index_page = $index_page; - } - - public function getViews() - { - return $this->views; - } - - public function incrViews() - { - global $DB, $YEAR; - - if (isset($_SESSION["user_id"]) && $_SESSION["role"] == Role::ADMIN || isset($_SESSION["admin"])) - return; - - $DB->exec("UPDATE `config` SET `value` = " . ($this->views + 1) . " WHERE `key` = 'views_$YEAR';"); - $this->views++; - } -} - -session_start(); -setlocale(LC_ALL, "fr_FR.utf8"); -date_default_timezone_set("Europe/Paris"); diff --git a/server_files/controllers/admins.php b/server_files/controllers/admins.php deleted file mode 100644 index 23ece61..0000000 --- a/server_files/controllers/admins.php +++ /dev/null @@ -1,8 +0,0 @@ -makeVerifications(); - $admin->register(); - } - catch (AssertionError $e) { - $has_error = true; - $error_message = $e->getMessage(); - } -} - -class NewAdmin { - public $surname; - public $first_name; - public $email; - public $password; - - public function __construct($data) - { - foreach ($data as $key => $value) - $this->$key = htmlspecialchars($value); - } - - public function makeVerifications() - { - ensure($this->surname != null && $this->surname != "", "Le nom est invalide."); - ensure($this->first_name != null && $this->first_name != "", "Le prénom est invalide."); - ensure(filter_var($this->email, FILTER_VALIDATE_EMAIL), "L'adresse e-mail est invalide."); - $this->email = strtolower($this->email); - ensure(!userExists($this->email), "Cette adresse e-mail est déjà utilisée."); - } - - public function register() { - global $DB, $YEAR; - - $this->password = genRandomPhrase(16, true); - - $req = $DB->prepare("INSERT INTO `users`(`email`, `pwd_hash`, `surname`, `first_name`, `class`, `role`, `year`) - VALUES (?, ?, ?, ?, ?, ?, ?);"); - $req->execute([$this->email, password_hash($this->password, PASSWORD_BCRYPT), $this->surname, - $this->first_name, "ADULT", "ADMIN", $YEAR]); - - Mailer::sendAddAdminMail($this); - } -} - -require_once "server_files/views/ajouter_admin.php"; \ No newline at end of file diff --git a/server_files/controllers/ajouter_equipe.php b/server_files/controllers/ajouter_equipe.php deleted file mode 100644 index 234d341..0000000 --- a/server_files/controllers/ajouter_equipe.php +++ /dev/null @@ -1,75 +0,0 @@ -makeVerifications(); - $new_team->register(); - } - catch (AssertionError $e) { - $has_error = true; - $error_message = $e->getMessage(); - } -} - -class NewTeam { - public $name; - public $trigram; - public $problem; - public $allow_other_teams; - public $allow_publish; - public $access_code; - - public function __construct($data) - { - foreach ($data as $key => $value) - $this->$key = htmlspecialchars($value); - - $this->trigram = strtoupper($this->trigram); - - $this->allow_other_teams = $this->allow_other_teams == "on" ? 1 : 0; - $this->allow_publish = $this->allow_publish == "on" ? 1 : 0; - } - - public function makeVerifications() { - global $CONFIG; - - ensure(date("Y-m-d H:i:s") < $CONFIG->getInscriptionDate(), "La date limite d'inscription est dépassée."); - ensure($_SESSION["team"] == null || $_SESSION["role"] == Role::ENCADRANT, "Vous êtes déjà dans une équipe."); - ensure($this->name != null && $this->name != "", "Vous devez spécifier un nom d'équipe."); - ensure(preg_match("#^[\p{L} ]+$#ui", $this->name), "Le nom de l'équipe ne doit pas comporter de caractères spéciaux."); - ensure(preg_match("#^[A-Z]{3}$#", $this->trigram), "Le trigramme entré n'est pas valide."); - ensure(!teamExists($this->name), "Une équipe existe déjà avec ce nom."); - ensure(!trigramExists($this->trigram), "Une équipe a déjà choisi ce trigramme."); - ensure(preg_match("#[0-4]#", $this->problem), "Le problème choisi n'a pas été reconnu."); - ensure($this->allow_other_teams, "Vous devez autoriser de diffuser vos vidéos aux autres équipes participantes pour pouvoir participer."); - } - - public function register() { - global $DB, $YEAR; - - $this->access_code = genRandomPhrase(6); - - $req = $DB->prepare("INSERT INTO `teams` (`name`, `trigram`, `problem`, `encadrant`, `participant_1`, `allow_publish`, `validation_status`, `access_code`, `year`) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);"); - $req->execute([$this->name, $this->trigram, $this->problem, $_SESSION["role"] == Role::ENCADRANT ? $_SESSION["user_id"] : NULL, - $_SESSION["role"] == Role::PARTICIPANT ? $_SESSION["user_id"] : NULL, $this->allow_publish, ValidationStatus::getName(ValidationStatus::NOT_READY), $this->access_code, $YEAR]); - - $_SESSION["teams"] = $_SESSION["user"]->getTeams(); - $team = Team::fromTrigram($this->trigram); - if ($_SESSION["role"] == Role::PARTICIPANT) { - $_SESSION["team"] = $team; - $_SESSION["user"]->setTeamId($_SESSION["team"]->getId()); - } - - Mailer::sendAddTeamMail($_SESSION["user"], $team); - } -} - -require_once "server_files/views/ajouter_equipe.php"; diff --git a/server_files/controllers/calendrier.php b/server_files/controllers/calendrier.php deleted file mode 100644 index 1db0176..0000000 --- a/server_files/controllers/calendrier.php +++ /dev/null @@ -1,76 +0,0 @@ -makeVerifications(); - $update_calendar->updateCalendar(); - } catch (AssertionError $e) { - $has_error = true; - $error_message = $e->getMessage(); - } -} - -class UpdateCalendar -{ - private $date_inscription; - private $time_inscription; - private $date_start_phase1; - private $time_start_phase1; - private $date_end_phase1; - private $time_end_phase1; - private $date_start_phase2; - private $time_start_phase2; - private $date_end_phase2; - private $time_end_phase2; - private $date_start_phase3; - private $time_start_phase3; - private $date_end_phase3; - private $time_end_phase3; - private $date_start_phase4; - private $time_start_phase4; - private $date_end_phase4; - private $time_end_phase4; - - public function __construct($data) - { - foreach ($data as $key => $value) - $this->$key = htmlspecialchars($value); - } - - public function makeVerifications() - { - ensure(dateWellFormed($this->date_inscription . " " . $this->time_inscription), "La date d'inscription n'est pas bien formée."); - ensure(dateWellFormed($this->date_start_phase1 . " " . $this->time_start_phase1), "La date de début de la phase 1 n'est pas bien formée."); - ensure(dateWellFormed($this->date_end_phase1 . " " . $this->time_end_phase1), "La date de fin de la phase 1 n'est pas bien formée."); - ensure(dateWellFormed($this->date_start_phase2 . " " . $this->time_start_phase2), "La date de début de la phase 2 n'est pas bien formée."); - ensure(dateWellFormed($this->date_end_phase2 . " " . $this->time_end_phase2), "La date de fin de la phase 2 n'est pas bien formée."); - ensure(dateWellFormed($this->date_start_phase3 . " " . $this->time_start_phase3), "La date de début de la phase 3 n'est pas bien formée."); - ensure(dateWellFormed($this->date_end_phase3 . " " . $this->time_end_phase3), "La date de fin de la phase 3 n'est pas bien formée."); - ensure(dateWellFormed($this->date_start_phase4 . " " . $this->time_start_phase4), "La date de début de la phase 4 n'est pas bien formée."); - ensure(dateWellFormed($this->date_end_phase4 . " " . $this->time_end_phase4), "La date de fin de la phase 4 n'est pas bien formée."); - } - - public function updateCalendar() - { - global $CONFIG, $URL_BASE; - - $CONFIG->setInscriptionDate($this->date_inscription . " " . $this->time_inscription); - $CONFIG->setStartPhase1Date($this->date_start_phase1 . " " . $this->time_start_phase1); - $CONFIG->setEndPhase1Date($this->date_end_phase1 . " " . $this->time_end_phase1); - $CONFIG->setStartPhase2Date($this->date_start_phase2 . " " . $this->time_start_phase2); - $CONFIG->setEndPhase2Date($this->date_end_phase2 . " " . $this->time_end_phase2); - $CONFIG->setStartPhase3Date($this->date_start_phase3 . " " . $this->time_start_phase3); - $CONFIG->setEndPhase3Date($this->date_end_phase3 . " " . $this->time_end_phase3); - $CONFIG->setStartPhase4Date($this->date_start_phase4 . " " . $this->time_start_phase4); - $CONFIG->setEndPhase4Date($this->date_end_phase4 . " " . $this->time_end_phase4); - - header("Location: $URL_BASE/calendrier"); - exit(); - } -} - -require_once "server_files/views/calendrier.php"; \ No newline at end of file diff --git a/server_files/controllers/commenter_echange.php b/server_files/controllers/commenter_echange.php deleted file mode 100644 index b1f3e92..0000000 --- a/server_files/controllers/commenter_echange.php +++ /dev/null @@ -1,77 +0,0 @@ -getRole() == Role::PARTICIPANT ? $_SESSION["team"] : Team::fromTrigram($_GET["trigram"]); - -if ($team == null) - require_once "server_files/404.php"; - -if ($user->getRole() == Role::ENCADRANT && $team->getEncadrantId() != $user->getId() || $team->getValidationStatus() != ValidationStatus::VALIDATED) - require_once "server_files/403.php"; - -if (isset($_POST["upload_answer"])) { - $new_answer = new NewAnswer($_POST); - try { - $new_answer->makeVerifications(); - $new_answer->uploadVideo(); - } catch (AssertionError $e) { - $has_error = true; - $error_message = $e->getMessage(); - } -} - -class NewAnswer -{ - public $link; - public $team; - private $valid_link; - private $no_change; - - public function __construct($data) - { - foreach ($data as $key => $value) - $this->$key = $value; - } - - public function makeVerifications() - { - ensure(preg_match("#(https?\:\/\/|)[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?#", $this->link), "Ce n'est pas une URL valide."); - $this->link = preg_replace('/^(?!https?:\/\/)/', 'https://', $this->link); - ensure(preg_match("#[1|2]#", $this->team), "L'équipe n'a pas été trouvée."); - ensure($this->valid_link != null, "Vous devez confirmer que le lien est valide."); - ensure($this->no_change != null, "Vous devez vous engager à ne pas changer le contenu du lien et de la vidéo."); - } - - public function uploadVideo() - { - global $DB, $YEAR, $team; - - $req = $DB->prepare("INSERT INTO `videos`(`team`, `problem`, `link`, `reason`, `year`) VALUES (?, ?, ?, ?, ?)"); - $req->execute([$team->getId(), $team->getProblem(), $this->link, "ANSWER" . $this->team, $YEAR]); - - Mailer::sendNewAnswer($this, $team); - } -} - -$team1 = Team::fromId($team->getVideoTeamIds()[0]); -$sol1 = Video::getVideo(Reason::SOLUTION, $team1); -$answer1 = Video::getVideo(Reason::ANSWER1, $team); -$answer1_validated = Video::getVideo(Reason::ANSWER1, $team, Video::ACCEPTED); -$team2 = Team::fromId($team->getVideoTeamIds()[1]); -$sol2 = Video::getVideo(Reason::SOLUTION, $team2); -$answer2 = Video::getVideo(Reason::ANSWER2, $team); -$answer2_validated = Video::getVideo(Reason::ANSWER2, $team, Video::ACCEPTED); - -$teams = [$team1, $team2]; -$sols = [$sol1, $sol2]; -$answers = [$answer1, $answer2]; -$answers_validated = [$answer1_validated, $answer2_validated]; - -require_once "server_files/views/commenter_echange.php"; \ No newline at end of file diff --git a/server_files/controllers/confirmer_mail.php b/server_files/controllers/confirmer_mail.php deleted file mode 100644 index ea06f20..0000000 --- a/server_files/controllers/confirmer_mail.php +++ /dev/null @@ -1,25 +0,0 @@ -query("SELECT `email` FROM `users` WHERE `confirm_email` = '$token' AND `year` = '$YEAR';"); - if (($data = $result->fetch()) === FALSE) { - $has_error = true; - $error_message = "Le jeton est invalide. Votre compte est peut-être déjà validé ?"; - } - else { - $DB->exec("UPDATE `users` SET `confirm_email` = NULL WHERE `confirm_email` = '$token';"); - $error_message = "Votre adresse mail a été validée ! Vous pouvez désormais vous connecter."; - } -} -else { - $has_error = true; - $error_message = "Il n'y a pas de compte à valider !"; -} -require_once "server_files/views/header.php"; -if (!$has_error) -echo "
$error_message
"; -require_once "server_files/views/footer.php"; diff --git a/server_files/controllers/connexion.php b/server_files/controllers/connexion.php deleted file mode 100644 index 9a441c8..0000000 --- a/server_files/controllers/connexion.php +++ /dev/null @@ -1,170 +0,0 @@ -makeVerifications(); - $logging_in_user->login(); - } catch (AssertionError $e) { - $has_error = true; - $error_message = $e->getMessage(); - } -} - -if (isset($_POST["forgotten_password"]) && !isset($_SESSION["user_id"])) { - $recuperate_account = new RecuperateAccount($_POST); - try { - $recuperate_account->makeVerifications(); - $recuperate_account->recuperateAccount(); - } catch (AssertionError $e) { - $has_error = true; - $error_message = $e->getMessage(); - } -} - -if (isset($_GET["reset_password"]) && isset($_GET["token"]) && !isset($_SESSION["user_id"])) { - $reset_password = new ResetPassword($_GET, $_POST); - try { - $reset_password->makeVerifications(); - if (isset($_POST["password"])) - $reset_password->resetPassword(); - } catch (AssertionError $e) { - $has_error = true; - $error_message = $e->getMessage(); - } -} - -if (isset($_GET["confirmation-mail"]) && !isset($_SESSION["user_id"])) - sendConfirmEmail(); - -class LoggingInUser -{ - public $email; - /** @var User $user */ - public $user; - private $password; - - public function __construct($data) - { - foreach ($data as $key => $value) - $this->$key = htmlspecialchars($value); - } - - public function makeVerifications() - { - ensure(filter_var($this->email, FILTER_VALIDATE_EMAIL), "L'adresse email est invalide."); - $this->user = User::fromEmail($this->email); - ensure($this->user != null, "Le compte n'existe pas."); - ensure($this->user->checkPassword($this->password), "Le mot de passe est incorrect."); - if ($this->user->getConfirmEmailToken() != null) { - $_SESSION["confirm_email"] = $this->email; - /** @noinspection HtmlUnknownTarget */ - throw new AssertionError("L'adresse mail n'a pas été validée. Veuillez vérifier votre boîte mail (surtout vos spams). " - . "Cliquez ici pour renvoyer le mail de confirmation."); - } - } - - public function login() - { - $_SESSION["user_id"] = $this->user->getId(); - $this->user->setForgottenPasswordToken(null); - loadUserValues(); - } -} - -class RecuperateAccount -{ - public $email; - /** @var User $user */ - public $user; - - public function __construct($data) - { - foreach ($data as $key => $value) - $this->$key = htmlspecialchars($value); - } - - public function makeVerifications() - { - ensure(filter_var($this->email, FILTER_VALIDATE_EMAIL), "L'adresse email est invalide."); - $this->user = User::fromEmail($this->email); - ensure($this->user != null, "Le compte n'existe pas."); - } - - public function recuperateAccount() - { - $token = genRandomPhrase(64); - $this->user->setForgottenPasswordToken($token); - Mailer::sendForgottenPasswordProcedureMail($this->user); - } -} - -class ResetPassword -{ - public $token; - /** @var User $user */ - public $user; - private $password; - private $confirm_password; - - public function __construct($data, $data2) - { - foreach ($data as $key => $value) - $this->$key = htmlspecialchars($value); - foreach ($data2 as $key => $value) - $this->$key = htmlspecialchars($value); - } - - public function makeVerifications() - { - global $DB; - $data = $DB->query("SELECT `id` FROM `users` WHERE `forgotten_password` = '" . $this->token . "';")->fetch(); - ensure($data !== false, "Il n'y a pas de compte à récupérer avec ce jeton."); - $this->user = User::fromId($data["id"]); - - if (!isset($_POST["password"])) - return; - - ensure($this->password == $this->confirm_password, "Les deux mots de passe sont différents."); - ensure(strlen($this->password) >= 8, "Le mot de passe doit comporter au moins 8 caractères."); - } - - public function resetPassword() - { - $this->user->setForgottenPasswordToken(null); - $this->user->setPassword($this->password); - - Mailer::sendChangePasswordMail($this->user); - - return false; - } -} - -function sendConfirmEmail() -{ - global $URL_BASE; - - $email = htmlspecialchars($_SESSION["confirm_email"]); - - if (!isset($email)) { - header("Location: $URL_BASE/connexion"); - exit(); - } - - $user = User::fromEmail($email); - - if ($user === null) { - unset($_SESSION["confirm_email"]); - header("Location: $URL_BASE/connexion"); - exit(); - } - - Mailer::sendConfirmEmail($user); - - return false; -} - -require_once "server_files/views/connexion.php"; diff --git a/server_files/controllers/deconnexion.php b/server_files/controllers/deconnexion.php deleted file mode 100644 index 20e215e..0000000 --- a/server_files/controllers/deconnexion.php +++ /dev/null @@ -1,14 +0,0 @@ - - -
- Déconnexion réussie ! -
- -getRole() == Role::PARTICIPANT ? $_SESSION["team"] : Team::fromTrigram($_GET["trigram"]); - -if ($team == null) - require_once "server_files/404.php"; - -if ($user->getRole() == Role::ENCADRANT && $team->getEncadrantId() != $user->getId() || $team->getValidationStatus() != ValidationStatus::VALIDATED) - require_once "server_files/403.php"; - -if (Phase::getCurrentPhase() != Phase::PHASE1) { - if (!(Phase::getCurrentPhase() == Phase::PHASE12 && Video::getVideo(Reason::SOLUTION, $team) != NULL && (Video::getVideo(Reason::SOLUTION, $team, ValidationStatus::WAITING) == NULL || isset($_POST["upload"])))) - require_once "server_files/403.php"; -} - -$has_error = false; -$error_message = null; - -if (isset($_POST["upload"])) { - $new_video = new NewVideo($_POST); - try { - $new_video->makeVerifications(); - $new_video->uploadVideo(); - } catch (AssertionError $e) { - $has_error = true; - $error_message = $e->getMessage(); - } -} - -class NewVideo -{ - public $link; - private $valid_link; - private $no_change; - - public function __construct($data) - { - foreach ($data as $key => $value) - $this->$key = $value; - } - - public function makeVerifications() - { - ensure(preg_match("#(https?\:\/\/|)[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?#", $this->link), "Ce n'est pas une URL valide."); - $this->link = preg_replace('/^(?!https?:\/\/)/', 'https://', $this->link); - ensure($this->valid_link != null, "Vous devez confirmer que le lien est valide."); - ensure($this->no_change != null, "Vous devez vous engager à ne pas changer le contenu du lien et de la vidéo."); - } - - public function uploadVideo() - { - global $DB, $YEAR, $team; - - $req = $DB->prepare("INSERT INTO `videos`(`team`, `problem`, `link`, `reason`, `year`) VALUES (?, ?, ?, ?, ?)"); - $req->execute([$team->getId(), $team->getProblem(), $this->link, Reason::getName(Reason::SOLUTION), $YEAR]); - - Mailer::sendNewVideo($this, $team); - } -} - -$video = Video::getVideo(Reason::SOLUTION, $team); -$video_validated = Video::getVideo(Reason::SOLUTION, $team, Video::ACCEPTED); - -require_once "server_files/views/envoyer_video.php"; \ No newline at end of file diff --git a/server_files/controllers/equipe.php b/server_files/controllers/equipe.php deleted file mode 100644 index 2f226b1..0000000 --- a/server_files/controllers/equipe.php +++ /dev/null @@ -1,112 +0,0 @@ -setValidationStatus(ValidationStatus::VALIDATED); - Mailer::sendValidateTeam($team, $_POST["message"]); -} -elseif (isset($_POST["unvalidate"])) { - $team->setValidationStatus(ValidationStatus::NOT_READY); - Mailer::sendUnvalidateTeam($team, $_POST["message"]); -} -elseif (isset($_POST["select_problem"])) { - if ($team->getValidationStatus() == ValidationStatus::NOT_READY) { - $problem = $_POST["select_problem"]; - if (preg_match("#[0-4]#", $problem)) { - $team->setProblem($problem); - $DB->prepare("UPDATE `documents` SET `problem` = ? WHERE `team` = ?;")->execute([$problem, $team->getId()]); - } - else { - $has_error = true; - $error_message = "Le problème indiqué n'existe pas."; - } - } - else { - $has_error = true; - $error_message = "Cette équipe est déjà validée ou en cours de validation."; - } -} -elseif (isset($_POST["delete_team"])) { - if ($team->getValidationStatus() == ValidationStatus::NOT_READY) { - $documents = Document::getAllDocuments($team->getProblem(), $team->getId()); - /** @var Document $doc */ - foreach ($documents as $doc) - unlink($LOCAL_PATH . "/files/" . $doc->getFileId()); - $DB->prepare("DELETE FROM `documents` WHERE `team` = ?;")->execute([$team->getId()]); - $DB->prepare("DELETE FROM `teams` WHERE `id` = ?;")->execute([$team->getId()]); - $DB->prepare("UPDATE `users` SET `team_id` = NULL WHERE `team_id` = ?;")->execute([$team->getId()]); - header("Location: /"); - exit(0); - } - else { - $has_error = true; - $error_message = "Cette équipe est déjà validée ou en cours de validation."; - } -} - -if (isset($_POST["download_zip"])) { - $file_name = getZipFile($team->getProblem(), $team->getId()); - - header("Content-Type: application/zip"); - header("Content-Disposition: attachment; filename=\"Documents de l'équipe " . $team->getTrigram() . ".zip\""); - header("Content-Length: " . strval(filesize($file_name))); - - readfile($file_name); - - exit(); -} - -if (isset($_POST["update_video_teams"])) { - $update_video_teams = new UpdateVideoTeams($_POST); - try { - $update_video_teams->makeVerifications(); - $update_video_teams->update(); - } catch (AssertionError $e) { - $has_error = true; - $error_message = $e->getMessage(); - } -} - -class UpdateVideoTeams -{ - private $other_teams; - - public function __construct($data) - { - foreach ($data as $key => $value) - $this->$key = $value; - } - - public function makeVerifications() - { - global $team; - - ensure(Phase::getCurrentPhase() <= Phase::PHASE2, "Il est trop tard pour réaffecter les vidéos aux équipes."); - ensure($team->getSolution() != null, "L'équipe doit avoir soumis une vidéo."); - ensure($team->getSolution()->getValidation() == ValidationStatus::VALIDATED - 1, "L'équipe doit avoir soumis une vidéo validée."); - ensure(sizeof($this->other_teams) == 2, "L'équipe doit recevoir exactement deux vidéos."); - ensure(Team::fromId($this->other_teams[0]) != null, "La première équipe n'existe pas."); - ensure(Team::fromId($this->other_teams[1]) != null, "La seconde équipe n'existe pas."); - } - - public function update() - { - global $team; - - $team->setVideoTeamIds($this->other_teams); - } -} - -$other_teams = Team::getAllTeams($team->getProblem(), true, true); -$documents = Document::getAllDocuments($team->getProblem(), $team->getId()); - -require_once "server_files/views/equipe.php"; diff --git a/server_files/controllers/exporter_donnees.php b/server_files/controllers/exporter_donnees.php deleted file mode 100644 index 71b786d..0000000 --- a/server_files/controllers/exporter_donnees.php +++ /dev/null @@ -1,42 +0,0 @@ -setIndexPage(htmlspecialchars($content)); - header("Location: /"); - exit(0); - } -} - -require_once "server_files/views/index.php"; diff --git a/server_files/controllers/informations.php b/server_files/controllers/informations.php deleted file mode 100644 index 370cfcf..0000000 --- a/server_files/controllers/informations.php +++ /dev/null @@ -1,117 +0,0 @@ -getId() != $_SESSION["user_id"]) - require_once "server_files/403.php"; -} - -if ($user === null) - require_once "server_files/404.php"; - -$teams = $user->getTeams(); -if ($user->getRole() == Role::PARTICIPANT) - $team = sizeof($teams) == 0 ? null : $teams[0]; - -$has_error = false; -$error_message = null; - -if (isset($_POST["kick"])) { - if (sizeof($teams) == null) { - $has_error = true; - $error_message = "La personne à expulser n'est dans aucune équipe."; - } - else { - quitTeam($id); - $team = null; - } -} - -if (isset($_POST["attribute_team"])) { - $attribute_team = new AttributeTeam($_POST); - try { - $attribute_team->makeVerifications(); - $attribute_team->attribute(); - } catch (AssertionError $e) { - $has_error = true; - $error_message = $e->getMessage(); - } -} - -if (isset($_POST["view_as"]) && $_SESSION["role"] == Role::ADMIN) { - if (!isset($_SESSION["admin"])) - $_SESSION["admin"] = $_SESSION["user_id"]; - $_SESSION["user_id"] = $user->getId(); - header("Location: /"); - exit(); -} - -if (isset($_POST["delete_account"]) && $team == null && $_SESSION["role"] == Role::ADMIN) { - /** @var Document $document */ - foreach ($user->getAllDocuments() as $document) - unlink($LOCAL_PATH . "/files/" . $document->getFileId()); - $DB->prepare("DELETE FROM `documents` WHERE `user` = ?;")->execute([$user->getId()]); - $DB->prepare("DELETE FROM `users` WHERE `id` = ?;")->execute([$user->getId()]); - header("Location: /"); - exit(); -} - -class AttributeTeam -{ - private $team_id; - private $team; - private $min_null_index; - - public function __construct($data) - { - $this->team_id = $data["team"]; - $this->team = Team::fromId($this->team_id); - } - - public function makeVerifications() - { - global $user; - - ensure($user->getConfirmEmailToken() == null, "Ce participant n'a pas encore validé son adresse e-mail."); - ensure($this->team_id != "no_team", "Vous n'avez pas choisi d'équipe."); - ensure($this->team != null, "Cette équipe n'existe pas."); - ensure($this->team->getValidationStatus() == ValidationStatus::NOT_READY, "Cette équipe est déjà validée ou en cours de validation."); - - $role = $user->getRole(); - for ($i = 1; $i <= $role == Role::ENCADRANT ? 1 : 5; ++$i) { - if (($role == Role::PARTICIPANT ? $this->team->getParticipants()[$i - 1] : $this->team->getEncadrantId()) == NULL) - break; - } - - $this->min_null_index = $i; - - ensure($role == Role::PARTICIPANT && $this->min_null_index <= 5 || $role == Role::ENCADRANT && $this->min_null_index <= 2, - "Il n'y a plus de place pour vous dans l'équipe."); - } - - public function attribute() - { - global $user, $team; - - $user->setTeamId($this->team->getId()); - - if ($user->getRole() == Role::ENCADRANT) - $this->team->setEncadrant($user->getId()); - else - $this->team->setParticipant($this->min_null_index, $user->getId()); - - Mailer::sendJoinTeamMail($user, $this->team); - - $team = $this->team; - } -} - -if ($teams != null) - $documents = $user->getAllDocuments(); - -require_once "server_files/views/informations.php"; diff --git a/server_files/controllers/inscription.php b/server_files/controllers/inscription.php deleted file mode 100644 index 6a51fe0..0000000 --- a/server_files/controllers/inscription.php +++ /dev/null @@ -1,84 +0,0 @@ -makeVerifications(); - $user->register(); - } catch (AssertionError $e) { - $has_error = true; - $error_message = $e->getMessage(); - } -} - -class NewUser -{ - public $email; - public $first_name; - public $surname; - public $role; - public $school; - public $city; - public $country; - public $class; - public $receive_animath_mails; - - public $description; - public $confirm_email_token; - private $password; - private $confirm_password; - - public function __construct($data) - { - foreach ($data as $key => $value) - $this->$key = htmlspecialchars($value); - - $this->receive_animath_mails = $this->receive_animath_mails ? 1 : 0; - } - - public function makeVerifications() - { - global $CONFIG; - - ensure(date("Y-m-d H:i:s") < $CONFIG->getInscriptionDate(), "Les inscriptions sont terminées."); - ensure(filter_var($this->email, FILTER_VALIDATE_EMAIL), "L'adresse e-mail entrée est invalide."); - $this->email = strtolower($this->email); - ensure(!userExists($this->email), "Un compte existe déjà avec cette adresse e-mail."); - ensure(strlen($this->password) >= 8, "Le mot de passe doit comporter au moins 8 caractères."); - ensure($this->password == $this->confirm_password, "Les deux mots de passe sont différents."); - ensure($this->surname != "", "Le nom de famille est obligatoire."); - ensure($this->first_name != "", "Le prénom est obligatoire."); - $this->role = Role::fromName(strtoupper($this->role)); - ensure($this->role == Role::PARTICIPANT || $this->role == Role::ENCADRANT, "Vous devez être participant ou encadrant."); - - if ($this->role == Role::PARTICIPANT) - $this->class = SchoolClass::fromName(strtoupper($this->class)); - else - $this->class = SchoolClass::ADULT; - - $this->confirm_email_token = genRandomPhrase(64); - } - - public function register() - { - global $DB, $YEAR; - - if (!$DB->query("SELECT `id` FROM `users` WHERE `year` = $YEAR;")->fetch()) - $this->role = Role::ADMIN; - - $req = $DB->prepare("INSERT INTO `users`(`email`, `pwd_hash`, `confirm_email`, `surname`, `first_name`, - `school`, `city`, `country`, `class`, `role`, `description`, `receive_animath_mails`, `year`) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"); - $req->execute([$this->email, password_hash($this->password, PASSWORD_BCRYPT), $this->confirm_email_token, - $this->surname, $this->first_name, $this->school, $this->city, $this->country, SchoolClass::getName($this->class), - Role::getName($this->role), $this->description, $this->receive_animath_mails, $YEAR]); - - Mailer::sendRegisterMail($this); - } -} - -require_once "server_files/views/inscription.php"; diff --git a/server_files/controllers/ma_participation.php b/server_files/controllers/ma_participation.php deleted file mode 100644 index 6452ed1..0000000 --- a/server_files/controllers/ma_participation.php +++ /dev/null @@ -1,23 +0,0 @@ - 0) { - /** - * @var User $user - * @var Team team - */ - $user = $_SESSION["user"]; - $team = $user->getRole() == Role::PARTICIPANT ? $_SESSION["team"] : Team::fromTrigram($_GET["trigram"]); - - if ($team == null) - require_once "server_files/404.php"; - - if ($user->getRole() == Role::ENCADRANT && $team->getEncadrantId() != $user->getId()) - require_once "server_files/403.php"; - - $video = Video::getVideo(Reason::SOLUTION, $team); - $questions_received = Question::getQuestionsTo($team); -} -else - require_once "server_files/403.php"; - -require_once "server_files/views/ma_participation.php"; \ No newline at end of file diff --git a/server_files/controllers/mon_compte.php b/server_files/controllers/mon_compte.php deleted file mode 100644 index dc944e4..0000000 --- a/server_files/controllers/mon_compte.php +++ /dev/null @@ -1,177 +0,0 @@ -makeVerifications(); - $my_account->updateAccount(); - } - catch (AssertionError $e) { - $has_error = true; - $error_message = $e->getMessage(); - } -} - -if (isset($_POST["update_password"])) { - $new_password = new NewPassword($_POST); - try { - $new_password->makeVerifications(); - $new_password->updatePassword(); - } - catch (AssertionError $e) { - $has_error = true; - $error_message = $e->getMessage(); - } -} - -if (isset($_POST["send_document"])) { - $send_document = new SendDocument(); - try { - $send_document->makeVerifications(); - $send_document->sendDocument(); - } - catch (AssertionError $e) { - $has_error = true; - $error_message = $e->getMessage(); - } -} - -class MyAccount -{ - public $email; - public $surname; - public $first_name; - public $school; - public $city; - public $country; - public $class; - public $description; - public $receive_animath_mails; - /** @var User */ - private $user; - - public function __construct($data) - { - foreach ($data as $key => $value) - $this->$key = htmlspecialchars($value); - - $this->user = $_SESSION["user"]; - - $keys = ["email", "surname", "first_name", "school", "class", "description"]; - - if ($this->user->getRole() == Role::PARTICIPANT) - $this->class = SchoolClass::fromName($this->class); - - foreach ($keys as $key) - $this->$key = $this->$key != null && $this->$key != "" ? $this->$key : $this->user->$key; - - $this->receive_animath_mails = $this->receive_animath_mails == "on"; - } - - public function makeVerifications() - { - ensure(filter_var($this->email, FILTER_VALIDATE_EMAIL), "L'adresse e-mail entrée est invalide."); - $this->email = strtolower($this->email); - ensure($this->email == $this->user->getEmail() || !userExists($this->email), "Un compte existe déjà avec cette adresse e-mail."); - $this->receive_animath_mails = $this->receive_animath_mails != false; - } - - public function updateAccount() - { - $this->user->setSurname($this->surname); - $this->user->setFirstName($this->first_name); - $this->user->setSchool($this->school); - $this->user->setCity($this->city); - $this->user->setCountry($this->country); - $this->user->setClass($this->class); - $this->user->setDescription($this->description); - $this->user->setReceiveAnimathMails($this->receive_animath_mails); - - if ($this->email != $this->user->getEmail()) { - $this->user->setEmail($this->email); - $this->user->setConfirmEmailToken(genRandomPhrase(64)); - - Mailer::sendChangeEmailAddressMail($this->user); - } - } -} - -class NewPassword -{ - private $user; - private $old_password; - private $new_password; - private $confirm_password; - - public function __construct($data) - { - foreach ($data as $key => $value) - $this->$key = htmlspecialchars($value); - - $this->user = $_SESSION["user"]; - } - - public function makeVerifications() - { - ensure($this->user->checkPassword($this->old_password), "L'ancien mot de passe est incorrect."); - ensure(strlen($this->new_password) >= 8, "Le mot de passe doit comporter au moins 8 caractères."); - ensure($this->new_password == $this->confirm_password, "Les deux mots de passe sont différents."); - } - - public function updatePassword() - { - $this->user->setPassword($this->new_password); - - Mailer::sendChangePasswordMail($this->user); - } -} - -class SendDocument -{ - private $file; - - public function __construct() - { - $this->file = $_FILES["document"]; - } - - public function makeVerifications() - { - global $LOCAL_PATH; - - ensure($this->file["size"] <= 2e6, "Le fichier doit peser moins que 2 Mo."); - ensure(!$this->file["error"], "Une erreur est survenue."); - $mime_type = finfo_file(finfo_open(FILEINFO_MIME_TYPE), $this->file["tmp_name"]); - ensure($mime_type == "application/pdf" || $mime_type == "image/png" || $mime_type == "image/jpeg", "Le fichier doit être au format PDF."); - ensure(is_dir("$LOCAL_PATH/files") || mkdir("$LOCAL_PATH/files"), "Un problème est survenu dans l'envoi du fichier. Veuillez vérifier que le fichier pèse moins de 2 Mo. Merci de compresser votre fichier si tel n'est pas le cas. En cas de problème, merci de contacter l'administrateur du serveur."); - } - - public function sendDocument() - { - global $LOCAL_PATH, $DB; - - do - $id = genRandomPhrase(64); - while (file_exists("$LOCAL_PATH/files/$id")); - - if (!rename($this->file["tmp_name"], "$LOCAL_PATH/files/$id")) - throw new AssertionError("Une erreur est survenue lors de l'envoi du fichier."); - - $req = $DB->prepare("INSERT INTO `documents`(`file_id`, `user`, `team`, `problem`) - VALUES (?, ?, ?, ?);"); - $req->execute([$id, $_SESSION["user_id"], $_SESSION["team"]->getId(), $_SESSION["team"]->getProblem()]); - } -} - -$documents = $user->getAllDocuments(); - -require_once "server_files/views/mon_compte.php"; diff --git a/server_files/controllers/mon_equipe.php b/server_files/controllers/mon_equipe.php deleted file mode 100644 index cde263d..0000000 --- a/server_files/controllers/mon_equipe.php +++ /dev/null @@ -1,112 +0,0 @@ -makeVerifications(); - $my_team->updateTeam(); - } - catch (AssertionError $e) { - $has_error = true; - $error_message = $e->getMessage(); - } -} - -/** - * @var User $user - * @var Team $team - */ -$user = $_SESSION["user"]; -$team = $user->getRole() == Role::PARTICIPANT ? $_SESSION["team"] : Team::fromTrigram($_GET["trigram"]); - -if (isset($_POST["request_validation"])) { - if (!canValidate($team)) { - $has_error = true; - $error_message = "Votre équipe ne peut pas demander la validation : il manque soit des participants, soit des documents."; - } - else if (!isset($_POST["engage"])) { - $has_error = true; - $error_message = "Vous devez cocher la case qui vous engage à participer à l'intégralité des Correspondances."; - } - else { - $team->setValidationStatus(ValidationStatus::WAITING); - Mailer::sendRequestValidationMail($team); - } -} - -/** @var Question[][] $questions_received */ -$questions_received = []; - -if (isset($_SESSION["user_id"]) && isset($_SESSION["teams"]) && sizeof($_SESSION["teams"]) > 0) { - if ($team == null) - require_once "server_files/404.php"; - - if ($user->getRole() == Role::ENCADRANT && $team->getEncadrantId() != $user->getId()) - require_once "server_files/403.php"; - - $documents = $team->getAllDocuments(); -} -else - require_once "server_files/403.php"; - -if (isset($_GET["publish_videos"])) { - $team->setAllowPublish(!$team->allowPublish()); - header("Location: /mon-equipe"); - exit(); -} - -class MyTeam -{ - public $name; - public $trigram; - public $problem; - /** @var Team */ - private $team; - - public function __construct($data) - { - foreach ($data as $key => $value) - $this->$key = htmlspecialchars($value); - - $this->trigram = strtoupper($this->trigram); - $this->team = $_SESSION["team"]; - } - - public function makeVerifications() - { - global $CONFIG; - - ensure($this->name != "" && $this->name != null, "Veuillez spécifier un nom d'équipe."); - ensure($this->name == $this->team->getName() || !teamExists($this->name), "Une équipe existe déjà avec ce nom."); - ensure(preg_match("#^[\p{L} ]+$#ui", $this->name), "Le nom de l'équipe ne doit pas comporter de caractères spéciaux."); - ensure(preg_match("#^[A-Z]{3}$#", $this->trigram), "Le trigramme n'est pas valide."); - ensure($this->trigram == $this->team->getTrigram() || !trigramExists($this->trigram), "Une équipe a déjà choisi ce trigramme."); - ensure(preg_match("#^[0-4]$#", $this->problem), "Le problème indiqué n'existe pas."); - ensure(date("Y-m-d H:i:s") <= $CONFIG->getInscriptionDate(), "Les inscriptions sont terminées."); - ensure($this->team->getValidationStatus() == ValidationStatus::NOT_READY, "Votre équipe est déjà validée ou en cours de validation."); - } - - public function updateTeam() - { - global $DB, $URL_BASE; - - $this->team->setName($this->name); - $this->team->setTrigram($this->trigram); - $this->team->setProblem($this->problem); - - $DB->exec("UPDATE `teams` SET `problem` = " . $this->problem . " WHERE `id` = " . $this->team->getId() . ";"); - $DB->exec("UPDATE `documents` SET `problem` = " . $this->problem . " WHERE `team` = " . $this->team->getId() . ";"); - - header("Location: $URL_BASE/mon-equipe"); - } -} - -require_once "server_files/views/mon_equipe.php"; diff --git a/server_files/controllers/poser_questions.php b/server_files/controllers/poser_questions.php deleted file mode 100644 index 7aa3ee8..0000000 --- a/server_files/controllers/poser_questions.php +++ /dev/null @@ -1,137 +0,0 @@ -getRole() == Role::PARTICIPANT ? $_SESSION["team"] : Team::fromTrigram($_GET["trigram"]); - -if ($team == null) - require_once "server_files/404.php"; - -if ($user->getRole() == Role::ENCADRANT && $team->getEncadrantId() != $user->getId() || $team->getValidationStatus() != ValidationStatus::VALIDATED) - require_once "server_files/403.php"; - -$has_error = false; -$error_message = null; - -if (isset($_POST["give_questions"])) { - $give_questions = new GiveQuestions($_POST, $_FILES); - try { - $give_questions->makeVerifications(); - $give_questions->giveQuestions(); - } catch (AssertionError $e) { - $has_error = true; - $error_message = $e->getMessage(); - } -} - -class GiveQuestions -{ - private $to; - /** - * @var Team $to_team - */ - private $to_team; - private $question_0; - private $question_1; - private $question_2; - private $question_3; - private $question_4; - private $question_5; - private $question_6; - private $questions; - private $no_drawing; - private $has_files; - private $files; - - public function __construct($data, $files) - { - foreach ($data as $key => $value) { - $this->$key = $value; - } - - $this->files = []; - $this->has_files = false; - - for ($i = 0; $i <= 6; ++$i) { - if (strlen($files["file_$i"]["name"]) > 0) { - $this->files[] = $files["file_$i"]; - $this->has_files = true; - } - else - $this->files[] = null; - } - - $this->questions = [$this->question_0, $this->question_1, $this->question_2, $this->question_3, $this->question_4, $this->question_5, $this->question_6]; - } - - public function makeVerifications() - { - global $LOCAL_PATH, $team; - - $this->to_team = Team::fromTrigram($this->to); - ensure($this->to_team, "L'équipe indiquée n'existe pas."); - ensure($team->getProblem() == $this->to_team->getProblem(), "Les équipes ne travaillent pas sur le même problème."); - ensure($this->question_1 != null && $this->question_1 != "" && $this->question_2 != null && $this->question_2 != "" && $this->question_3 != null && $this->question_3 != "", - "Vous devez poser au moins 3 questions."); - ensure(!$this->has_files || $this->no_drawing, "Vous devez confirmer ne pas avoir inclus de texte dans vos pièces jointes."); - - for ($i = 4; $i <= 6; ++$i) { - if ($this->questions[$i] == "") - $this->questions[$i] = null; - } - - for ($i = 0; $i <= 6; ++$i) { - ensure($this->files[$i]["size"] <= 2e6, "Le fichier doit peser moins que 2 Mo."); - ensure(!$this->files[$i]["error"], "Une erreur est survenue. Veuillez vérifier vos pièces jointes. Elles ne doivent pas peser plus de 2 Mo chacune."); - } - - ensure(is_dir("$LOCAL_PATH/files") || mkdir("$LOCAL_PATH/files"), "Un problème est survenue dans l'envoi du fichier. Veuillez contacter l'administrateur du serveur."); - } - - public function giveQuestions() - { - global $LOCAL_PATH, $team; - - /** @var Question[] $questions */ - $questions = Question::getQuestions($team, $this->to_team); - for ($i = 0; $i <= 6; ++$i) { - $question = $questions[$i]; - if ($question->getQuestion() != $this->questions[$i] && $question->getAttachedFile() != null) { - unlink("$LOCAL_PATH/files/" . $question->getAttachedFile()); - $question->setAttachedFile(null); - } - - $question->setQuestion($this->questions[$i]); - - if ($this->files[$i] != null) { - do - $file_id = genRandomPhrase(64); - while (file_exists("$LOCAL_PATH/files/$file_id")); - - if (!rename($this->files[$i]["tmp_name"], "$LOCAL_PATH/files/$file_id")) - throw new AssertionError("Une erreur est survenue lors de l'envoi du fichier."); - - $question->setAttachedFile($file_id); - } - } - } -} - -/** - * @var Team[] $receivers - * @var Video[] $videos - * @var Question[][] $questions - */ -$receivers = [Team::fromId($team->getVideoTeamIds()[0]), Team::fromId($team->getVideoTeamIds()[1])]; -$videos = [Video::getVideo(Reason::SOLUTION, $receivers[0], Video::ACCEPTED), - Video::getVideo(Reason::SOLUTION, $receivers[1], Video::ACCEPTED)]; -$questions = [Question::getQuestions($team, $receivers[0]), - Question::getQuestions($team, $receivers[1])]; - -require_once "server_files/views/poser_questions.php"; \ No newline at end of file diff --git a/server_files/controllers/probleme.php b/server_files/controllers/probleme.php deleted file mode 100644 index 59130b8..0000000 --- a/server_files/controllers/probleme.php +++ /dev/null @@ -1,26 +0,0 @@ -getValidationStatus() == ValidationStatus::VALIDATED) - $validated_emails = array_merge($validated_emails, $team->getAllEmails()); - else - $not_validated_emails = array_merge($not_validated_emails, $team->getAllEmails()); -} - -require_once "server_files/views/probleme.php"; diff --git a/server_files/controllers/profiles.php b/server_files/controllers/profiles.php deleted file mode 100644 index cf4d789..0000000 --- a/server_files/controllers/profiles.php +++ /dev/null @@ -1,9 +0,0 @@ -makeVerifications(); - $join_team->joinTeam(); - } catch (AssertionError $e) { - $has_error = true; - $error_message = $e->getMessage(); - } -} - -class JoinTeam -{ - private $access_code; - private $team; - private $min_null_index; - - public function __construct($data) - { - $this->access_code = strtolower(htmlspecialchars($data["access_code"])); - $this->team = Team::fromAccessCode($this->access_code); - } - - public function makeVerifications() - { - global $CONFIG; - - ensure(date("Y-m-d H:i:s") < $CONFIG->getInscriptionDate(), "La date limite d'inscription est dépassée."); - ensure($_SESSION["team"] == null || $_SESSION["role"] == Role::ENCADRANT, "Vous êtes déjà dans une équipe."); - ensure(preg_match("#[a-z0-9]{6}#", $this->access_code), "Le code d'accès doit comporter 6 caractères alphanumériques."); - ensure($this->team != null, "Ce code d'accès est invalide."); - ensure($this->team->getValidationStatus() == ValidationStatus::NOT_READY, "Cette équipe est déjà validée ou en cours de validation, vous ne pouvez pas la rejoindre."); - - for ($i = 1; $i <= ($_SESSION["role"] == Role::PARTICIPANT ? 5 : 1); ++$i) { - if (($_SESSION["role"] == Role::PARTICIPANT ? $this->team->getParticipants()[$i - 1] : $this->team->getEncadrantId()) == NULL) - break; - } - - $this->min_null_index = $i; - - ensure($_SESSION["role"] == Role::PARTICIPANT && $this->min_null_index <= 5 || $_SESSION["role"] == Role::ENCADRANT && $this->min_null_index <= 1, "Il n'y a plus de place pour vous dans l'équipe."); - } - - public function joinTeam() - { - global $team; - - $user = $_SESSION["user"]; - - $user->setTeamId($this->team->getId()); - - if ($_SESSION["role"] == Role::ENCADRANT) - $this->team->setEncadrant($user->getId()); - else - $this->team->setParticipant($this->min_null_index, $user->getId()); - - $team = $_SESSION["team"] = $this->team; - - Mailer::sendJoinTeamMail($user, $this->team); - } -} - -require_once "server_files/views/rejoindre_equipe.php"; diff --git a/server_files/controllers/repondre_questions.php b/server_files/controllers/repondre_questions.php deleted file mode 100644 index 924171b..0000000 --- a/server_files/controllers/repondre_questions.php +++ /dev/null @@ -1,126 +0,0 @@ -getRole() == Role::PARTICIPANT ? $_SESSION["team"] : Team::fromTrigram($_GET["trigram"]); - -if ($team == null) - require_once "server_files/404.php"; - -if ($user->getRole() == Role::ENCADRANT && $team->getEncadrantId() != $user->getId() || $team->getValidationStatus() != ValidationStatus::VALIDATED) - require_once "server_files/403.php"; - -$has_error = false; -$error_message = null; - -if (isset($_POST["answer"])) { - $answer_questions = new AnswerQuestions($_POST, $_FILES); - try { - $answer_questions->makeVerifications(); - $answer_questions->answerQuestions(); - } catch (AssertionError $e) { - $has_error = true; - $error_message = $e->getMessage(); - } -} - -class AnswerQuestions -{ - private $from; - /** - * @var Team $to_team - */ - private $from_team; - private $answer_0; - private $answer_1; - private $answer_2; - private $answer_3; - private $answer_4; - private $answer_5; - private $answer_6; - private $answers; - private $no_drawing; - private $has_files; - private $files; - - public function __construct($data, $files) - { - foreach ($data as $key => $value) { - $this->$key = $value; - } - - $this->files = []; - $this->has_files = false; - - for ($i = 0; $i <= 6; ++$i) { - if (strlen($files["file_$i"]["name"]) > 0) { - $this->files[] = $files["file_$i"]; - $this->has_files = true; - } - else - $this->files[] = null; - } - - $this->answers = [$this->answer_0, $this->answer_1, $this->answer_2, $this->answer_3, $this->answer_4, $this->answer_5, $this->answer_6]; - } - - public function makeVerifications() - { - global $LOCAL_PATH, $team; - - $this->from_team = Team::fromTrigram($this->from); - ensure($this->from_team != null, "L'équipe indiquée n'existe pas."); - ensure($team->getProblem() == $this->from_team->getProblem(), "Les équipes ne travaillent pas sur le même problème."); - ensure(!$this->has_files || $this->no_drawing, "Vous devez confirmer ne pas avoir inclus de texte dans vos pièces jointes."); - - for ($i = 1; $i <= 6; ++$i) { - if ($this->answers[$i] == "") - $this->answers[$i] = null; - } - - for ($i = 0; $i <= 6; ++$i) { - ensure($this->files[$i]["size"] <= 2e6, "Le fichier doit peser moins que 2 Mo."); - ensure(!$this->files[$i]["error"], "Une erreur est survenue. Veuillez vérifier vos pièces jointes. Elles ne doivent pas peser plus de 2 Mo chacune."); - } - - ensure(is_dir("$LOCAL_PATH/files") || mkdir("$LOCAL_PATH/files"), "Un problème est survenue dans l'envoi du fichier. Veuillez contacter l'administrateur du serveur."); - } - - public function answerQuestions() - { - global $LOCAL_PATH, $team; - - /** @var Question[] $questions */ - $questions = Question::getQuestions($this->from_team, $team); - for ($i = 0; $i <= 6; ++$i) { - $question = $questions[$i]; - if ($question->getAnswer() != $this->answers[$i] && $question->getAttachedFileAnswer() != null) { - unlink("$LOCAL_PATH/files/" . $question->getAttachedFileAnswer()); - $question->setAttachedFileAnswer(null); - } - - $question->setAnswer($this->answers[$i]); - - if ($this->files[$i] != null) { - do - $file_id = genRandomPhrase(64); - while (file_exists("$LOCAL_PATH/files/$file_id")); - - if (!rename($this->files[$i]["tmp_name"], "$LOCAL_PATH/files/$file_id")) - throw new AssertionError("Une erreur est survenue lors de l'envoi du fichier."); - - $question->setAttachedFileAnswer($file_id); - } - } - } -} - -$questions = Question::getQuestionsTo($team); -$video = Video::getVideo(Reason::SOLUTION, $team); - -require_once "server_files/views/repondre_questions.php"; \ No newline at end of file diff --git a/server_files/controllers/suivi_correspondances.php b/server_files/controllers/suivi_correspondances.php deleted file mode 100644 index 522fabd..0000000 --- a/server_files/controllers/suivi_correspondances.php +++ /dev/null @@ -1,141 +0,0 @@ -makeVerifications(); - $validate_video->validate(); - } - catch (AssertionError $e) { - $has_error = true; - $error_message = $e->getMessage(); - } -} - -class ValidateVideo -{ - private $video_id; - private $accept; - private $reject; - /** @var Video */ - private $video; - private $message; - - public function __construct($data) - { - foreach ($data as $key => $value) - $this->$key = $value; - } - - public function makeVerifications() - { - $this->video = Video::fromId($this->video_id); - ensure($this->video != null, "La vidéo n'existe pas."); - ensure($this->video->getValidation() != 1, "La vidéo est déjà validée / rejetée."); - ensure(($this->accept == null || $this->reject == null) && $this->accept != $this->reject, "Impossible de déterminer s'il faut accepter ou non la vidéo."); - } - - public function validate() - { - $this->video->setValidation($this->accept ? 1 : -1); - Mailer::validateVideo($this->video, $this->message); - } -} - -$videos = []; - -if (!isset($_GET["problem"])) { - for ($problem = 1; $problem <= 4; ++$problem) - $videos[] = Video::getVideos(Reason::SOLUTION, $problem); -} -else { - $videos = [[], [], [], []]; - $videos[intval($_GET["problem"]) - 1] = Video::getVideos(Reason::SOLUTION, intval($_GET["problem"])); -} - -$waiting_teams = []; -$waiting_emails = []; - -switch (Phase::getCurrentPhase()) { - case Phase::PHASE1: - case Phase::PHASE12: - $req = $DB->query("SELECT DISTINCT `teams`.`id`, `teams`.`problem`, `teams`.`trigram` FROM `teams` WHERE `validation_status` = '" . ValidationStatus::getName(ValidationStatus::VALIDATED) . "'" - . " AND `id` NOT IN (SELECT DISTINCT `team` FROM `videos` WHERE `reason` = 'SOLUTION' AND `validation` = " . Video::ACCEPTED . ")" - . " AND `year` = $YEAR ORDER BY `problem`, `trigram`;"); - break; - case Phase::PHASE2: - case Phase::PHASE23: - $req = $DB->query("SELECT DISTINCT `teams`.`id`, `teams`.`problem`, `teams`.`trigram` FROM `teams`" - . " WHERE `id` NOT IN (SELECT `q1`.`from` FROM `questions` AS `q1`" - . " JOIN `questions` AS `q2` ON `q2`.`from` = `q1`.`from` AND `q2`.`number` = 2" - . " JOIN `questions` AS `q3` ON `q3`.`from` = `q1`.`from` AND `q3`.`number` = 3" - . " JOIN `questions` AS `q4` ON `q4`.`from` = `q1`.`from` AND `q4`.`number` = 4" - . " JOIN `questions` AS `q5` ON `q5`.`from` = `q1`.`from` AND `q5`.`number` = 5" - . " JOIN `questions` AS `q6` ON `q6`.`from` = `q1`.`from` AND `q6`.`number` = 6" - . " WHERE `q1`.`number` = 1" - . " AND (`q1`.`question` != '" . Question::DEFAULT_QUESTIONS[0] . "'" - . " OR `q2`.`question` != '" . Question::DEFAULT_QUESTIONS[1] . "'" - . " OR `q3`.`question` != '" . Question::DEFAULT_QUESTIONS[2] . "'" - . " OR `q4`.`question` IS NOT NULL" - . " OR `q5`.`question` IS NOT NULL" - . " OR `q6`.`question` IS NOT NULL))" - . " AND `validation_status` = '" . ValidationStatus::getName(ValidationStatus::VALIDATED) . "'" - . " AND `year` = $YEAR ORDER BY `problem`, `trigram`;"); - break; - case Phase::PHASE3: - case Phase::PHASE34: - $req = $DB->query("SELECT DISTINCT `teams`.`id`, `teams`.`problem`, `teams`.`trigram` FROM `teams`" - . " WHERE `id` NOT IN (SELECT `q1`.`to` FROM `questions` AS `q1`" - . " JOIN `questions` AS `q2` ON `q2`.`to` = `q1`.`to` AND `q2`.`number` = 2" - . " JOIN `questions` AS `q3` ON `q3`.`to` = `q1`.`to` AND `q3`.`number` = 3" - . " JOIN `questions` AS `q4` ON `q4`.`to` = `q1`.`to` AND `q4`.`number` = 4" - . " JOIN `questions` AS `q5` ON `q5`.`to` = `q1`.`to` AND `q5`.`number` = 5" - . " JOIN `questions` AS `q6` ON `q6`.`to` = `q1`.`to` AND `q6`.`number` = 6" - . " WHERE `q1`.`number` = 1" - . " AND (`q1`.`answer` IS NOT NULL" - . " OR `q2`.`answer` IS NOT NULL" - . " OR `q3`.`answer` IS NOT NULL" - . " OR `q4`.`answer` IS NOT NULL" - . " OR `q5`.`answer` IS NOT NULL" - . " OR `q6`.`answer` IS NOT NULL))" - . " AND `validation_status` = '" . ValidationStatus::getName(ValidationStatus::VALIDATED) . "'" - . " AND `year` = $YEAR ORDER BY `problem`, `trigram`;"); - break; - case Phase::PHASE4: - case Phase::END: - $req = $DB->query("SELECT DISTINCT `teams`.`id`, `teams`.`problem`, `teams`.`trigram` FROM `teams` WHERE `validation_status` = '" . ValidationStatus::getName(ValidationStatus::VALIDATED) . "'" - . " AND (`id` NOT IN (SELECT DISTINCT `team` FROM `videos` WHERE `reason` = 'ANSWER1' AND `validation` = " . Video::ACCEPTED . ")" - . " OR `id` NOT IN (SELECT DISTINCT `team` FROM `videos` WHERE `reason` = 'ANSWER2' AND `validation` = " . Video::ACCEPTED . "))" - . " AND `year` = $YEAR ORDER BY `problem`, `trigram`;"); - break; -} - -if (isset($req)) { - $waiting_emails = []; - while (($data = $req->fetch()) !== false) { - $team = Team::fromId($data["id"]); - if (Phase::getCurrentPhase() >= Phase::PHASE12 && $team->getSolution() == null) - continue; - if (isset($_GET["problem"]) && intval($_GET["problem"]) != $team->getProblem()) - continue; - $waiting_teams[] = $team; - $waiting_emails = array_merge($waiting_emails, $team->getAllEmails()); - } -} - -$all_emails = []; -foreach (Team::getAllTeams() as $team) { - if (Phase::getCurrentPhase() >= Phase::PHASE12 && $team->getSolution() == null) - continue; - if (isset($_GET["problem"]) && intval($_GET["problem"]) != $team->getProblem()) - continue; - $all_emails = array_merge($all_emails, $team->getAllEmails()); -} - -require_once "server_files/views/suivi_correspondances.php"; \ No newline at end of file diff --git a/server_files/controllers/view_file.php b/server_files/controllers/view_file.php deleted file mode 100644 index f54e827..0000000 --- a/server_files/controllers/view_file.php +++ /dev/null @@ -1,51 +0,0 @@ -getTeamId());; - $trigram = $team->getTrigram(); - - $user = User::fromId($file->getUserId()); - - if (($_SESSION["role"] == Role::PARTICIPANT || $_SESSION["role"] == Role::ENCADRANT) && $user->getId() != $_SESSION["user_id"]) - require_once "server_files/403.php"; - - $surname = $user->getSurname(); - $first_name = $user->getFirstName(); - $mime_type = finfo_file(finfo_open(FILEINFO_MIME_TYPE), "$LOCAL_PATH/files/$id"); - $ext = $mime_type == "application/pdf" ? "pdf" : ($mime_type == "image/png" ? "png" : "jpg"); - $name = "Autorisation de droit à l'image de $first_name $surname.$ext"; - - header("Content-Type: " . $mime_type); -} -else { - $question = Question::fromAttachedFile($id); - if ($question != null) - { - $from = Team::fromId($question->getFrom()); - $to = Team::fromId($question->getTo()); - $mime_type = finfo_file(finfo_open(FILEINFO_MIME_TYPE), "$LOCAL_PATH/files/$id"); - $name = "Pièce jointe n°" . $question->getNumber() . " de l'équipe " . $from->getTrigram() . " pour l'équipe " . $from->getTrigram() . " (problème " . $question->getProblem() . ")"; - $name .= getExtFromMimeType($mime_type); - header("Content-Type: " . $mime_type); - } - else - require_once "server_files/404.php"; -} - -header("Content-Disposition: inline; filename=\"$name\""); - -readfile("$LOCAL_PATH/files/$id"); - -exit(); \ No newline at end of file diff --git a/server_files/model.php b/server_files/model.php deleted file mode 100644 index aa4fb2d..0000000 --- a/server_files/model.php +++ /dev/null @@ -1,326 +0,0 @@ -getRole(); - - $_SESSION["teams"] = $user->getTeams(); - - if ($user->getRole() == Role::PARTICIPANT) - $_SESSION["team"] = sizeof($_SESSION["teams"]) > 0 ? $_SESSION["teams"][0] : null; - } - - if (isset($_GET["view-as-admin"])) { - if (isset($_SESSION["admin"])) { - $_SESSION["user_id"] = $_SESSION["admin"]; - unset($_SESSION["admin"]); - } - header("Location: /"); - exit(); - } -} - -function quitTeam($user_id = -1) -{ - global $DB, $URL_BASE; - - if ($user_id == -1) - header("Location: $URL_BASE"); - - $user_id = $user_id >= 0 ? $user_id : $_SESSION["user_id"]; - /** @var User $user */ - $user = User::fromId($user_id); - $role = $user->getRole(); - - if ($role == Role::ADMIN) - return; - - if ($role == Role::PARTICIPANT) - for ($i = 1; $i <= 5; ++$i) - /** @noinspection SqlResolve */ - $DB->exec("UPDATE `teams` SET `participant_$i` = NULL WHERE `participant_$i` = $user_id;"); - else - $DB->exec("UPDATE `teams` SET `encadrant` = NULL WHERE `encadrant` = $user_id;"); - $user->setTeamId(null); - for ($i = 1; $i <= 4; ++$i) { - /** @noinspection SqlResolve */ - $DB->exec("UPDATE `teams` SET `participant_$i` = `participant_" . strval($i + 1) . "`, `participant_" . strval($i + 1) . "` = NULL WHERE `participant_$i` IS NULL;"); - } - - $DB->exec("DELETE FROM `teams` WHERE `encadrant` IS NULL AND `participant_1` IS NULL;"); - $req = $DB->query("SELECT `file_id` FROM `documents` WHERE `user` = $user_id;"); - while (($data = $req->fetch()) !== false) - unlink("$URL_BASE/files/" . $data["file_id"]); - $DB->exec("DELETE FROM `documents` WHERE `user` = $user_id;"); - - $_SESSION["team"] = null; - unset($_SESSION["team"]); - - $_SESSION["teams"] = $user->getTeams(); -} - -function userExists($email) -{ - global $DB, $YEAR; - - $req = $DB->prepare("SELECT `id` FROM `users` WHERE `email` = ? AND `year` = '$YEAR';"); - $req->execute([$email]); - return $req->fetch(); -} - -function teamExists($name) -{ - global $DB, $YEAR; - - $req = $DB->prepare("SELECT `id` FROM `teams` WHERE `name` = ? AND `year` = '$YEAR';"); - $req->execute([$name]); - return $req->fetch(); -} - -function trigramExists($trigram) -{ - global $DB, $YEAR; - - $req = $DB->prepare("SELECT `id` FROM `teams` WHERE `trigram` = ? AND `year` = '$YEAR';"); - $req->execute([$trigram]); - return $req->fetch(); -} - -function canValidate(Team $team) -{ - global $DB, $CONFIG; - - $can_validate = date("Y-m-d H:i:s") < $CONFIG->getInscriptionDate(); - $can_validate &= $team->getValidationStatus() == ValidationStatus::NOT_READY; - $can_validate &= $team->getEncadrantId() != null; - $can_validate &= $team->getParticipants()[2] != null; - $can_validate &= preg_match("#[1-4]#", $team->getProblem()); - - for ($i = 0; $i < 5; ++$i) { - if ($team->getParticipants()[$i] === NULL) - continue; - - $req = $DB->prepare("SELECT COUNT(*) AS `version` FROM `documents` WHERE `user` = ? AND `problem` = ?;"); - $req->execute([$team->getParticipants()[$i], $team->getProblem()]); - $d = $req->fetch(); - $can_validate &= $d["version"] > 0; - } - - return $can_validate; -} - -function printDocuments($documents) -{ - if (sizeof($documents) == 0) { - echo "
\nPas de document envoyé pour le moment.\n
\n"; - return; - } - - echo "
\n"; - foreach ($documents as $document) { - $file_id = $document->getFileId(); - $user = User::fromId($document->getUserId()); - $surname = $user->getSurname(); - $first_name = $user->getFirstName(); - $name = "Autorisation de droit à l'image"; - $version = $document->getVersion(); - echo "$name de $first_name $surname (version $version) : Télécharger
\n"; - } - echo "
\n"; -} - -function getZipFile($problem, $team_id = -1) -{ - global $LOCAL_PATH; - - $zip = new ZipArchive(); - - $file_name = tempnam("tmp", "corres2math-"); - - if ($zip->open($file_name, ZipArchive::CREATE) !== true) { - die("Impossible de créer le fichier zip."); - } - - $data = Document::getAllDocuments($problem, $team_id); - - /** @var Document $file */ - foreach ($data as $file) { - $file_id = $file->getFileId(); - $user = User::fromId($file->getUserId()); - $mime_type = finfo_file(finfo_open(FILEINFO_MIME_TYPE), "$LOCAL_PATH/files/$file_id"); - $ext = $mime_type == "application/pdf" ? "pdf" : ($mime_type == "image/png" ? "png" : "jpg"); - $name = "Autorisation de droit à l'image de " . $user->getFirstName() . " " . $user->getSurname() . "." . $ext; - - $zip->addFile("$LOCAL_PATH/files/$file_id", $name); - } - - $zip->close(); - - return $file_name; -} - -function exportUserData() { - global $DB, $YEAR; - - $file_name = tempnam("tmp", "corres2math-"); - - $csv = "Identifiant,Nom,Prénom,E-mail,École,Ville,Pays,Classe,Description,Rôle,Équipe,Autorise l'envoi de mails,Date d'inscription\n"; - - $req = $DB->query("SELECT `id` FROM `users` WHERE `year` = $YEAR;"); - while (($data = $req->fetch()) !== false) { - $user = User::fromId($data["id"]); - - $csv .= $user->getId() . ","; - $csv .= $user->getSurname() . ","; - $csv .= $user->getFirstName() . ","; - $csv .= $user->getEmail() . ","; - $csv .= $user->getSchool() . ","; - $csv .= $user->getCity() . ","; - $csv .= $user->getCountry() . ","; - $csv .= SchoolClass::getTranslatedName($user->getClass()) . ","; - $csv .= $user->getDescription() . ","; - $csv .= Role::getTranslatedName($user->getRole()) . ","; - $csv .= ($user->getTeamId() == null ? "" : Team::fromId($user->getTeamId())->getTrigram()) . ","; - $csv .= ($user->doReceiveAnimathMails() ? "oui" : "non") . ","; - $csv .= $user->getInscriptionDate() . "\n"; - } - file_put_contents($file_name, $csv, FILE_APPEND); - - return $file_name; -} - -function exportTeamData() { - global $DB, $YEAR; - - $file_name = tempnam("tmp", "corres2math-"); - - $csv = "Identifiant,Nom,Trigramme,Problème,Encadrant,Participant 1,Participant 2,Participant 3,Participant 4,Participant 5," - . "Date d'inscription,Autorise la publication,État de validation,Code d'accès\n"; - - $req = $DB->query("SELECT `id` FROM `teams` WHERE `year` = $YEAR ORDER BY `problem`;"); - while (($data = $req->fetch()) !== false) { - $team = Team::fromId($data["id"]); - - $csv .= $team->getId() . ","; - $csv .= $team->getName() . ","; - $csv .= $team->getTrigram() . ","; - $csv .= $team->getProblem() . ","; - $csv .= $team->getEncadrantId() . ","; - $csv .= $team->getParticipants()[0] . ","; - $csv .= $team->getParticipants()[1] . ","; - $csv .= $team->getParticipants()[2] . ","; - $csv .= $team->getParticipants()[3] . ","; - $csv .= $team->getParticipants()[4] . ","; - $csv .= $team->getInscriptionDate() . ","; - $csv .= $team->allowPublish() . ","; - $csv .= ValidationStatus::getTranslatedName($team->getValidationStatus()) . ","; - $csv .= $team->getAccessCode() . "\n"; - } - file_put_contents($file_name, $csv, FILE_APPEND); - - return $file_name; -} - -function exportProblemsData() { - global $DB, $URL_BASE, $YEAR; - - $file_name = tempnam("tmp", "corres2math-"); - - $csv = "Équipe,Problème,Lien,Équipe 1 ayant reçu la vidéo," - . "Question 1,Pièce jointe,Réponse,Pièce jointe," - . "Question 2,Pièce jointe,Réponse,Pièce jointe," - . "Question 3,Pièce jointe,Réponse,Pièce jointe," - . "Question 4,Pièce jointe,Réponse,Pièce jointe," - . "Question 5,Pièce jointe,Réponse,Pièce jointe," - . "Question 6,Pièce jointe,Réponse,Pièce jointe," - . "Vidéo de réponse," - . "Équipe 2 ayant reçu la vidéo," - . "Question 1,Pièce jointe,Réponse,Pièce jointe," - . "Question 2,Pièce jointe,Réponse,Pièce jointe," - . "Question 3,Pièce jointe,Réponse,Pièce jointe," - . "Question 4,Pièce jointe,Réponse,Pièce jointe," - . "Question 5,Pièce jointe,Réponse,Pièce jointe," - . "Question 6,Pièce jointe,Réponse,Pièce jointe," - . "Vidéo de réponse\n"; - - $req = $DB->query("SELECT `id` FROM `teams` WHERE `validation_status` = 'VALIDATED' AND `year` = $YEAR ORDER BY `problem`;"); - while (($data = $req->fetch()) !== false) { - $team = Team::fromId($data["id"]); - $video = Video::getVideo(Reason::SOLUTION, $team); - $questions_received = Question::getQuestionsTo($team); - - $csv .= $team->getTrigram() . ","; - $csv .= $team->getProblem() . ","; - $csv .= ($video == null ? "" : $video->getLink()) . ","; - for ($i = 0; $i < 2; ++$i) { - /** @var Question[] $questions */ - $questions = $questions_received[$i]; - $asker = Team::fromId($questions[0]->getFrom()); - $csv .= $asker->getTrigram() . ","; - - for ($j = 0; $j < 6; ++$j) { - $question = $questions[$j]; - - if ($question == null) { - $csv .= ",,,,"; - continue; - } - - $csv .= $question->getQuestion() . ","; - $csv .= ($question->getAttachedFile() == null ? "" : $URL_BASE . "/file/" . $question->getAttachedFile()) . ','; - $csv .= $question->getAnswer() . ","; - $csv .= ($question->getAttachedFileAnswer() == null ? "" : $URL_BASE . "/file/" . $question->getAttachedFileAnswer()) . ','; - } - - $answer = Video::getVideo($asker->getVideoTeamIds()[0] == $team->getId() ? Reason::ANSWER1 : Reason::ANSWER2, - $asker, Video::ACCEPTED); - $csv .= $answer == null ? "" : $answer->getLink(); - $csv .= ($i == 0 ? "," : "\n"); - } - } - file_put_contents($file_name, $csv, FILE_APPEND); - - return $file_name; -} - -function displayVideo($link) -{ - if (preg_match("#(https?://|)(www\.|)(youtube\.com/watch\?v=|youtu.be/)([a-zA-Z0-9,\-,_]*)?.*?#", $link, $matches)) { - $code = $matches[4]; - /** @noinspection HtmlDeprecatedAttribute */ - /** @noinspection HtmlDeprecatedTag */ - echo "

\n"; - } - elseif (preg_match("#(https?://|)drive\.google\.com/(file/d/|open\?id=)([a-zA-Z0-9\-_]*)/?.*?#", $link, $matches)) { - $code = $matches[3]; - /** @noinspection HtmlDeprecatedAttribute */ - /** @noinspection HtmlDeprecatedTag */ - echo "

\n"; - } - elseif (preg_match("#(https?://|)(www\.|)vimeo\.com/([0-9]*)#", $link, $matches)) { - $code = $matches[3]; - /** @noinspection HtmlDeprecatedAttribute */ - /** @noinspection HtmlDeprecatedTag */ - echo "
"; - - } - elseif (preg_match("#(https?://|)(www\.|)dailymotion\.com/video/(.*)#", $link, $matches)) { - $code = $matches[3]; - /** @noinspection HtmlDeprecatedAttribute */ - /** @noinspection HtmlDeprecatedTag */ - echo "
"; - } -} \ No newline at end of file diff --git a/server_files/services/mail.php b/server_files/services/mail.php deleted file mode 100644 index f3963eb..0000000 --- a/server_files/services/mail.php +++ /dev/null @@ -1,256 +0,0 @@ -\r\n"; - $headers .= "Reply-To: \"Contact corres2Math\" \r\n"; - $headers .= "Content-Type: text/html; charset=UTF-8\r\n"; - - ensure(mail($email, $subject, $content, $headers), "Un problème est survenu dans l'envoi d'un mail. Veuiller contacter votre administrateur."); - } - - private static function broadcastToTeam(Team $team, $subject, $content, $from = "contact") - { - $content = preg_replace("#{TEAM_NAME}#", $team->getName(), $content); - $content = preg_replace("#{TRIGRAM}#", $team->getTrigram(), $content); - - $encadrant = User::fromId($team->getEncadrantId()); - - if ($encadrant != null) { - $c = preg_replace("#{FIRST_NAME}#", $encadrant->getFirstName(), $content); - $c = preg_replace("#{SURNAME}#", $encadrant->getSurname(), $c); - self::sendMail($encadrant->getEmail(), $subject, $c, $from); - } - - foreach ($team->getParticipants() as $participant_id) { - $participant = User::fromId($participant_id); - if ($participant == null) - continue; - - $c = preg_replace("#{FIRST_NAME}#", $participant->getFirstName(), $content); - $c = preg_replace("#{SURNAME}#", $participant->getSurname(), $c); - self::sendMail($participant->getEmail(), $subject, $c, $from); - } - } - - private static function broadcastToAdmins($subject, $content, $from = "contact") - { - /** @var User $admin */ - foreach (User::getAdmins() as $admin) { - if (!$admin->doReceiveAnimathMails()) - continue; - - $c = preg_replace("#{FIRST_NAME}#", $admin->getFirstName(), $content); - $c = preg_replace("#{SURNAME}#", $admin->getSurname(), $c); - self::sendMail($admin->getEmail(), $subject, $c, $from); - } - } - - private static function getTemplate($name) - { - global $LOCAL_PATH; - return file_get_contents("$LOCAL_PATH/server_files/services/mail_templates/$name.html"); - } - - public static function sendRegisterMail(NewUser $new_user) - { - global $YEAR; - - $content = self::getTemplate("register"); - $content = preg_replace("#{FIRST_NAME}#", $new_user->first_name, $content); - $content = preg_replace("#{SURNAME}#", $new_user->surname, $content); - $content = preg_replace("#{TOKEN}#", $new_user->confirm_email_token, $content); - - self::sendMail($new_user->email, "Inscription aux Correspondances des Jeunes Mathématicien·ne·s $YEAR - " . ($YEAR + 1), $content); - } - - public static function sendConfirmEmail(User $user) - { - global $YEAR; - - $content = self::getTemplate("confirm_email"); - $content = preg_replace("#{FIRST_NAME}#", $user->getFirstName(), $content); - $content = preg_replace("#{SURNAME}#", $user->getSurname(), $content); - $content = preg_replace("#{TOKEN}#", $user->getConfirmEmailToken(), $content); - - self::sendMail($user->getEmail(), "Confirmation d'adresse e-mail – Correspondances des Jeunes Mathématicien·ne·s $YEAR - " . ($YEAR + 1), $content); - } - - public static function sendChangeEmailAddressMail(User $user) - { - global $YEAR; - - $content = self::getTemplate("change_email_address"); - $content = preg_replace("#{FIRST_NAME}#", $user->getFirstName(), $content); - $content = preg_replace("#{SURNAME}#", $user->getSurname(), $content); - $content = preg_replace("#{TOKEN}#", $user->getConfirmEmailToken(), $content); - - self::sendMail($user->getEmail(), "Changement d'adresse e-mail – Correspondances des Jeunes Mathématicien·ne·s $YEAR - " . ($YEAR + 1), $content); - } - - public static function sendForgottenPasswordProcedureMail(User $user) - { - global $YEAR; - - $content = self::getTemplate("forgotten_password"); - $content = preg_replace("#{FIRST_NAME}#", $user->getFirstName(), $content); - $content = preg_replace("#{SURNAME}#", $user->getSurname(), $content); - $content = preg_replace("#{TOKEN}#", $user->getForgottenPasswordToken(), $content); - - self::sendMail($user->getEmail(), "Mot de passe oublié – Correspondances des Jeunes Mathématicien·ne·s $YEAR - " . ($YEAR + 1), $content); - } - - public static function sendChangePasswordMail(User $user) - { - global $YEAR; - - $content = self::getTemplate("change_password"); - $content = preg_replace("#{FIRST_NAME}#", $user->getFirstName(), $content); - $content = preg_replace("#{SURNAME}#", $user->getSurname(), $content); - - self::sendMail($user->getEmail(), "Mot de passe changé – Correspondances des Jeunes Mathématicien·ne·s $YEAR - " . ($YEAR + 1), $content); - } - - public static function sendAddAdminMail(NewAdmin $new_admin) - { - global $YEAR; - - $content = self::getTemplate("add_admin"); - $content = preg_replace("#{FIRST_NAME}#", $new_admin->first_name, $content); - $content = preg_replace("#{SURNAME}#", $new_admin->surname, $content); - $content = preg_replace("#{PASSWORD}#", $new_admin->password, $content); - - self::sendMail($new_admin->email, "Ajout d'un administrateur – Correspondances des Jeunes Mathématicien·ne·s $YEAR - " . ($YEAR + 1), $content); - } - - public static function sendAddTeamMail(User $user, Team $team) - { - global $YEAR; - - $content = self::getTemplate("add_team"); - $content = preg_replace("#{FIRST_NAME}#", $user->getFirstName(), $content); - $content = preg_replace("#{SURNAME}#", $user->getSurname(), $content); - $content = preg_replace("#{TEAM_NAME}#", $team->getName(), $content); - $content = preg_replace("#{TRIGRAM}#", $team->getTrigram(), $content); - $content = preg_replace("#{ACCESS_CODE}#", $team->getAccessCode(), $content); - if ($team->getProblem() > 0) - $content = preg_replace("#{PROBLEM}#", "pour le problème" . $team->getProblem(), $content); - else - $content = preg_replace("#{PROBLEM}#", "", $content); - - self::sendMail($user->getEmail(), "Ajout d'une équipe – Correspondances des Jeunes Mathématicien·ne·s $YEAR - " . ($YEAR + 1), $content); - } - - public static function sendJoinTeamMail(User $user, Team $team) - { - global $YEAR; - - $content = self::getTemplate("join_team"); - $content = preg_replace("#{FIRST_NAME}#", $user->getFirstName(), $content); - $content = preg_replace("#{SURNAME}#", $user->getSurname(), $content); - $content = preg_replace("#{TEAM_NAME}#", $team->getName(), $content); - $content = preg_replace("#{TRIGRAM}#", $team->getTrigram(), $content); - if ($team->getProblem() > 0) - $content = preg_replace("#{PROBLEM}#", "pour le problème" . $team->getProblem(), $content); - else - $content = preg_replace("#{PROBLEM}#", "", $content); - - self::sendMail($user->getEmail(), "Équipe rejointe – Correspondances des Jeunes Mathématicien·ne·s $YEAR - " . ($YEAR + 1), $content); - } - - public static function sendRequestValidationMail(Team $team) - { - global $YEAR; - - $content = self::getTemplate("request_validation"); - $content = preg_replace("#{TEAM_NAME}#", $team->getName(), $content); - $content = preg_replace("#{TRIGRAM}#", $team->getTrigram(), $content); - $content = preg_replace("#{PROBLEM}#", $team->getProblem(), $content); - $content = preg_replace("#{ACCESS_CODE}#", $team->getAccessCode(), $content); - - self::broadcastToAdmins("Demande de validation – Correspondances des Jeunes Mathématicien·ne·s $YEAR - " . ($YEAR + 1), $content); - } - - public static function sendValidateTeam($team, $message) - { - global $YEAR; - - $content = self::getTemplate("validate_team"); - if (strlen($message) > 0) - $message = " L'équipe d'organisation vous transmet le message suivant :\n\n" . $message; - $message = preg_replace("#\n#", "
\n", $message); - $content = preg_replace("#{MESSAGE}#", $message, $content); - - self::broadcastToTeam($team, "Équipe validée – Correspondances des Jeunes Mathématicien·ne·s $YEAR - " . ($YEAR + 1), $content); - } - - public static function sendUnvalidateTeam($team, $message) - { - global $YEAR; - - $content = self::getTemplate("unvalidate_team"); - if (strlen($message) > 0) - $message = " L'équipe d'organisation vous transmet le message suivant :\n\n" . $message; - $message = preg_replace("#\n#", "
\n", $message); - $content = preg_replace("#{MESSAGE}#", $message, $content); - - self::broadcastToTeam($team, "Équipe non validée – Correspondances des Jeunes Mathématicien·ne·s $YEAR - " . ($YEAR + 1), $content); - } - - public static function sendNewVideo(NewVideo $video, Team $team) - { - global $YEAR; - - $content = self::getTemplate("new_video"); - $content = preg_replace("#{TEAM_NAME}#", $team->getName(), $content); - $content = preg_replace("#{TRIGRAM}#", $team->getTrigram(), $content); - $content = preg_replace("#{PROBLEM}#", $team->getProblem(), $content); - $content = preg_replace("#{VIDEO_LINK}#", $video->link, $content); - self::broadcastToAdmins("Nouvelle vidéo – Correspondances des Jeunes Mathématicien·ne·s $YEAR - " . ($YEAR + 1), $content); - } - - public static function sendNewAnswer(NewAnswer $video, Team $team) - { - global $YEAR; - - $content = self::getTemplate("new_answer"); - $content = preg_replace("#{TEAM_NAME}#", $team->getName(), $content); - $content = preg_replace("#{TRIGRAM}#", $team->getTrigram(), $content); - $dest = Team::fromId($team->getVideoTeamIds()[$video->team - 1]); - $content = preg_replace("#{DEST_TEAM_NAME}#", $dest->getName(), $content); - $content = preg_replace("#{DEST_TRIGRAM}#", $dest->getTrigram(), $content); - $content = preg_replace("#{PROBLEM}#", $team->getProblem(), $content); - $content = preg_replace("#{VIDEO_LINK}#", $video->link, $content); - - self::broadcastToAdmins("Nouvelle vidéo de réponse – Correspondances des Jeunes Mathématicien·ne·s $YEAR - " . ($YEAR + 1), $content); - } - - public static function validateVideo(Video $video, $message) - { - global $YEAR; - - $team = Team::fromId($video->getTeam()); - - $template = "video_"; - $template .= $video->getValidation() == Video::ACCEPTED ? "accepted" : "rejected"; - $template .= $video->getReason() == Reason::SOLUTION ? "_solution" : "_answer"; - $content = self::getTemplate($template); - $content = preg_replace("#{TRIGRAM}#", $team->getTrigram(), $content); - $content = preg_replace("#{PROBLEM}#", $team->getProblem(), $content); - $content = preg_replace("#{VIDEO_LINK}#", $video->getLink(), $content); - if (strlen($message) > 0) - $message = " L'équipe d'organisation vous transmet le message suivant :\n\n" . $message . "\n\n"; - $message = preg_replace("#\n#", "
\n", $message); - $content = preg_replace("#{MESSAGE}#", $message, $content); - - self::broadcastToTeam($team, ($video->getValidation() == Video::REJECTED ? "Vidéo refusée " : "Vidéo acceptée ") - . $team->getTrigram() . " – Correspondances des Jeunes Mathématicien·ne·s $YEAR - " . ($YEAR + 1), $content); - } -} diff --git a/server_files/services/mail_templates/add_admin.html b/server_files/services/mail_templates/add_admin.html deleted file mode 100644 index 1f4745d..0000000 --- a/server_files/services/mail_templates/add_admin.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - Administrateur des Correspondances des Jeunes Mathématicien·ne·s - - -Bonjour {FIRST_NAME} {SURNAME},
-
-Vous recevez ce message (envoyé automatiquement) car vous êtes administrateur pour les Correspondances des Jeunes Mathématicien·ne·s. -Veuillez trouver ci-dessous vos informations d'utilisateur pour le site officiel des inscriptions. Elles vous permettront de gérer les inscriptions des équipes.
-
-Votre mot de passe est : {PASSWORD}
-Vous pouvez vous connecter ici : {URL_BASE}/connexion
-
-Notez bien que ce mot de passe est temporaire, et pour des raisons de sécurité vous devrez le changer lors de votre prochaine connexion sur le site.
-
-Merci beaucoup pour votre aide !
-
-L'organisation des Correspondances des Jeunes Mathématicien·ne·s - - \ No newline at end of file diff --git a/server_files/services/mail_templates/add_team.html b/server_files/services/mail_templates/add_team.html deleted file mode 100644 index 0b2b0a6..0000000 --- a/server_files/services/mail_templates/add_team.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Nouvelle équipe Correspondances des Jeunes Mathématicien·ne·s {YEAR} - - -Bonjour {FIRST_NAME} {SURNAME},
-
-Vous venez de créer l'équipe « {TEAM_NAME} » ({TRIGRAM}) pour les Correspondances des Jeunes Mathématicien·ne·s -{PROBLEM} et nous vous en remercions.
-Afin de permettre aux autres membres de votre équipe de vous rejoindre, veuillez leur transmettre le code d'accès : -{ACCESS_CODE}
-
-Le comité d'organisation des Correspondances des Jeunes Mathématicien·ne·s - - \ No newline at end of file diff --git a/server_files/services/mail_templates/change_email_address.html b/server_files/services/mail_templates/change_email_address.html deleted file mode 100644 index b61c801..0000000 --- a/server_files/services/mail_templates/change_email_address.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - Changement d'adresse e-mail – Correspondances des Jeunes Mathématicien·ne·s - - -Bonjour {FIRST_NAME} {SURNAME},
-
-Vous venez de changer votre adresse e-mail. Veuillez désormais la confirmer en cliquant ici : {URL_BASE}/confirmer-mail/{TOKEN}
-
-Le comité d'organisation des Correspondances des Jeunes Mathématicien·ne·s - - \ No newline at end of file diff --git a/server_files/services/mail_templates/change_password.html b/server_files/services/mail_templates/change_password.html deleted file mode 100644 index f659999..0000000 --- a/server_files/services/mail_templates/change_password.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Mot de passe changé – Correspondances des Jeunes Mathématicien·ne·s - - -Bonjour {FIRST_NAME} {SURNAME},
-
-Nous vous informons que votre mot de passe vient d'être modifié. Si vous n'êtes pas à l'origine de cette manipulation, -veuillez immédiatement vérifier vos accès à votre boîte mail et changer votre mot de passe sur la plateforme -d'inscription.
-
-Cordialement,
-
-Le comité d'organisation des Correspondances des Jeunes Mathématicien·ne·s - - \ No newline at end of file diff --git a/server_files/services/mail_templates/confirm_email.html b/server_files/services/mail_templates/confirm_email.html deleted file mode 100644 index 471323f..0000000 --- a/server_files/services/mail_templates/confirm_email.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - Inscription aux Correspondances des Jeunes Mathématicien·ne·s {YEAR} - - -Bonjour {FIRST_NAME} {SURNAME},
-
-Vous êtes inscrit aux Correspondances des Jeunes Mathématicien·ne·s {YEAR} et nous vous en remercions.
-Pour valider votre adresse e-mail, veuillez cliquer sur le lien : {URL_BASE}/confirmer-mail/{TOKEN}
-
-Cordialement,
-
-Le comité d'organisation des Correspondances des Jeunes Mathématicien·ne·s - - \ No newline at end of file diff --git a/server_files/services/mail_templates/forgotten_password.html b/server_files/services/mail_templates/forgotten_password.html deleted file mode 100644 index a5aa18a..0000000 --- a/server_files/services/mail_templates/forgotten_password.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - Mot de passe oublié – Correspondances des Jeunes Mathématicien·ne·s - - -Bonjour,
-
-Vous avez indiqué avoir oublié votre mot de passe. Veuillez cliquer ici pour le réinitialiser : {URL_BASE}/connexion/reinitialiser_mdp/{TOKEN}
-
-Si vous n'êtes pas à l'origine de cette manipulation, vous pouvez ignorer ce message.
-
-Cordialement,
-
-Le comité d'organisation des Correspondances des Jeunes Mathématicien·ne·s - - \ No newline at end of file diff --git a/server_files/services/mail_templates/join_team.html b/server_files/services/mail_templates/join_team.html deleted file mode 100644 index aa63d65..0000000 --- a/server_files/services/mail_templates/join_team.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Équipe rejointe – Correspondances des Jeunes Mathématicien·ne·s {YEAR} - - -Bonjour {FIRST_NAME} {SURNAME},
-
-Vous venez de rejoindre l'équipe « {TEAM_NAME} » ({TRIGRAM}) pour les Correspondances des Jeunes Mathématicien·ne·s -{PROBLEM} et nous vous en remercions.
-
-Cordialement,
-
-Le comité d'organisation des Correspondances des Jeunes Mathématicien·ne·s - - \ No newline at end of file diff --git a/server_files/services/mail_templates/new_answer.html b/server_files/services/mail_templates/new_answer.html deleted file mode 100644 index 3f9fb3c..0000000 --- a/server_files/services/mail_templates/new_answer.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - Nouvelle vidéo – Correspondances des Jeunes Mathématicien·ne·s {YEAR} - - -Bonjour {FIRST_NAME} {SURNAME},
-
-L'équipe « {TEAM_NAME} » ({TRIGRAM}) vient d'ajouter une vidéo de réponse destinée à l'équipe « {DEST_TEAM_NAME} » ({DEST_TRIGRAM}) -pour le problème {PROBLEM} des Correspondances des Jeunes Mathématicien·ne·s : {VIDEO_LINK}. -Vous êtes désormais invité avant que quelqu'un d'autre ne le fasse à accepter ou refuser cette vidéo via la plateforme d'inscription (accessible après connexion) : -{URL_BASE}/suivi-correspondances
-
-Cordialement,
-
-Le comité d'organisation des Correspondances des Jeunes Mathématicien·ne·s - - \ No newline at end of file diff --git a/server_files/services/mail_templates/new_video.html b/server_files/services/mail_templates/new_video.html deleted file mode 100644 index b98d2d1..0000000 --- a/server_files/services/mail_templates/new_video.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Nouvelle vidéo – Correspondances des Jeunes Mathématicien·ne·s {YEAR} - - -Bonjour {FIRST_NAME} {SURNAME},
-
-L'équipe « {TEAM_NAME} » ({TRIGRAM}) vient d'ajouter une vidéo pour le problème {PROBLEM} des Correspondances des Jeunes Mathématicien·ne·s : {VIDEO_LINK}. -Vous êtes désormais invité avant que quelqu'un d'autre ne le fasse à accepter ou refuser cette vidéo via la plateforme d'inscription (accessible après connexion) : -{URL_BASE}/suivi-correspondances
-
-Cordialement,
-
-Le comité d'organisation des Correspondances des Jeunes Mathématicien·ne·s - - \ No newline at end of file diff --git a/server_files/services/mail_templates/register.html b/server_files/services/mail_templates/register.html deleted file mode 100644 index ab699c9..0000000 --- a/server_files/services/mail_templates/register.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - Inscription aux Correspondances des Jeunes Mathématicien·ne·s {YEAR} - - -Bonjour {FIRST_NAME} {SURNAME},
-
-Vous venez de vous inscrire aux Correspondances des Jeunes Mathématicien·ne·s {YEAR} et nous vous en remercions.
-Pour valider votre adresse e-mail, veuillez cliquer sur le lien : {URL_BASE}/confirmer-mail/{TOKEN}
-
-Le comité d'organisation des Correspondances des Jeunes Mathématicien·ne·s - - \ No newline at end of file diff --git a/server_files/services/mail_templates/request_validation.html b/server_files/services/mail_templates/request_validation.html deleted file mode 100644 index 137166e..0000000 --- a/server_files/services/mail_templates/request_validation.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - Demande de validation - Correspondances des Jeunes Mathématicien·ne·s - - -Bonjour {FIRST_NAME} {SURNAME},
-
-L'équipe « {TEAM_NAME} » ({TRIGRAM}) vient de demander à valider son équipe pour participer au problème n°{PROBLEM} des -Correspondances des Jeunes Mathématicien·ne·s. Vous pouvez décider d'accepter ou de refuser l'équipe en vous rendant sur -la page de l'équipe : {URL_BASE}/equipe/{TRIGRAM}
-
-Cordialement,
-
-L'organisation des Correspondances des Jeunes Mathématicien·ne·s - - \ No newline at end of file diff --git a/server_files/services/mail_templates/unvalidate_team.html b/server_files/services/mail_templates/unvalidate_team.html deleted file mode 100644 index 3c80990..0000000 --- a/server_files/services/mail_templates/unvalidate_team.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - Équipe non validée – Correspondances des Jeunes Mathématicien·ne·s {YEAR} - - -Bonjour {FIRST_NAME} {SURNAME},
-
-Maleureusement, votre équipe « {TEAM_NAME} » ({TRIGRAM}) n'a pas été validée. Veuillez vérifier que vos autorisations -de droit à l'image sont correctes. -{MESSAGE}
-
-N'hésitez pas à nous contacter à l'adresse contact@correspondances-maths.fr -pour plus d'informations. -
-Cordialement,
-
-Le comité d'organisation des Correspondances des Jeunes Mathématicien·ne·s - - \ No newline at end of file diff --git a/server_files/services/mail_templates/validate_team.html b/server_files/services/mail_templates/validate_team.html deleted file mode 100644 index f34caab..0000000 --- a/server_files/services/mail_templates/validate_team.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Équipe validée – Correspondances des Jeunes Mathématicien·ne·s {YEAR} - - -Bonjour {FIRST_NAME} {SURNAME},
-
-Félicitations ! Votre équipe « {TEAM_NAME} » ({TRIGRAM}) est désormais validée ! Vous êtes désormais apte à travailler sur -votre problème. Lorsque les Correspondances auront débutées, vous pourrez soumettre votre vidéo sur la plateforme d'inscription. -{MESSAGE}
-
-Cordialement,
-
-Le comité d'organisation des Correspondances des Jeunes Mathématicien·ne·s - - \ No newline at end of file diff --git a/server_files/services/mail_templates/video_accepted_answer.html b/server_files/services/mail_templates/video_accepted_answer.html deleted file mode 100644 index a3bfe08..0000000 --- a/server_files/services/mail_templates/video_accepted_answer.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - Vidéo acceptée – Correspondances des Jeunes Mathématicien·ne·s {YEAR} - - -Bonjour {FIRST_NAME} {SURNAME},
-
-Félicitations, votre vidéo de réponse pour le problème {PROBLEM} a été validée ! Pour rappel, vous aviez soumis ce lien : {VIDEO_LINK}.
-Vous avez à présent terminé l'aventure des Correspondances. Bravo à vous ! Nous vous recontacterons dans les prochains jours pour vous tenir au courant des résultats.
-Si toutefois vous le souhaitez, vous pouvez à nouveau soumettre une vidéo avant la fin de la phase. Cette nouvelle vidéo ne remplacera l'actuelle qu'au moment de la validation de celle-ci.
-
-N'oubliez pas de contrôler que les paramètres de diffusion de vidéo sont cohérents avec ce que vous souhaitez : {URL_BASE}/mon-equipe
-
-{MESSAGE} -Cordialement,
-
-Le comité d'organisation des Correspondances des Jeunes Mathématicien·ne·s - - \ No newline at end of file diff --git a/server_files/services/mail_templates/video_accepted_solution.html b/server_files/services/mail_templates/video_accepted_solution.html deleted file mode 100644 index 4c62be8..0000000 --- a/server_files/services/mail_templates/video_accepted_solution.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - Vidéo acceptée – Correspondances des Jeunes Mathématicien·ne·s {YEAR} - - -Bonjour {FIRST_NAME} {SURNAME},
-
-Félicitations, votre vidéo pour le problème {PROBLEM} a été validée ! Pour rappel, vous aviez soumis ce lien : {VIDEO_LINK}.
-Votre travail est à présent terminé, et vous pouvez attendre les prochaines phases. Bravo à vous !
-Si toutefois vous le souhaitez, vous pouvez à nouveau soumettre une vidéo avant la fin de la phase. Cette nouvelle vidéo ne remplacera l'actuelle qu'au moment de la validation de celle-ci.
-
-N'oubliez pas de contrôler que les paramètres de diffusion de vidéo sont cohérents avec ce que vous souhaitez : {URL_BASE}/mon-equipe
-
-{MESSAGE} -Cordialement,
-
-Le comité d'organisation des Correspondances des Jeunes Mathématicien·ne·s - - \ No newline at end of file diff --git a/server_files/services/mail_templates/video_rejected_answer.html b/server_files/services/mail_templates/video_rejected_answer.html deleted file mode 100644 index fdf4700..0000000 --- a/server_files/services/mail_templates/video_rejected_answer.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - - Vidéo refusée – Correspondances des Jeunes Mathématicien·ne·s {YEAR} - - -Bonjour {FIRST_NAME} {SURNAME},
-
-Malheureusement, votre vidéo de réponse pour le problème {PROBLEM} n'a pas été validée. Pour rappel, vous aviez soumis -ce lien : {VIDEO_LINK}.
-Si vous aviez soumis une précédente vidéo qui a été validée, elle reste conservée. -Vous êtes désormais invités à retravailler vos réponses ou votre présentation orale afin que votre prestation soit -validée par les organisateurs. N'hésitez pas à nous contacter à -contact@correspondances-maths.fr si vous souhaitez avoir plus -d'informations ou contester ce refus.
-
-{MESSAGE} -Cordialement,
-
-Le comité d'organisation des Correspondances des Jeunes Mathématicien·ne·s - - \ No newline at end of file diff --git a/server_files/services/mail_templates/video_rejected_solution.html b/server_files/services/mail_templates/video_rejected_solution.html deleted file mode 100644 index 3fe16da..0000000 --- a/server_files/services/mail_templates/video_rejected_solution.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - - Vidéo refusée – Correspondances des Jeunes Mathématicien·ne·s {YEAR} - - -Bonjour {FIRST_NAME} {SURNAME},
-
-Malheureusement, votre vidéo pour le problème {PROBLEM} n'a pas été validée. Pour rappel, vous aviez soumis ce lien : -{VIDEO_LINK}.
-Si vous aviez soumis une précédente vidéo qui a été validée, elle reste conservée. -Vous êtes désormais invités à retravailler vos résultats ou votre présentation orale afin que votre prestation soit -validée par les organisateurs. N'hésitez pas à nous contacter à -contact@correspondances-maths.fr si vous souhaitez avoir plus -d'informations ou contester ce refus.
-
-{MESSAGE} -Cordialement,
-
-Le comité d'organisation des Correspondances des Jeunes Mathématicien·ne·s - - \ No newline at end of file diff --git a/server_files/utils.php b/server_files/utils.php deleted file mode 100644 index 6363e82..0000000 --- a/server_files/utils.php +++ /dev/null @@ -1,48 +0,0 @@ - - -
-

Liste des administrateurs

-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - -
- Nom - - Prénom - - Adresse e-mail -
- getSurname() ?>"> - getSurname() ?> - - - getSurname() ?>"> - getFirstName() ?> - - - - getEmail() ?> - -
- Nom - - Prénom - - Adresse e-mail -
- - - -
-

Ajouter un administrateur

-
- - -
- Administrateur ajouté avec succès ! Ses identifiants ont été transmis par mail. -
- - -
-
-
- - -
- -
- - -
-
- -
-
- - -
-
- -
- -
-
- - diff --git a/server_files/views/ajouter_equipe.php b/server_files/views/ajouter_equipe.php deleted file mode 100644 index df1618a..0000000 --- a/server_files/views/ajouter_equipe.php +++ /dev/null @@ -1,78 +0,0 @@ - - -
-

Ajouter une équipe

-
- - -
- Votre équipe a bien été créée ! Voici le code d'accès à transmettre aux autres membres de votre équipe : - access_code ?> -
- -
- Vous êtes déjà dans une équipe. -
-= $CONFIG->getInscriptionDate()) { ?> -
- La date limite d'inscription est dépassée. -
- - - 0) { ?> -
- Vous êtes déjà inscrit dans une équipe. Vous pouvez toutefois encadrer plusieurs équipes. -
- - -
- Chacune des informations pourra être modifiée avant que l'équipe tant que l'équipe n'est pas validée. -
- -
-
-
- - -
- -
- - -
-
- -
- - -
- - - allow_other_teams ? "checked" : "" ?> required/>
- - - allow_publish ? "checked" : "" ?> /> - -
- Cette dernière option est modifiable à tout moment, et permet à Animath de diffuser les vidéos primées. -
- -
- -
-
- - - diff --git a/server_files/views/calendrier.php b/server_files/views/calendrier.php deleted file mode 100644 index 995eed9..0000000 --- a/server_files/views/calendrier.php +++ /dev/null @@ -1,138 +0,0 @@ - - -
-

Calendrier

-
- - - -
-
- -
- - -
-
- -
- -
- - -
-
- - -
-
- -
- -
- - -
-
- - -
-
- -
- -
- - -
-
- - -
-
- -
- -
- - -
-
- - -
-
- -
- -
-
- - - -
getInscriptionDate() ? "warning" : "success" ?>"> - : - getInscriptionDate(), true) ?> -
- -
"> - : - Du getStartPhase1Date(), true) ?> au - getEndPhase1Date(), true) ?> -
- -
"> - : - Du getStartPhase2Date(), true) ?> au - getEndPhase2Date(), true) ?> -
- -
"> - : - Du getStartPhase3Date(), true) ?> au - getEndPhase3Date(), true) ?> -
- -
"> - : - Du getStartPhase4Date(), true) ?> au - getEndPhase4Date(), true) ?> -
- - - - - - - - -
- - - - - - - -
-

Répondre aux questions

-
- - -
- Votre vidéo a bien été envoyée ! -
- - -
- Pour clore vos Correspondances, vous devez produire, pour chaque vidéo reçue d'une autre équipe, une vidéo de - synthèse d'au plus 4 minutes. - Cette vidéo doit mettre en perspective de la vidéo initiale en tenant compte de l'échange qui a eu lieu. - Vous devez mettre en valeur l’échange questions/réponses, et montrer l'évolution de la résolution au problème. -
- -
- Date limite de soumission : getEndPhase4Date(), true) ?> -
- - -
-

Vidéo de l'équipe getName() ?> (getTrigram() ?>) :

-
- Lien de la vidéo de présentation de la solution au problème : - getLink() ?> -
- getLink()) ?> - -
Questions échangées :
- getQuestion(), Question::DEFAULT_QUESTIONS[0]) - && !strcmp($questions[2]->getQuestion(), Question::DEFAULT_QUESTIONS[1]) - && !strcmp($questions[3]->getQuestion(), Question::DEFAULT_QUESTIONS[2])) { ?> -
- L'équipe n'a malheureusement transmis aucune question. Vous n'avez donc pas de réponse à donner. -
- 0 && $question->getQuestion() === null) - continue; - ?> -
- getNumber() . " :" ?> - getQuestion() ?>
- getAttachedFile() !== null) { ?> - Pièce jointe attachée : - Télécharger
- - Réponse : getAnswer() ?>
- getAttachedFileAnswer() !== null) { ?> - Pièce jointe attachée : - Télécharger
- -
- -
-
Vidéo de réponse :
- - getLink(); - echo "
Lien de la vidéo déjà envoyée : $link (version " . $answer->getVersion() . ")
\n"; - displayVideo($link); - switch ($answer->getValidation()) { - case 0: - echo "
La vidéo n'a pas encore été vérifiée par l'équipe d'organisation.
"; - break; - case 1: - echo "
La vidéo a été acceptée par l'équipe d'organisation.
"; - break; - case -1: - echo "
La vidéo a été rejetée par l'équipe d'organisation.
"; - break; - } - } - if ($answer_validated != null && $answer_validated->getId() != $answer->getId()) { - $link = $answer_validated->getLink(); - echo "
\n
Lien de la dernière vidéo validée : $link
\n"; - displayVideo($link); - } - ?> - -
- -
-
- - -
-
- -
- - - - -
-
- Le mail de récupération de mot de passe a bien été envoyé."; - elseif (isset($reset_password) && isset($_POST["password"])) - echo "
Le mot de passe a bien été changé. Vous pouvez désormais vous connecter.
"; - elseif (isset($_GET["confirmation-mail"])) - echo "
Le mail a bien été renvoyé.
"; - else if (isset($logging_in_user)) { - echo "
Connexion réussie !
"; - require_once "footer.php"; - } else if (isset($_SESSION["user_id"])) { - echo "
Vous êtes déjà connecté !
"; - require_once "footer.php"; - } -} - -if (isset($_GET["mdp_oublie"])) { ?> -
-

Réinitialisation du mot de passe

- - - -
-user != null && ($has_error || !isset($_POST["password"]))) { ?> -
-

Connexion

- "/> -
- - -
-
- - -
- -
- - -
-

Connexion

-
-
- - -
-
- - -
- -
- - - - diff --git a/server_files/views/envoyer_video.php b/server_files/views/envoyer_video.php deleted file mode 100644 index dfa8b23..0000000 --- a/server_files/views/envoyer_video.php +++ /dev/null @@ -1,87 +0,0 @@ - - -
-

Envoyer la vidéo de solution

-
- - -
- Votre vidéo a bien été envoyée ! -
- - -
-
    -
  • Une fois vos travaux sur votre problème terminés, vous êtes invités dans le cadre des Correspondances à tourner - une vidéo dans laquelle vous présentez vos résultats.
  • -
  • La vidéo doit durer au maximum 8 minutes.
  • -
  • Un travail de recherche, en équipe sur les problèmes, supervisé par l'encadrant·e, est attendu.
  • -
  • Au début de la vidéo, une brève présentation de l'énoncé est appréciée.
  • -
  • L'équipe doit présenter ses réponses trouvées aux questions de l'énoncé.
  • -
  • Toutes les plateformes d'hébergement vidéo sont supportées. Néanmoins, les plateformes - Viméo, YouTube - et Dailymotion permettent une prévisualisation de la vidéo. - Cette liste pourra être étendue si besoin est.
  • -
  • Les liens de vos vidéos sont soumis à validation à l'équipe d'organisation.
  • -
-
- -
- Date limite de soumission : getEndPhase1Date(), true) ?> -
- - -
- Vous avez soumis précédemment une vidéo, qui a été refusée par l'équipe d'organisation. Les détails ont du vous être transmis par mail. - Vous êtes désormais invités à poster une nouvelle vidéo, conforme aux attentes. En particulier, vérifiez que votre vidéo n'excède pas - la durée limite de 8 minutes. -
- - -getLink(); - echo "
Lien de la vidéo déjà envoyée : $link (version " . $video->getVersion() . ")
\n"; - displayVideo($link); - switch ($video->getValidation()) { - case 0: - echo "
La vidéo n'a pas encore été vérifiée par l'équipe d'organisation.
"; - break; - case 1: - echo "
La vidéo a été acceptée par l'équipe d'organisation.
"; - break; - case -1: - echo "
La vidéo a été rejetée par l'équipe d'organisation.
"; - break; - } -} -if ($video_validated != null && $video_validated->getId() != $video->getId()) { - $link = $video_validated->getLink(); - echo "
\n
Lien de la dernière vidéo validée : $link
\n"; - displayVideo($link); -} -?> - -
- -
-
-
- - -
-
- -
- - - - -
- - - -
-

Informations sur l'équipe

-
- -
- Nom de l'équipe : getName() ?> -
-
- Trigramme : getTrigram() ?> -
-
- getInscriptionDate() && $team->getValidationStatus() == ValidationStatus::NOT_READY) { ?> - -
- -
- - Problème : - getProblem() == 0 ? "Pas de problème choisi" : $team->getProblem() ?> - - -
-
getValidationStatus() == ValidationStatus::WAITING ? "warning" : "danger") ?>"> - Validation de l'équipe - : getValidationStatus()) ?> -
-
- getEncadrantId() !== null) { - $encadrant = User::fromId($team->getEncadrantId()); - $id = $encadrant->getId(); - echo "Encadrant : getFirstName() . " " . $encadrant->getSurname() . "\">" . $encadrant->getFirstName() . " " . $encadrant->getSurname() . "
"; - } - for ($i = 1; $i <= 5; ++$i) { - if ($team->getParticipants()[$i - 1] == NULL) - continue; - $participant = User::fromId($team->getParticipants()[$i - 1]); - $id = $participant->getId(); - echo "Participant $i : getFirstName() . " " . $participant->getSurname() . "\">" . $participant->getFirstName() . " " . $participant->getSurname() . "
"; - } - ?> -
-
- Autorise Animath à diffuser les vidéos : allowPublish() ? "oui" : "non" ?> -
- - - -getValidationStatus() == ValidationStatus::VALIDATED && $team->getSolution() != null && $team->getSolution()->getValidation() == ValidationStatus::VALIDATED - 1) { ?> -
- - - -
-
-
-
- - -
-
-
- - - -
-
- - -
- -

Autorisations de droit à l'image

- - - -
- -
- -getValidationStatus() == ValidationStatus::WAITING) { ?> -
-
-
- - -
- -
-
- - -
-
-
- getValidationStatus() == ValidationStatus::NOT_READY) { ?> -
-
- -
- \ No newline at end of file diff --git a/server_files/views/exporter_donnees.php b/server_files/views/exporter_donnees.php deleted file mode 100644 index 597f711..0000000 --- a/server_files/views/exporter_donnees.php +++ /dev/null @@ -1,33 +0,0 @@ - - -
-

Exporter les données

-
- -
- -
- -
- -
- -
- -
- -
- -
- -
- -

Ce site a enregistré getViews() ?> visites.

- - - - - -
-
-
-
- Ce site a été conçu pour Animath, avec amour et passion. Il est récent et il est possible que - certaines pages ne fonctionnent pas correctement. Si vous remarquez des bugs, merci de les signaler à - l'adresse contact@correspondances-maths.fr.
- © Correspondances de Jeunes Mathématicien·ne·s -
-
-
- - - diff --git a/server_files/views/header.php b/server_files/views/header.php deleted file mode 100644 index 57b78b8..0000000 --- a/server_files/views/header.php +++ /dev/null @@ -1,177 +0,0 @@ -incrViews() ?> - - - - - - !"> - - - - - Site d'inscription pour les Correspondances des Jeunes Mathématicien·ne·s <?= $YEAR . " - " . ($YEAR + 1) ?> - - - - - - - - - - -
-
-
- - -
- Erreur : -
- -
- Le site est actuellement en maintenance. Veuillez réessayer ultérieurement. -
- - -
-
-

- Bienvenue sur le site d'inscription aux - Correspondances des Jeunes Mathématicien·ne·s ! -

-
-
-
-
-

- Tu souhaites participer aux Correspondances ? -
- Ton équipe est déjà formée ? -

-
- -
- -
-
Comment ça marche ?
-

- Pour participer aux Correspondances, il suffit de créer un compte sur la rubrique Inscription. - Vous devrez ensuite confirmer votre adresse e-mail. -

- -

- Vous pouvez accéder à votre compte via la rubrique Connexion. Une fois connecté, vous pourrez créer une équipe - ou en rejoindre une déjà créée par l'un de vos camarades via un code d'accès qui vous aura été transmis. Vous serez ensuite - invité à soumettre une autorisation de droit à l'image, indispensable au bon déroulement des Correspondances. Une fois que votre équipe - comporte au moins 3 participants (maximum 5) et un encadrant, vous pourrez demander à valider votre équipe pour - être apte à travailler sur le problème de votre choix. -

- -
- Attention aux dates ! Si vous ne finalisez pas votre inscription dans le délai indiqué, vous - ne pourrez malheureusement pas participer aux Correspondances. -
- -
- Si votre équipe est déjà formée mais que vous peinez à trouver un encadrant, n'hésitez pas à nous contacter à l'adresse - contact@correspondances-maths.fr pour que nous vous aidions à - vous mettre éventuellement en contact avec un encadrant de votre région. -
-
- -
\ No newline at end of file diff --git a/server_files/views/index.php b/server_files/views/index.php deleted file mode 100644 index 129d4e5..0000000 --- a/server_files/views/index.php +++ /dev/null @@ -1,76 +0,0 @@ - -
- - - -
- -
- -
-
-getInscriptionDate()) { - if ($_SESSION["teams"] == null || sizeof($_SESSION["teams"]) == 0) { ?> -
- Pour participer aux Correspondances, vous devez rejoindre une équipe. Cliquez ici - pour rejoindre une équipe, et ici pour en créer une. -
- getParticipants()[2] == null || $_SESSION["team"]->getEncadrantId() == null) { ?> -
- Votre équipe doit comporter au moins 3 personnes et un encadrant pour pouvoir participer. Pensez - à transmettre - le code d'accès aux autres membres de votre équipe, qui doivent elles aussi s'inscrire sur la - plateforme : - getAccessCode() ?> -
- getProblem() == 0) { ?> -
- Vous devez indiquer problème pour participer. Pensez à le spécifier dans la page Mon équipe. -
- getValidationStatus() == ValidationStatus::NOT_READY) { ?> -
- Pensez à demander la validation de votre équipe pour pouvoir participer aux Correspondances. - Chaque membre de votre - équipe doit pour cela avoir soumis son autorisation de droit à l'image sur la page Mon compte. - Les encadrants ne sont pas concernés. -
- -
- Vous avez soumis précédemment une vidéo pour l'équipe getName() ?>, qui a été refusée par - l'équipe d'organisation. Les détails ont du vous être transmis par mail. - Vous êtes désormais invités à poster une nouvelle vidéo sur la page dédiée, conforme aux - attentes. En particulier, vérifiez - que votre vidéo n'excède pas la durée limite de 8 minutes. -
- getIndexPage()); - - if (isset($_SESSION["user_id"]) && $_SESSION["role"] == Role::ADMIN) { ?> -
- - Modifier la page - - - -
-

getFirstName() . " " . $user->getSurname() ?>

-
- - -
- La personne a bien été exclue de l'équipe ! -
- -
- La personne a bien rejoint l'équipe ! -
- - -
- Rôle : getRole()) ?> -
- -getRole() == Role::PARTICIPANT || $user->getRole() == Role::ENCADRANT) { ?> -
- Équipe - : getTrigram() . "\">" - . $team->getName() . " (" . $team->getTrigram() . ")" ?> - -
-
-
- - -
-
-
- - - -
-
- getValidationStatus() == ValidationStatus::NOT_READY) { ?> -
- - Virer de l'équipe -
- -
- - -getRole() == Role::PARTICIPANT) { ?> -
- Lycée : getSchool() ?>
- Ville : getCity() ?>
- Pays : getCountry() ?>
- Classe : getClass()) ?> -
-getDescription() != "") { ?> -
- Activité professionnelle : getDescription() ?> -
- - -
- Adresse e-mail : getEmail() ?> - getConfirmEmailToken() == null ? "" : "(non validée)" ?> -
- -
- getRole() == Role::ADMIN ? "Reçoit des notifications par mail :" - : "Autorise Animath à envoyer des mails :" ?> doReceiveAnimathMails() ? "oui" : "non" ?> -
- -getRole() == Role::PARTICIPANT) { ?> -
- -
-

Autorisation de droit à l'image :

-
- getId()) { - if ($user->getRole() != Role::ADMIN && $team == null) { ?> -
- -
- -
- - -
- -
- getSurname() ?>"/> -
- - -
-

Formulaire d'inscription

-
- - -
- Vous êtes bien inscrit ! Merci désormais de confirmer votre boîte mail pour valider votre adresse. Pensez à vérifier - vos courriers indésirables. -
- -
- Vous êtes déjà connecté ! -
-= $CONFIG->getInscriptionDate()) { ?> -
- La date limite d'inscription est dépassée. -
- - -
-
- - -
- -
-
- - -
- -
- - -
-
- -
- L'adresse mail sert uniquement à recevoir les informations de déroulement des Correspondances. -
- -
-
- - -
-
- -
-
- - -
-
- - -
-
- -
-
- - -
-
- - -
-
-
-
- - "/> -
-
- - -
-
- -
- - - -
- - - receive_animath_mails ? "checked" : "" ?> />

- -
- -
-
- - - - - - \ No newline at end of file diff --git a/server_files/views/ma_participation.php b/server_files/views/ma_participation.php deleted file mode 100644 index 3084198..0000000 --- a/server_files/views/ma_participation.php +++ /dev/null @@ -1,132 +0,0 @@ - -= Phase::PHASE1) { ?> -
-

Ma participation

-
- -
-

Vidéo de solution proposée :

-
- Lien de la vidéo : getLink() ?> -
- getLink()) ?> -
- = Phase::PHASE3) { ?> -

Questions reçues :

- getFrom()); - $answer = Video::getVideo($asker->getVideoTeamIds()[0] == $team->getId() ? Reason::ANSWER1 : Reason::ANSWER2, - $asker, Video::ACCEPTED); - ?> -
Questions de l'équipe getName() ?> (getTrigram() ?>) :
- getQuestion() === null) - continue; - ?> -
- - getQuestion() ?> -
- getAttachedFile() !== null) { ?> - Pièce jointe attachée : - Télécharger -
- - Réponse : getAnswer() ?>
- getAttachedFileAnswer() !== null) { ?> - Pièce jointe attachée : - Télécharger -
- -
- -
- Phase::PHASE4 && $answer != null) { ?> -
Vidéo de réponse proposée par l'équipe :
-
- Lien de la vidéo : getLink() ?> -
- getLink()) ?> - " : "" ?> - - - - -
- - = Phase::PHASE2) { ?> -
-
- getVideoTeamIds()[$i]); - if ($defender == null) - continue; - $sol = Video::getVideo(Reason::SOLUTION, $defender, Video::ACCEPTED); - $answer = Video::getVideo($i == 0 ? Reason::ANSWER1 : Reason::ANSWER2, $team, Video::ACCEPTED); - $questions = Question::getQuestions($team, $defender); - ?> -

Vidéo de solution proposée par l'équipe getName() ?> - (getTrigram() ?>) :

-
- Lien de la vidéo : getLink() ?> -
- getLink()) ?> -
-
Vos questions :
-
- getQuestion() === null) - continue; - ?> -
- getNumber() ? "Question " . $question->getNumber() : "Remarques générales" ?> : \n", $question->getQuestion()) ?> -
- getAttachedFile() !== null) { ?> - Pièce jointe attachée : - Télécharger -
- - = Phase::PHASE4) { ?> - Réponse : \n", $question->getAnswer()) ?>
- getAttachedFile() !== null) { ?> - Pièce jointe attachée : - Télécharger -
- - -
- -
- = Phase::PHASE4 && $answer != null) { ?> -
Votre vidéo de réponse :
-
- Lien de la vidéo : getLink() ?> -
- getLink()) ?> - - " : "" ?> - - - - - - -
-

Mon compte

-
- - -
- Le fichier a été correctement envoyé ! -
- - - -
- Votre compte a bien été mis à jour ! -
- getEmail() != $my_account->email) { ?> -
- Votre adresse mail a bien été changée. Veuillez vérifier votre boîte mail pour valider votre nouvelle - adresse, vous en aurez besoin pour vous reconnecter. -
- - - -
- -
-
- - -
- -
- - -
-
- -
-
- - -
-
- - - doReceiveAnimathMails() ? "checked" : "" ?> /> - - getRole() == Role::PARTICIPANT) { ?> -
-
- - -
-
- - -
-
- -
-
- - -
-
- - -
-
- - getRole() == Role::ENCADRANT) { ?> - -
- - -
- - - -
- -
-
- -
- -
- -
-
- - -
- -
- - -
- -
- - -
-
- -
- -
-
- -getRole() == Role::PARTICIPANT) { - $not_validated = $_SESSION["team"]->getValidationStatus() == ValidationStatus::NOT_READY - && date("Y-m-d H:i:s") < $CONFIG->getInscriptionDate(); - ?> -
-
-

Autorisation de droit à l'image

-
- - Ce document peut être modifié tant que l'équipe n'est pas validée. - -
- Modèle d'autorisation de droit à l'image : - majeur - mineur -
- - - -
- Le fichier doit être au format PDF, PNG ou JPEG et doit peser moins de 2 Mo. -
-
- -
-
- - -
-
- -
- -
-
- - - - \ No newline at end of file diff --git a/server_files/views/mon_equipe.php b/server_files/views/mon_equipe.php deleted file mode 100644 index 3c58e77..0000000 --- a/server_files/views/mon_equipe.php +++ /dev/null @@ -1,135 +0,0 @@ - - -
-

Mon équipe

-
- -
- Nom de l'équipe : getName() ?> -
-
- Trigramme : getTrigram() ?> -
-
- Problème : - getProblem() == 0 ? "Pas de problème choisi" : $team->getProblem() ?> -
-
- getEncadrantId() !== null) { - $encadrant = User::fromId($team->getEncadrantId()); - $id = $encadrant->getId(); - echo "Encadrant : " . $encadrant->getFirstName() . " " . $encadrant->getSurname() . "
"; - } - for ($i = 1; $i <= 5; ++$i) { - if ($team->getParticipants()[$i - 1] == NULL) - continue; - $participant = User::fromId($team->getParticipants()[$i - 1]); - $id = $participant->getId(); - echo "Participant $i : " . $participant->getFirstName() . " " . $participant->getSurname() . "
"; - } - - ?> -
-
- Code d'accès : getAccessCode() ?> -
-
- - Autorise Animath à diffuser mes vidéos à la fin des Correspondances : - allowPublish() ? "oui" : "non" ?> (changer) -
- -= $CONFIG->getInscriptionDate() && $team->getValidationStatus() == ValidationStatus::NOT_READY) { ?> -
- La date limite d'inscription est dépassée, vous ne pouvez plus demander la validation de votre équipe. -
-getValidationStatus() == ValidationStatus::NOT_READY) { ?> - -
-
-
- - -
- -
- - -
-
- -
- - -
- -
- -
-
- - - - getValidationStatus() == ValidationStatus::NOT_READY && date("Y-m-d H:i:s") <= $CONFIG->getInscriptionDate()) { ?> - - - - - - getValidationStatus() == ValidationStatus::NOT_READY) { ?> -
- -
- -
- - -
-
- - -
- Attention ! Une fois votre équipe validée, vous ne pourrez plus modifier le nom - de l'équipe, le trigramme, le problème sur lequel vous souhaitez travailler ou la composition de l'équipe. -
- -
- -
-
- Pour demander à valider votre équipe, vous devez avoir au moins un encadrant, trois participants, - choisi un problème et soumis une autorisation de droit à l'image par participant. -
- - getValidationStatus() == ValidationStatus::WAITING) { ?> -
- Votre équipe est en attente de validation. -
- - -
- -

Autorisations de l'équipe

- - - - - \ No newline at end of file diff --git a/server_files/views/poser_questions.php b/server_files/views/poser_questions.php deleted file mode 100644 index 013d788..0000000 --- a/server_files/views/poser_questions.php +++ /dev/null @@ -1,98 +0,0 @@ - - -
-

Poser des questions

-
- - -
- Vos questions ont bien été mises à jour ! -
- - -
- Pour cette deuxième phase des Correspondances, vous êtes invités à visionner les vidéos de solution de deux autres - équipes, qui ont travaillé sur le même problème que vous. Vous devez désormais poser entre 3 et 6 questions, portant - sur la présentation de l'équipe. Chaque question peut-être accompagnée d'une pièce jointe (dessin, schéma, ...) - sous toute forme (PDF, image, archive, ...) tant que le poids ne dépasse pas 2 Mo. Si vous le souhaitez, vous pouvez - adresser aux équipes des remarques plus générales. -
- -
- Date limite de soumission des questions : getEndPhase2Date(), true) ?> -
- -
-

Veuillez toujours enregistrer votre travail ailleurs que sur la plateforme !

-
- - -
-

Questions pour l'équipe getName() ?> (getTrigram() ?>) :

-
- Lien de la vidéo : getLink() ?> -
- getLink()) ?> -
-
- - - getQuestion() == null && $j > 0) { ?> - " - onclick="addQuestion(, )">Ajouter une question -
- -
;"> -
- - -
- - getAttachedFile() != null) { ?> -
-
- Pièce jointe : Télécharger -
- - -
- - -
-
- - - - - -
-
- - - - -
-

- -

-
- -
- -

Équipes inscrites 0 ? "pour ce problème" : "sans problème choisi" ?> :

- - - - - - - - 0) { ?> - - - - - - - - - - - 0) { ?> - - - - - - - - - - - 0) { ?> - - - - -
- Équipe - - Trigramme - - Date d'inscription - - État de validation de l'inscription -
- getTrigram() . "\">" . $team->getName() . ""; - else - echo $team->getName(); - ?> - getTrigram() ?>getInscriptionDate()) ?>getValidationStatus()) ?>
- Équipe - - Trigramme - - Date d'inscription - - État de validation de l'inscription -
- - - - - diff --git a/server_files/views/profiles.php b/server_files/views/profiles.php deleted file mode 100644 index cc8f2e6..0000000 --- a/server_files/views/profiles.php +++ /dev/null @@ -1,63 +0,0 @@ - - -
-

-
- -
- Cette page recense tous les utilisateurs inscrits. -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - -
- Nom - - Rôle - - Inscrit le -
- getFirstName() . " " . $user->getSurname() ?>"> - getFirstName() . " " . $user->getSurname() ?> - - getRole()) ?>getInscriptionDate(), true) ?>
- Nom - - Rôle - - Inscrit le -
- - - -
-

Rejoindre une équipe

-
- - -
- Vous avez bien rejoint l'équipe getName() ?> ! -
-= $CONFIG->getInscriptionDate()) { ?> -
- La date limite d'inscription est dépassée. -
- - - 0) { ?> -
- Vous êtes déjà inscrit dans une équipe. Vous pouvez toutefois encadrer plusieurs équipes. -
- - -
-
-
- - -
-
- -
- -
-
- - - - \ No newline at end of file diff --git a/server_files/views/repondre_questions.php b/server_files/views/repondre_questions.php deleted file mode 100644 index ca578bc..0000000 --- a/server_files/views/repondre_questions.php +++ /dev/null @@ -1,93 +0,0 @@ - - -
-

Répondre aux questions

-
- - -
- Vos réponses ont bien été mises à jour ! -
- - -
- Deux autres équipes ayant travaillé sur le même problème que vous vous ont posé quelques questions. Afin de faire - avancer l'échange, vous êtes invités à répondre à leurs interrogations. Vous êtes libres d'ajouter à votre souhait - un paragraphe de remarques. -
- -
- Date limite de soumission des réponses : getEndPhase3Date(), true) ?> -
- -
- Lien de la vidéo : getLink() ?> -
- -getLink()); ?> - -getFrom()); - $remark = $questions_team[0]; - echo "

Questions de l'équipe " . $from->getName() . " (" . $from->getTrigram() . ") :

\n"; - if (!strcmp($questions_team[1]->getQuestion(), Question::DEFAULT_QUESTIONS[0]) - && !strcmp($questions_team[2]->getQuestion(), Question::DEFAULT_QUESTIONS[1]) - && !strcmp($questions_team[3]->getQuestion(), Question::DEFAULT_QUESTIONS[2])) { ?> -
- L'équipe n'a malheureusement transmis aucune question. Vous n'avez donc pas de réponse à donner. -
- -
- - - 0 && $question->getQuestion() == null) - continue; - ?> -
- getNumber() . " :" ?> - getQuestion() ?>
- getAttachedFile() != null) { ?> - Pièce jointe : - Télécharger
- -
-
- - -
-
- getAttachedFileAnswer() != null) { ?> - Pièce jointe : - Télécharger - -
-
- - -
-
-
- - - - -
-
- - - - - -
-

Suivi des Correspondances

-
- - 0) { ?> -
- pas encore - participé à la phase en cours : - pas encore participé à la phase en cours, ou leurs vidéos n'ont pas encore été validées : - - subject=Correspondances de Jeunes Mathématicien·ne·s" - target="_blank">Leur envoyer un mail -
- - -
- subject=Correspondances de Jeunes Mathématicien·ne·s" target="_blank"> - - - -
- - -
-

Vidéos pour le problème

-
- getLink(); - $team = Team::fromId($video->getTeam()); - $version = $video->getVersion(); - ?> -
-

- Équipe « getName() ?> » (getTrigram() ?>) -

-
- Lien de la vidéo (version ) : -
- getValidation() <= 0) { ?> -
- - - -
- - -
- - - getValidation() == 0) { ?> - - -
-
- getValidation() != 0) { ?> -
"> - La vidéo a été getValidation() == 1 ? "acceptée" : "refusée" ?>. -
- getValidation() != Video::ACCEPTED) { - $last_validated_video = Video::getVideo(Reason::SOLUTION, $team, Video::ACCEPTED); - if ($last_validated_video !== null) { - $link = $last_validated_video->getLink(); ?> -
- Lien de la vidéo validée de cette équipe (version ) : - -
- Phase::PHASE1) { - /** @var Question[] $from_questions */ - foreach (Question::getQuestionsTo($team) as $from_questions) { - - $from = Team::fromId($from_questions[0]->getFrom()); - echo "
Questions posées par l'équipe " . $from->getName() . " (" . $from->getTrigram() . ") :
\n"; - if (!strcmp($from_questions[1]->getQuestion(), Question::DEFAULT_QUESTIONS[0]) - && !strcmp($from_questions[2]->getQuestion(), Question::DEFAULT_QUESTIONS[1]) - && !strcmp($from_questions[3]->getQuestion(), Question::DEFAULT_QUESTIONS[2])) { ?> -
"> - Cette équipe n'a pas envoyé ses questions. -
- 0 && $question->getQuestion() == null) - continue; - - echo "
\n"; - echo "" . ($i == 0 ? "Remarques générales :" : "Question " . $i . " :") . " " . preg_replace("#\n#", "
\n", $question->getQuestion()) . "
\n"; - if ($question->getAttachedFile() != null) - echo "Pièce jointe attachée : getAttachedFile() . "\">Télécharger
\n"; - if ($question->getAnswer() != null) - echo "Réponse apportée : " . preg_replace("#\n#", "
\n", $question->getAnswer()) . "
\n"; - if ($question->getAttachedFileAnswer() != null) - echo "Pièce jointe attachée pour la réponse : getAttachedFileAnswer() . "\">Télécharger
\n"; - echo "
\n"; - } - echo "
\n"; - if (Phase::getCurrentPhase() >= Phase::PHASE4) { - $answer = Video::getVideo($from->getVideoTeamIds()[0] == $team->getId() ? Reason::ANSWER1 : Reason::ANSWER2, $from); - if ($answer == null) - continue; - $link = $answer->getLink(); - $version = $answer->getVersion(); - echo "
Vidéo de réponse :
\n"; - echo "Lien de la vidéo (version $version) : $link"; - displayVideo($link); - - if ($answer->getValidation() == 0) { ?> -
- - - -
- - -
- - - getValidation() == 0) { ?> - - -
-
- getValidation() != 0) { ?> -
"> - La vidéo a été getValidation() == 1 ? "acceptée" : "refusée" ?>. -
- getValidation() != Video::ACCEPTED) { - $last_validated_answer = Video::getVideo($from->getVideoTeamIds()[0] == $team->getId() ? Reason::ANSWER1 : Reason::ANSWER2, $team, Video::ACCEPTED); - if ($last_validated_answer !== null) { - $link = $last_validated_answer->getLink(); - echo "\n
\nLien de la dernière vidéo validée de cette équipe : $link
\n"; - displayVideo($link); - } - } - } - } - } - } ?> -
- \n"; -} - -require_once "footer.php"; \ No newline at end of file diff --git a/setup/create_database.sql b/setup/create_database.sql deleted file mode 100644 index 10aefe1..0000000 --- a/setup/create_database.sql +++ /dev/null @@ -1,146 +0,0 @@ --- phpMyAdmin SQL Dump --- version 4.7.5 --- https://www.phpmyadmin.net/ --- --- Hôte : db --- Généré le : mar. 22 oct. 2019 à 13:10 --- Version du serveur : 5.7.20 --- Version de PHP : 7.1.9 - -SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; -SET AUTOCOMMIT = 0; -START TRANSACTION; -SET time_zone = "+00:00"; - - -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; -/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; -/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; -/*!40101 SET NAMES utf8mb4 */; - --- --- Base de données : `inscription_corres2math` --- - --- -------------------------------------------------------- - --- --- Structure de la table `config` --- - -CREATE TABLE IF NOT EXISTS `config` ( - `key` varchar(64) NOT NULL, - `value` varchar(8192) NOT NULL, - PRIMARY KEY (`key`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - --- -------------------------------------------------------- - --- --- Structure de la table `documents` --- - -CREATE TABLE IF NOT EXISTS `documents` ( - `file_id` varchar(64) NOT NULL, - `user` int(11) NOT NULL, - `team` int(11) NOT NULL, - `problem` int(11) NOT NULL, - `uploaded_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY (`file_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - --- -------------------------------------------------------- - --- --- Structure de la table `questions` --- - -CREATE TABLE IF NOT EXISTS `questions` ( - `id` int(8) NOT NULL AUTO_INCREMENT, - `from` int(8) NOT NULL, - `to` int(8) NOT NULL, - `problem` int(8) NOT NULL, - `number` int(8) NOT NULL, - `question` varchar(1024) DEFAULT NULL, - `attached_file` varchar(64) DEFAULT NULL, - `answer` varchar(1024) DEFAULT NULL, - `attached_file_answer` varchar(64) DEFAULT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - --- -------------------------------------------------------- - --- --- Structure de la table `teams` --- - -CREATE TABLE IF NOT EXISTS `teams` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `name` varchar(64) NOT NULL, - `trigram` varchar(3) NOT NULL, - `problem` int(8) NOT NULL, - `encadrant` int(8) DEFAULT NULL, - `participant_1` int(8) DEFAULT NULL, - `participant_2` int(8) DEFAULT NULL, - `participant_3` int(8) DEFAULT NULL, - `participant_4` int(8) DEFAULT NULL, - `participant_5` int(8) DEFAULT NULL, - `inscription_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `allow_publish` tinyint(1) NOT NULL DEFAULT '0', - `validation_status` varchar(64) NOT NULL, - `video_team1` int(11) DEFAULT NULL, - `video_team2` int(11) DEFAULT NULL, - `access_code` varchar(6) NOT NULL, - `year` int(4) NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - --- -------------------------------------------------------- - --- --- Structure de la table `users` --- - -CREATE TABLE IF NOT EXISTS `users` ( - `id` int(8) NOT NULL AUTO_INCREMENT, - `email` varchar(255) NOT NULL, - `pwd_hash` varchar(64) NOT NULL, - `surname` varchar(255) NOT NULL, - `first_name` varchar(255) NOT NULL, - `school` varchar(255) DEFAULT NULL, - `city` varchar(256) DEFAULT NULL, - `country` varchar(256) DEFAULT NULL, - `class` varchar(255) DEFAULT NULL, - `description` varchar(255) DEFAULT NULL, - `role` varchar(64) NOT NULL, - `team_id` int(8) DEFAULT NULL, - `receive_animath_mails` tinyint(1) NOT NULL DEFAULT '0', - `year` int(4) NOT NULL DEFAULT '2020', - `confirm_email` varchar(64) DEFAULT NULL COMMENT 'Jeton de confirmation d''e-mail', - `forgotten_password` varchar(64) DEFAULT NULL COMMENT 'Jeton de récupération de mot de passe', - `inscription_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - --- -------------------------------------------------------- - --- --- Structure de la table `videos` --- - -CREATE TABLE IF NOT EXISTS `videos` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `team` int(8) NOT NULL, - `problem` int(8) NOT NULL, - `link` varchar(128) NOT NULL, - `reason` varchar(64) NOT NULL, - `validation` tinyint(1) NOT NULL DEFAULT '0', - `uploaded_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, - `year` int(4) NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; -COMMIT; - -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; -/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; -/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/setup/msmtprc b/setup/msmtprc deleted file mode 100644 index 0be3f65..0000000 --- a/setup/msmtprc +++ /dev/null @@ -1,18 +0,0 @@ -defaults -auth on -tls on -tls_starttls off -tls_trust_file /etc/ssl/certs/ca-certificates.crt -syslog on -logfile /var/log/msmtp.log - -account corres2math -host ssl0.ovh.net -auth on -port 465 -from contact@correspondances-maths.fr -user contact@correspondances-maths.fr -passwordeval "echo $CORRES2MATH_MAIL_PASSWORD" - -# Set a default account -account default : corres2math diff --git a/templates/400.html b/templates/400.html new file mode 100644 index 0000000..0734a85 --- /dev/null +++ b/templates/400.html @@ -0,0 +1,8 @@ +{% extends "base.html" %} + +{% load i18n %} + +{% block content %} +

{% trans "Bad request" %}

+ {% blocktrans %}Sorry, your request was bad. Don't know what could be wrong. An email has been sent to webmasters with the details of the error. You can now watch some videos.{% endblocktrans %} +{% endblock %} \ No newline at end of file diff --git a/templates/403.html b/templates/403.html new file mode 100644 index 0000000..317865f --- /dev/null +++ b/templates/403.html @@ -0,0 +1,13 @@ +{% extends "base.html" %} + +{% load i18n %} + +{% block content %} +

{% trans "Permission denied" %}

+ {% blocktrans %}You don't have the right to perform this request.{% endblocktrans %} + {% if exception %} +
+ {% trans "Exception message:" %} {{ exception }} +
+ {% endif %} +{% endblock %} \ No newline at end of file diff --git a/templates/404.html b/templates/404.html new file mode 100644 index 0000000..8477f91 --- /dev/null +++ b/templates/404.html @@ -0,0 +1,13 @@ +{% extends "base.html" %} + +{% load i18n %} + +{% block content %} +

{% trans "Page not found" %}

+ {% blocktrans %}The requested path {{ request_path }} was not found on the server.{% endblocktrans %} + {% if exception != "Resolver404" %} +
+ {% trans "Exception message:" %} {{ exception }} +
+ {% endif %} +{% endblock %} \ No newline at end of file diff --git a/templates/500.html b/templates/500.html new file mode 100644 index 0000000..38d12e4 --- /dev/null +++ b/templates/500.html @@ -0,0 +1,8 @@ +{% extends "base.html" %} + +{% load i18n %} + +{% block content %} +

{% trans "Server error" %}

+ {% blocktrans %}Sorry, an error occurred when processing your request. An email has been sent to webmasters with the detail of the error, and this will be fixed soon. You can now watch some videos.{% endblocktrans %} +{% endblock %} diff --git a/templates/amount_input.html b/templates/amount_input.html new file mode 100644 index 0000000..6ef4a53 --- /dev/null +++ b/templates/amount_input.html @@ -0,0 +1,11 @@ +
+ +
+ +
+
\ No newline at end of file diff --git a/templates/autocomplete_model.html b/templates/autocomplete_model.html new file mode 100644 index 0000000..2236c6e --- /dev/null +++ b/templates/autocomplete_model.html @@ -0,0 +1,9 @@ + + +
    +
diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000..eceb437 --- /dev/null +++ b/templates/base.html @@ -0,0 +1,154 @@ +{% load static i18n static %} + + + + + + + + {% block title %}{{ title }}{% endblock title %} - Plateforme des Correspondances + + + + {# Favicon #} + + + {% if no_cache %} + + {% endif %} + + {# Bootstrap CSS #} + + + + + {# JQuery, Bootstrap and Turbolinks JavaScript #} + + + + + + {# Si un formulaire requiert des données supplémentaires (notamment JS), les données sont chargées #} + {% if form.media %} + {{ form.media }} + {% endif %} + + + + {% block extracss %}{% endblock %} + + +
+ +
+ {% block contenttitle %}

{{ title }}

{% endblock %} +
+ {% block content %} +

Default content...

+ {% endblock content %} +
+
+ +
+
+
+
+
+ + — + {% trans "Contact us" %} — + + {% csrf_token %} + + +
+
+ +
+
+
+ + + +{% block extrajavascript %} +{% endblock extrajavascript %} + + diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..8272782 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,6 @@ +{% extends "base.html" %} + +{% block content %} + {% autoescape off %} + {% endautoescape %} +{% endblock %} diff --git a/templates/registration/email_validation_complete.html b/templates/registration/email_validation_complete.html new file mode 100644 index 0000000..f58a7e5 --- /dev/null +++ b/templates/registration/email_validation_complete.html @@ -0,0 +1,27 @@ +{% extends "base.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} +{% load i18n %} + +{% block content %} +
+

+ {{ title }} +

+
+ {% if validlink %} +

+ {% trans "Your email have successfully been validated." %} +

+

+ {% blocktrans %}You can now log in.{% endblocktrans %} +

+ {% else %} +

+ {% trans "The link was invalid. The token may have expired. Please send us an email to activate your account." %} +

+ {% endif %} +
+
+{% endblock %} diff --git a/templates/registration/email_validation_email_sent.html b/templates/registration/email_validation_email_sent.html new file mode 100644 index 0000000..adc0c02 --- /dev/null +++ b/templates/registration/email_validation_email_sent.html @@ -0,0 +1,18 @@ +{% extends "base.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} +{% load i18n %} + +{% block content %} +
+

+ {% trans "Account activation" %} +

+
+

+ {% trans "An email has been sent. Please click on the link to activate your account." %} +

+
+
+{% endblock %} diff --git a/templates/registration/logged_out.html b/templates/registration/logged_out.html new file mode 100644 index 0000000..3b044b7 --- /dev/null +++ b/templates/registration/logged_out.html @@ -0,0 +1,10 @@ +{% extends "base.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} +{% load i18n %} + +{% block content %} +

{% trans "Thanks for spending some quality time with the Web site today." %}

+

{% trans 'Log in again' %}

+{% endblock %} diff --git a/templates/registration/login.html b/templates/registration/login.html new file mode 100644 index 0000000..64c5c26 --- /dev/null +++ b/templates/registration/login.html @@ -0,0 +1,25 @@ +{% extends "base.html" %} +{% comment %} +SPDX-License-Identifier: GPL-2.0-or-later +{% endcomment %} +{% load i18n crispy_forms_filters %} + +{% block title %}{% trans "Log in" %}{% endblock %} +{% block contenttitle %}

{% trans "Log in" %}

{% endblock %} + +{% block content %} + {% if user.is_authenticated %} +

+ {% blocktrans trimmed %} + You are authenticated as {{ user }}, but are not authorized to + access this page. Would you like to login to a different account? + {% endblocktrans %} +

+ {% endif %} +
+ {% csrf_token %} + {{ form | crispy }} + + {% trans 'Forgotten your password or username?' %} +
+{% endblock %} diff --git a/templates/registration/mails/email_validation_email.html b/templates/registration/mails/email_validation_email.html new file mode 100644 index 0000000..cd0bfed --- /dev/null +++ b/templates/registration/mails/email_validation_email.html @@ -0,0 +1,36 @@ +{% load i18n %} + + + + + + + + + +

+ {% trans "Hi" %} {{ user.username }}, +

+ +

+ {% trans "You recently registered on the Correspondances platform. Please click on the link below to confirm your registration." %} +

+ +

+ + https://{{ domain }}{% url 'member:email_validation' uidb64=uid token=token %} + +

+ +

+ {% trans "This link is only valid for a couple of days, after that you will need to contact us to validate your email." %} +

+ +

+ {% trans "Thanks" %}, +

+ +-- +

+ {% trans "The CNO." %}
+

diff --git a/templates/registration/mails/email_validation_email.txt b/templates/registration/mails/email_validation_email.txt new file mode 100644 index 0000000..b12d3fa --- /dev/null +++ b/templates/registration/mails/email_validation_email.txt @@ -0,0 +1,13 @@ +{% load i18n %} + +{% trans "Hi" %} {{ user.username }}, + +{% trans "You recently registered on the Correspondances platform. Please click on the link below to confirm your registration." %} + +https://{{ domain }}{% url 'member:email_validation' uidb64=uid token=token %} + +{% trans "This link is only valid for a couple of days, after that you will need to contact us to validate your email." %} + +{% trans "Thanks" %}, + +{% trans "The CNO." %} diff --git a/templates/registration/password_change_done.html b/templates/registration/password_change_done.html new file mode 100644 index 0000000..150a00e --- /dev/null +++ b/templates/registration/password_change_done.html @@ -0,0 +1,9 @@ +{% extends "base.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} +{% load i18n %} + +{% block content %} +

{% trans 'Your password was changed.' %}

+{% endblock %} diff --git a/templates/registration/password_change_form.html b/templates/registration/password_change_form.html new file mode 100644 index 0000000..01133e4 --- /dev/null +++ b/templates/registration/password_change_form.html @@ -0,0 +1,13 @@ +{% extends "base.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} +{% load i18n crispy_forms_tags %} + +{% block content %} +
{% csrf_token %} +

{% trans "Please enter your old password, for security's sake, and then enter your new password twice so we can verify you typed it in correctly." %}

+ {{ form | crispy }} + +
+{% endblock %} \ No newline at end of file diff --git a/templates/registration/password_reset_complete.html b/templates/registration/password_reset_complete.html new file mode 100644 index 0000000..dec34f6 --- /dev/null +++ b/templates/registration/password_reset_complete.html @@ -0,0 +1,12 @@ +{% extends "base.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} +{% load i18n %} + +{% block content %} +

{% trans "Your password has been set. You may go ahead and log in now." %}

+

+ {% trans 'Log in' %} +

+{% endblock %} diff --git a/templates/registration/password_reset_confirm.html b/templates/registration/password_reset_confirm.html new file mode 100644 index 0000000..6432872 --- /dev/null +++ b/templates/registration/password_reset_confirm.html @@ -0,0 +1,17 @@ +{% extends "base.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} +{% load i18n crispy_forms_tags %} + +{% block content %} + {% if validlink %} +

{% trans "Please enter your new password twice so we can verify you typed it in correctly." %}

+
{% csrf_token %} + {{ form | crispy }} + +
+ {% else %} +

{% trans "The password reset link was invalid, possibly because it has already been used. Please request a new password reset." %}

+ {% endif %} +{% endblock %} diff --git a/templates/registration/password_reset_done.html b/templates/registration/password_reset_done.html new file mode 100644 index 0000000..a215ab9 --- /dev/null +++ b/templates/registration/password_reset_done.html @@ -0,0 +1,10 @@ +{% extends "base.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} +{% load i18n %} + +{% block content %} +

{% trans "We've emailed you instructions for setting your password, if an account exists with the email you entered. You should receive them shortly." %}

+

{% trans "If you don't receive an email, please make sure you've entered the address you registered with, and check your spam folder." %}

+{% endblock %} diff --git a/templates/registration/password_reset_form.html b/templates/registration/password_reset_form.html new file mode 100644 index 0000000..61adaa9 --- /dev/null +++ b/templates/registration/password_reset_form.html @@ -0,0 +1,13 @@ +{% extends "base.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} +{% load i18n crispy_forms_tags %} + +{% block content %} +

{% trans "Forgotten your password? Enter your email address below, and we'll email instructions for setting a new one." %}

+
{% csrf_token %} + {{ form | crispy }} + +
+{% endblock %} diff --git a/templates/registration/signup.html b/templates/registration/signup.html new file mode 100644 index 0000000..ed100d0 --- /dev/null +++ b/templates/registration/signup.html @@ -0,0 +1,17 @@ + +{% extends 'base.html' %} +{% load crispy_forms_filters %} +{% load i18n %} +{% block title %}{% trans "Sign up" %}{% endblock %} + +{% block content %} +

{% trans "Sign up" %}

+ +
+ {% csrf_token %} + {{ form|crispy }} + +
+{% endblock %}