mirror of
				https://gitlab.com/animath/si/plateforme-corres2math.git
				synced 2025-10-31 21:04:34 +01:00 
			
		
		
		
	Restart the project in Django
This commit is contained in:
		
							
								
								
									
										45
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										45
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1 +1,44 @@ | |||||||
| .idea/ | # 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/ | ||||||
|   | |||||||
| @@ -1,4 +0,0 @@ | |||||||
| Options +FollowSymlinks |  | ||||||
| Options -Indexes |  | ||||||
| RewriteEngine On |  | ||||||
| RewriteRule ^(.*)$ dispatcher.php?path=$1 [QSA,L] |  | ||||||
							
								
								
									
										52
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										52
									
								
								Dockerfile
									
									
									
									
									
								
							| @@ -1,39 +1,31 @@ | |||||||
| FROM php:7.3-apache as plateforme-builder | FROM python:3-alpine | ||||||
|  |  | ||||||
| # Enabling apache rewrite mod | ENV PYTHONUNBUFFERED 1 | ||||||
| RUN a2enmod rewrite |  | ||||||
|  |  | ||||||
| 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 apk add --no-cache bash | ||||||
| RUN docker-php-ext-install pdo_mysql \ |  | ||||||
|     &&  docker-php-ext-enable pdo_mysql |  | ||||||
|  |  | ||||||
| # Install zip utilities | RUN mkdir /code | ||||||
| RUN apt install -y libzip-dev zip \ | WORKDIR /code | ||||||
|     && docker-php-ext-configure zip --with-libzip \ | COPY requirements.txt /code/requirements.txt | ||||||
|     && docker-php-ext-install zip \ | RUN pip install -r requirements.txt --no-cache-dir | ||||||
|     &&  docker-php-ext-enable zip |  | ||||||
|  |  | ||||||
| # Setup locales | COPY . /code/ | ||||||
| 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 |  | ||||||
|  |  | ||||||
| # Setup timezone | # Configure nginx | ||||||
| RUN echo Europe/Paris > /etc/timezone \ | RUN mkdir /run/nginx | ||||||
|     && ln -sf /usr/share/zoneinfo/Europe/Paris /etc/localtime \ | RUN ln -sf /dev/stdout /var/log/nginx/access.log && ln -sf /dev/stderr /var/log/nginx/error.log | ||||||
|     && dpkg-reconfigure -f noninteractive tzdata | RUN ln -sf /code/nginx_corres2math.conf /etc/nginx/conf.d/corres2math.conf | ||||||
|  | RUN rm /etc/nginx/conf.d/default.conf | ||||||
|  |  | ||||||
| # Setup mailing | RUN cp /code/corres2math.cron /etc/crontabs/corres2math | ||||||
| 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 |  | ||||||
|  |  | ||||||
| # Setting environment | # With a bashrc, the shell is better | ||||||
| ENV CORRES2MATH_LOCAL_PATH /var/www/html | RUN ln -s /code/.bashrc /root/.bashrc | ||||||
| ENV CORRES2MATH_MAIL_DOMAIN correspondances-maths.fr |  | ||||||
| ENV CORRES2MATH_URL_BASE https://inscription.correspondances-maths.fr |  | ||||||
|  |  | ||||||
| RUN chmod 0777 /var/www/html | ENTRYPOINT ["/code/entrypoint.sh"] | ||||||
|  | EXPOSE 80 | ||||||
|  |  | ||||||
|  | CMD ["./manage.py", "shell_plus", "--ptpython"] | ||||||
|   | |||||||
							
								
								
									
										64
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -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. | ||||||
							
								
								
									
										1
									
								
								apps/api/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								apps/api/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | default_app_config = 'api.apps.APIConfig' | ||||||
							
								
								
									
										10
									
								
								apps/api/apps.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								apps/api/apps.py
									
									
									
									
									
										Normal file
									
								
							| @@ -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') | ||||||
							
								
								
									
										15
									
								
								apps/api/serializers.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								apps/api/serializers.py
									
									
									
									
									
										Normal file
									
								
							| @@ -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', | ||||||
|  |         ) | ||||||
							
								
								
									
										18
									
								
								apps/api/urls.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								apps/api/urls.py
									
									
									
									
									
										Normal file
									
								
							| @@ -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')), | ||||||
|  | ] | ||||||
							
								
								
									
										17
									
								
								apps/api/viewsets.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								apps/api/viewsets.py
									
									
									
									
									
										Normal file
									
								
							| @@ -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', ] | ||||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 8.6 KiB | 
| @@ -1,47 +0,0 @@ | |||||||
| html, body { |  | ||||||
|     height: 100%; |  | ||||||
|     margin: 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| :root { |  | ||||||
|     --navbar-height: 32px; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .container { |  | ||||||
|     min-height: 78%; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .inner { |  | ||||||
|     margin: 20px; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .alert { |  | ||||||
|     text-align: justify; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| footer .alert { |  | ||||||
|     text-align: center; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #navbar-logo { |  | ||||||
|     height: var(--navbar-height); |  | ||||||
|     display: block; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| ul .deroule { |  | ||||||
|     display: none; |  | ||||||
|     position: absolute; |  | ||||||
|     background: #f8f9fa !important; |  | ||||||
|     list-style-type: none; |  | ||||||
|     padding: 20px; |  | ||||||
|     z-index: 42; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| li:hover ul.deroule { |  | ||||||
|     display:block; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| a.nav-link:hover { |  | ||||||
|     background-color: #d8d9da; |  | ||||||
| } |  | ||||||
							
								
								
									
										5
									
								
								corres2math.cron
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								corres2math.cron
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | # m  h   dom mon dow     user   command | ||||||
|  | # Envoyer les mails en attente | ||||||
|  |  *   *     *   *   *     root   cd /code && python manage.py send_mail -c 1 | ||||||
|  |  *   *     *   *   *     root   cd /code && python manage.py retry_deferred -c 1 | ||||||
|  |  00  0     *   *   *     root   cd /code && python manage.py purge_mail_log 7 -c 1 | ||||||
							
								
								
									
										0
									
								
								corres2math/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								corres2math/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										16
									
								
								corres2math/asgi.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								corres2math/asgi.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | """ | ||||||
|  | ASGI config for corres2math project. | ||||||
|  |  | ||||||
|  | It exposes the ASGI callable as a module-level variable named ``application``. | ||||||
|  |  | ||||||
|  | For more information on this file, see | ||||||
|  | https://docs.djangoproject.com/en/3.0/howto/deployment/asgi/ | ||||||
|  | """ | ||||||
|  |  | ||||||
|  | import os | ||||||
|  |  | ||||||
|  | from django.core.asgi import get_asgi_application | ||||||
|  |  | ||||||
|  | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'corres2math.settings') | ||||||
|  |  | ||||||
|  | application = get_asgi_application() | ||||||
							
								
								
									
										322
									
								
								corres2math/inputs.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										322
									
								
								corres2math/inputs.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,322 @@ | |||||||
|  | from json import dumps as json_dumps | ||||||
|  |  | ||||||
|  | from django.forms.widgets import DateTimeBaseInput, NumberInput, TextInput, Widget | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class AmountInput(NumberInput): | ||||||
|  |     """ | ||||||
|  |     This input type lets the user type amounts in euros, but forms receive data in cents | ||||||
|  |     """ | ||||||
|  |     template_name = "amount_input.html" | ||||||
|  |  | ||||||
|  |     def format_value(self, value): | ||||||
|  |         return None if value is None or value == "" else "{:.02f}".format(int(value) / 100, ) | ||||||
|  |  | ||||||
|  |     def value_from_datadict(self, data, files, name): | ||||||
|  |         val = super().value_from_datadict(data, files, name) | ||||||
|  |         return str(int(100 * float(val))) if val else val | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Autocomplete(TextInput): | ||||||
|  |     template_name = "autocomplete_model.html" | ||||||
|  |  | ||||||
|  |     def __init__(self, model, attrs=None): | ||||||
|  |         super().__init__(attrs) | ||||||
|  |  | ||||||
|  |         self.model = model | ||||||
|  |         self.model_pk = None | ||||||
|  |  | ||||||
|  |     class Media: | ||||||
|  |         """JS/CSS resources needed to render the date-picker calendar.""" | ||||||
|  |  | ||||||
|  |         js = ('js/autocomplete_model.js', ) | ||||||
|  |  | ||||||
|  |     def format_value(self, value): | ||||||
|  |         if value: | ||||||
|  |             self.attrs["model_pk"] = int(value) | ||||||
|  |             return str(self.model.objects.get(pk=int(value))) | ||||||
|  |         return "" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class ColorWidget(Widget): | ||||||
|  |     """ | ||||||
|  |     Pulled from django-colorfield. | ||||||
|  |     Select a color. | ||||||
|  |     """ | ||||||
|  |     template_name = 'colorfield/color.html' | ||||||
|  |  | ||||||
|  |     class Media: | ||||||
|  |         js = [ | ||||||
|  |             'colorfield/jscolor/jscolor.min.js', | ||||||
|  |             'colorfield/colorfield.js', | ||||||
|  |         ] | ||||||
|  |  | ||||||
|  |     def format_value(self, value): | ||||||
|  |         if value is None: | ||||||
|  |             value = 0xFFFFFF | ||||||
|  |         return "#{:06X}".format(value) | ||||||
|  |  | ||||||
|  |     def value_from_datadict(self, data, files, name): | ||||||
|  |         val = super().value_from_datadict(data, files, name) | ||||||
|  |         return int(val[1:], 16) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | """ | ||||||
|  | The remaining of this file comes from the project `django-bootstrap-datepicker-plus` available on Github: | ||||||
|  | https://github.com/monim67/django-bootstrap-datepicker-plus | ||||||
|  | This is distributed under Apache License 2.0. | ||||||
|  |  | ||||||
|  | This adds datetime pickers with bootstrap. | ||||||
|  | """ | ||||||
|  |  | ||||||
|  | """Contains Base Date-Picker input class for widgets of this package.""" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class DatePickerDictionary: | ||||||
|  |     """Keeps track of all date-picker input classes.""" | ||||||
|  |  | ||||||
|  |     _i = 0 | ||||||
|  |     items = dict() | ||||||
|  |  | ||||||
|  |     @classmethod | ||||||
|  |     def generate_id(cls): | ||||||
|  |         """Return a unique ID for each date-picker input class.""" | ||||||
|  |         cls._i += 1 | ||||||
|  |         return 'dp_%s' % cls._i | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class BasePickerInput(DateTimeBaseInput): | ||||||
|  |     """Base Date-Picker input class for widgets of this package.""" | ||||||
|  |  | ||||||
|  |     template_name = 'bootstrap_datepicker_plus/date_picker.html' | ||||||
|  |     picker_type = 'DATE' | ||||||
|  |     format = '%Y-%m-%d' | ||||||
|  |     config = {} | ||||||
|  |     _default_config = { | ||||||
|  |         'id': None, | ||||||
|  |         'picker_type': None, | ||||||
|  |         'linked_to': None, | ||||||
|  |         'options': {}  # final merged options | ||||||
|  |     } | ||||||
|  |     options = {}  # options extended by user | ||||||
|  |     options_param = {}  # options passed as parameter | ||||||
|  |     _default_options = { | ||||||
|  |         'showClose': True, | ||||||
|  |         'showClear': True, | ||||||
|  |         'showTodayButton': True, | ||||||
|  |         "locale": "fr", | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     # source: https://github.com/tutorcruncher/django-bootstrap3-datetimepicker | ||||||
|  |     # file: /blob/31fbb09/bootstrap3_datetime/widgets.py#L33 | ||||||
|  |     format_map = ( | ||||||
|  |         ('DDD', r'%j'), | ||||||
|  |         ('DD', r'%d'), | ||||||
|  |         ('MMMM', r'%B'), | ||||||
|  |         ('MMM', r'%b'), | ||||||
|  |         ('MM', r'%m'), | ||||||
|  |         ('YYYY', r'%Y'), | ||||||
|  |         ('YY', r'%y'), | ||||||
|  |         ('HH', r'%H'), | ||||||
|  |         ('hh', r'%I'), | ||||||
|  |         ('mm', r'%M'), | ||||||
|  |         ('ss', r'%S'), | ||||||
|  |         ('a', r'%p'), | ||||||
|  |         ('ZZ', r'%z'), | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     class Media: | ||||||
|  |         """JS/CSS resources needed to render the date-picker calendar.""" | ||||||
|  |  | ||||||
|  |         js = ( | ||||||
|  |             'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.9.0/' | ||||||
|  |             'moment-with-locales.min.js', | ||||||
|  |             'https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/' | ||||||
|  |             '4.17.47/js/bootstrap-datetimepicker.min.js', | ||||||
|  |             'bootstrap_datepicker_plus/js/datepicker-widget.js' | ||||||
|  |         ) | ||||||
|  |         css = {'all': ( | ||||||
|  |             'https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/' | ||||||
|  |             '4.17.47/css/bootstrap-datetimepicker.css', | ||||||
|  |             'bootstrap_datepicker_plus/css/datepicker-widget.css' | ||||||
|  |         ), } | ||||||
|  |  | ||||||
|  |     @classmethod | ||||||
|  |     def format_py2js(cls, datetime_format): | ||||||
|  |         """Convert python datetime format to moment datetime format.""" | ||||||
|  |         for js_format, py_format in cls.format_map: | ||||||
|  |             datetime_format = datetime_format.replace(py_format, js_format) | ||||||
|  |         return datetime_format | ||||||
|  |  | ||||||
|  |     @classmethod | ||||||
|  |     def format_js2py(cls, datetime_format): | ||||||
|  |         """Convert moment datetime format to python datetime format.""" | ||||||
|  |         for js_format, py_format in cls.format_map: | ||||||
|  |             datetime_format = datetime_format.replace(js_format, py_format) | ||||||
|  |         return datetime_format | ||||||
|  |  | ||||||
|  |     def __init__(self, attrs=None, format=None, options=None): | ||||||
|  |         """Initialize the Date-picker widget.""" | ||||||
|  |         self.format_param = format | ||||||
|  |         self.options_param = options if options else {} | ||||||
|  |         self.config = self._default_config.copy() | ||||||
|  |         self.config['id'] = DatePickerDictionary.generate_id() | ||||||
|  |         self.config['picker_type'] = self.picker_type | ||||||
|  |         self.config['options'] = self._calculate_options() | ||||||
|  |         attrs = attrs if attrs else {} | ||||||
|  |         if 'class' not in attrs: | ||||||
|  |             attrs['class'] = 'form-control' | ||||||
|  |         super().__init__(attrs, self._calculate_format()) | ||||||
|  |  | ||||||
|  |     def _calculate_options(self): | ||||||
|  |         """Calculate and Return the options.""" | ||||||
|  |         _options = self._default_options.copy() | ||||||
|  |         _options.update(self.options) | ||||||
|  |         if self.options_param: | ||||||
|  |             _options.update(self.options_param) | ||||||
|  |         return _options | ||||||
|  |  | ||||||
|  |     def _calculate_format(self): | ||||||
|  |         """Calculate and Return the datetime format.""" | ||||||
|  |         _format = self.format_param if self.format_param else self.format | ||||||
|  |         if self.config['options'].get('format'): | ||||||
|  |             _format = self.format_js2py(self.config['options'].get('format')) | ||||||
|  |         else: | ||||||
|  |             self.config['options']['format'] = self.format_py2js(_format) | ||||||
|  |         return _format | ||||||
|  |  | ||||||
|  |     def get_context(self, name, value, attrs): | ||||||
|  |         """Return widget context dictionary.""" | ||||||
|  |         context = super().get_context( | ||||||
|  |             name, value, attrs) | ||||||
|  |         context['widget']['attrs']['dp_config'] = json_dumps(self.config) | ||||||
|  |         return context | ||||||
|  |  | ||||||
|  |     def start_of(self, event_id): | ||||||
|  |         """ | ||||||
|  |         Set Date-Picker as the start-date of a date-range. | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             - event_id (string): User-defined unique id for linking two fields | ||||||
|  |         """ | ||||||
|  |         DatePickerDictionary.items[str(event_id)] = self | ||||||
|  |         return self | ||||||
|  |  | ||||||
|  |     def end_of(self, event_id, import_options=True): | ||||||
|  |         """ | ||||||
|  |         Set Date-Picker as the end-date of a date-range. | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             - event_id (string): User-defined unique id for linking two fields | ||||||
|  |             - import_options (bool): inherit options from start-date input, | ||||||
|  |               default: TRUE | ||||||
|  |         """ | ||||||
|  |         event_id = str(event_id) | ||||||
|  |         if event_id in DatePickerDictionary.items: | ||||||
|  |             linked_picker = DatePickerDictionary.items[event_id] | ||||||
|  |             self.config['linked_to'] = linked_picker.config['id'] | ||||||
|  |             if import_options: | ||||||
|  |                 backup_moment_format = self.config['options']['format'] | ||||||
|  |                 self.config['options'].update(linked_picker.config['options']) | ||||||
|  |                 self.config['options'].update(self.options_param) | ||||||
|  |                 if self.format_param or 'format' in self.options_param: | ||||||
|  |                     self.config['options']['format'] = backup_moment_format | ||||||
|  |                 else: | ||||||
|  |                     self.format = linked_picker.format | ||||||
|  |             # Setting useCurrent is necessary, see following issue | ||||||
|  |             # https://github.com/Eonasdan/bootstrap-datetimepicker/issues/1075 | ||||||
|  |             self.config['options']['useCurrent'] = False | ||||||
|  |             self._link_to(linked_picker) | ||||||
|  |         else: | ||||||
|  |             raise KeyError( | ||||||
|  |                 'start-date not specified for event_id "%s"' % event_id) | ||||||
|  |         return self | ||||||
|  |  | ||||||
|  |     def _link_to(self, linked_picker): | ||||||
|  |         """ | ||||||
|  |         Executed when two date-inputs are linked together. | ||||||
|  |  | ||||||
|  |         This method for sub-classes to override to customize the linking. | ||||||
|  |         """ | ||||||
|  |         pass | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class DatePickerInput(BasePickerInput): | ||||||
|  |     """ | ||||||
|  |     Widget to display a Date-Picker Calendar on a DateField property. | ||||||
|  |  | ||||||
|  |     Args: | ||||||
|  |         - attrs (dict): HTML attributes of rendered HTML input | ||||||
|  |         - format (string): Python DateTime format eg. "%Y-%m-%d" | ||||||
|  |         - options (dict): Options to customize the widget, see README | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     picker_type = 'DATE' | ||||||
|  |     format = '%Y-%m-%d' | ||||||
|  |     format_key = 'DATE_INPUT_FORMATS' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class TimePickerInput(BasePickerInput): | ||||||
|  |     """ | ||||||
|  |     Widget to display a Time-Picker Calendar on a TimeField property. | ||||||
|  |  | ||||||
|  |     Args: | ||||||
|  |         - attrs (dict): HTML attributes of rendered HTML input | ||||||
|  |         - format (string): Python DateTime format eg. "%Y-%m-%d" | ||||||
|  |         - options (dict): Options to customize the widget, see README | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     picker_type = 'TIME' | ||||||
|  |     format = '%H:%M' | ||||||
|  |     format_key = 'TIME_INPUT_FORMATS' | ||||||
|  |     template_name = 'bootstrap_datepicker_plus/time_picker.html' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class DateTimePickerInput(BasePickerInput): | ||||||
|  |     """ | ||||||
|  |     Widget to display a DateTime-Picker Calendar on a DateTimeField property. | ||||||
|  |  | ||||||
|  |     Args: | ||||||
|  |         - attrs (dict): HTML attributes of rendered HTML input | ||||||
|  |         - format (string): Python DateTime format eg. "%Y-%m-%d" | ||||||
|  |         - options (dict): Options to customize the widget, see README | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     picker_type = 'DATETIME' | ||||||
|  |     format = '%Y-%m-%d %H:%M' | ||||||
|  |     format_key = 'DATETIME_INPUT_FORMATS' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class MonthPickerInput(BasePickerInput): | ||||||
|  |     """ | ||||||
|  |     Widget to display a Month-Picker Calendar on a DateField property. | ||||||
|  |  | ||||||
|  |     Args: | ||||||
|  |         - attrs (dict): HTML attributes of rendered HTML input | ||||||
|  |         - format (string): Python DateTime format eg. "%Y-%m-%d" | ||||||
|  |         - options (dict): Options to customize the widget, see README | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     picker_type = 'MONTH' | ||||||
|  |     format = '01/%m/%Y' | ||||||
|  |     format_key = 'DATE_INPUT_FORMATS' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class YearPickerInput(BasePickerInput): | ||||||
|  |     """ | ||||||
|  |     Widget to display a Year-Picker Calendar on a DateField property. | ||||||
|  |  | ||||||
|  |     Args: | ||||||
|  |         - attrs (dict): HTML attributes of rendered HTML input | ||||||
|  |         - format (string): Python DateTime format eg. "%Y-%m-%d" | ||||||
|  |         - options (dict): Options to customize the widget, see README | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     picker_type = 'YEAR' | ||||||
|  |     format = '01/01/%Y' | ||||||
|  |     format_key = 'DATE_INPUT_FORMATS' | ||||||
|  |  | ||||||
|  |     def _link_to(self, linked_picker): | ||||||
|  |         """Customize the options when linked with other date-time input""" | ||||||
|  |         yformat = self.config['options']['format'].replace('-01-01', '-12-31') | ||||||
|  |         self.config['options']['format'] = yformat | ||||||
							
								
								
									
										93
									
								
								corres2math/middlewares.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								corres2math/middlewares.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,93 @@ | |||||||
|  | from django.conf import settings | ||||||
|  | from django.contrib.auth.models import AnonymousUser, User | ||||||
|  |  | ||||||
|  | from threading import local | ||||||
|  |  | ||||||
|  | from django.contrib.sessions.backends.db import SessionStore | ||||||
|  |  | ||||||
|  | USER_ATTR_NAME = getattr(settings, 'LOCAL_USER_ATTR_NAME', '_current_user') | ||||||
|  | SESSION_ATTR_NAME = getattr(settings, 'LOCAL_SESSION_ATTR_NAME', '_current_session') | ||||||
|  | IP_ATTR_NAME = getattr(settings, 'LOCAL_IP_ATTR_NAME', '_current_ip') | ||||||
|  |  | ||||||
|  | _thread_locals = local() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def _set_current_user_and_ip(user=None, session=None, ip=None): | ||||||
|  |     setattr(_thread_locals, USER_ATTR_NAME, user) | ||||||
|  |     setattr(_thread_locals, SESSION_ATTR_NAME, session) | ||||||
|  |     setattr(_thread_locals, IP_ATTR_NAME, ip) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def get_current_user() -> 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 | ||||||
							
								
								
									
										202
									
								
								corres2math/settings.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								corres2math/settings.py
									
									
									
									
									
										Normal file
									
								
							| @@ -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 * | ||||||
							
								
								
									
										5
									
								
								corres2math/settings_dev.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								corres2math/settings_dev.py
									
									
									
									
									
										Normal file
									
								
							| @@ -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' | ||||||
							
								
								
									
										30
									
								
								corres2math/settings_prod.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								corres2math/settings_prod.py
									
									
									
									
									
										Normal file
									
								
							| @@ -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 <contact@correspondances-maths.fr>') | ||||||
|  | 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 | ||||||
							
								
								
									
										
											BIN
										
									
								
								corres2math/static/favicon.ico
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								corres2math/static/favicon.ico
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 7.1 KiB | 
| Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB | 
							
								
								
									
										35
									
								
								corres2math/urls.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								corres2math/urls.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | |||||||
|  | """corres2math URL Configuration | ||||||
|  |  | ||||||
|  | The `urlpatterns` list routes URLs to views. For more information please see: | ||||||
|  |     https://docs.djangoproject.com/en/3.0/topics/http/urls/ | ||||||
|  | Examples: | ||||||
|  | Function views | ||||||
|  |     1. Add an import:  from my_app import views | ||||||
|  |     2. Add a URL to urlpatterns:  path('', views.home, name='home') | ||||||
|  | Class-based views | ||||||
|  |     1. Add an import:  from other_app.views import Home | ||||||
|  |     2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home') | ||||||
|  | Including another URLconf | ||||||
|  |     1. Import the include() function: from django.urls import include, path | ||||||
|  |     2. Add a URL to urlpatterns:  path('blog/', include('blog.urls')) | ||||||
|  | """ | ||||||
|  |  | ||||||
|  | from django.contrib import admin | ||||||
|  | from django.urls import path, include | ||||||
|  | from django.views.defaults import bad_request, permission_denied, page_not_found, server_error | ||||||
|  | from django.views.generic import TemplateView | ||||||
|  |  | ||||||
|  | urlpatterns = [ | ||||||
|  |     path('', TemplateView.as_view(template_name="index.html"), name='index'), | ||||||
|  |     path('i18n/', include('django.conf.urls.i18n')), | ||||||
|  |     path('admin/doc/', include('django.contrib.admindocs.urls')), | ||||||
|  |     path('admin/', admin.site.urls, name="admin"), | ||||||
|  |     path('accounts/', include('django.contrib.auth.urls')), | ||||||
|  |  | ||||||
|  |     path('api/', include('api.urls')), | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | handler400 = bad_request | ||||||
|  | handler403 = permission_denied | ||||||
|  | handler404 = page_not_found | ||||||
|  | handler500 = server_error | ||||||
							
								
								
									
										16
									
								
								corres2math/wsgi.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								corres2math/wsgi.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | """ | ||||||
|  | WSGI config for corres2math project. | ||||||
|  |  | ||||||
|  | It exposes the WSGI callable as a module-level variable named ``application``. | ||||||
|  |  | ||||||
|  | For more information on this file, see | ||||||
|  | https://docs.djangoproject.com/en/3.0/howto/deployment/wsgi/ | ||||||
|  | """ | ||||||
|  |  | ||||||
|  | import os | ||||||
|  |  | ||||||
|  | from django.core.wsgi import get_wsgi_application | ||||||
|  |  | ||||||
|  | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'corres2math.settings') | ||||||
|  |  | ||||||
|  | application = get_wsgi_application() | ||||||
| @@ -1,95 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| require_once "server_files/config.php"; |  | ||||||
|  |  | ||||||
| require_once "server_files/classes/Document.php"; |  | ||||||
| require_once "server_files/classes/Phase.php"; |  | ||||||
| require_once "server_files/classes/Question.php"; |  | ||||||
| require_once "server_files/classes/Reason.php"; |  | ||||||
| require_once "server_files/classes/Role.php"; |  | ||||||
| require_once "server_files/classes/SchoolClass.php"; |  | ||||||
| require_once "server_files/classes/Team.php"; |  | ||||||
| require_once "server_files/classes/User.php"; |  | ||||||
| require_once "server_files/classes/ValidationStatus.php"; |  | ||||||
| require_once "server_files/classes/Video.php"; |  | ||||||
| require_once "server_files/services/mail.php"; |  | ||||||
| require_once "server_files/utils.php"; |  | ||||||
| require_once "server_files/model.php"; |  | ||||||
|  |  | ||||||
| loadUserValues(); |  | ||||||
|  |  | ||||||
| if (!isset($_GET["path"])) |  | ||||||
| 	require_once "server_files/403.php"; |  | ||||||
|  |  | ||||||
| $path = $_GET["path"]; |  | ||||||
|  |  | ||||||
| $ROUTES = []; |  | ||||||
|  |  | ||||||
| # URL paths |  | ||||||
|  |  | ||||||
| $ROUTES["^(|accueil|index|accueil\.php|accueil\.html|accueil\.py|index\.php|index\.html|index\.py)/?$"] = ["server_files/controllers/index.php"]; |  | ||||||
| $ROUTES["^(modifier-page)$"] = ["server_files/controllers/index.php", "edit"]; |  | ||||||
| $ROUTES["^admins$"] = ["server_files/controllers/admins.php"]; |  | ||||||
| $ROUTES["^ajouter-equipe$"] = ["server_files/controllers/ajouter_equipe.php"]; |  | ||||||
| $ROUTES["^ajouter-admin$"] = ["server_files/controllers/ajouter_admin.php"]; |  | ||||||
| $ROUTES["^calendrier/(modifier)$"] = ["server_files/controllers/calendrier.php", "edit"]; |  | ||||||
| $ROUTES["^calendrier/?$"] = ["server_files/controllers/calendrier.php"]; |  | ||||||
| $ROUTES["^commenter-echange-4$"] = ["server_files/controllers/commenter_echange.php"]; |  | ||||||
| $ROUTES["^commenter-echange-4/([A-Z]{3})$"] = ["server_files/controllers/commenter_echange.php", "trigram"]; |  | ||||||
| $ROUTES["^confirmer-mail/([a-z0-9]*)/?$"] = ["server_files/controllers/confirmer_mail.php", "token"]; |  | ||||||
| $ROUTES["^connexion/(confirmation-mail)/?$"] = ["server_files/controllers/connexion.php", "confirmation-mail"]; |  | ||||||
| $ROUTES["^connexion/(mdp-oublie)/?$"] = ["server_files/controllers/connexion.php", "mdp_oublie"]; |  | ||||||
| $ROUTES["^connexion/(reinitialiser_mdp)/(.*)/?$"] = ["server_files/controllers/connexion.php", "reset_password", "token"]; |  | ||||||
| $ROUTES["^connexion/?$"] = ["server_files/controllers/connexion.php"]; |  | ||||||
| $ROUTES["^deconnexion/?$"] = ["server_files/controllers/deconnexion.php"]; |  | ||||||
| $ROUTES["^envoyer-video-1$"] = ["server_files/controllers/envoyer_video.php"]; |  | ||||||
| $ROUTES["^envoyer-video-1/([A-Z]{3})$"] = ["server_files/controllers/envoyer_video.php", "trigram"]; |  | ||||||
| $ROUTES["^equipe/([A-Z]{3})/?$"] = ["server_files/controllers/equipe.php", "trigram"]; |  | ||||||
| $ROUTES["^exporter-donnees/?$"] = ["server_files/controllers/exporter_donnees.php"]; |  | ||||||
| $ROUTES["^file/([a-z0-9]{64})/?$"] = ["server_files/controllers/view_file.php", "file_id"]; |  | ||||||
| $ROUTES["^informations/([0-9]*)/.*?$"] = ["server_files/controllers/informations.php", "id"]; |  | ||||||
| $ROUTES["^inscription/?$"] = ["server_files/controllers/inscription.php"]; |  | ||||||
| $ROUTES["^mon-compte/?$"] = ["server_files/controllers/mon_compte.php"]; |  | ||||||
| $ROUTES["^mon-equipe/(diffusion-videos)/?$"] = ["server_files/controllers/mon_equipe.php", "publish_videos"]; |  | ||||||
| $ROUTES["^mon-equipe/(modifier)/?$"] = ["server_files/controllers/mon_equipe.php", "modifier"]; |  | ||||||
| $ROUTES["^mon-equipe/?$"] = ["server_files/controllers/mon_equipe.php"]; |  | ||||||
| $ROUTES["^mon-equipe/([A-Z]{3})/?$"] = ["server_files/controllers/mon_equipe.php", "trigram"]; |  | ||||||
| $ROUTES["^ma-participation/?$"] = ["server_files/controllers/ma_participation.php"]; |  | ||||||
| $ROUTES["^ma-participation/([A-Z]{3})/?$"] = ["server_files/controllers/ma_participation.php", "trigram"]; |  | ||||||
| $ROUTES["^poser-questions-2$"] = ["server_files/controllers/poser_questions.php"]; |  | ||||||
| $ROUTES["^poser-questions-2/([A-Z]{3})$"] = ["server_files/controllers/poser_questions.php", "trigram"]; |  | ||||||
| $ROUTES["^probleme/([0-4])/?$"] = ["server_files/controllers/probleme.php", "probleme"]; |  | ||||||
| $ROUTES["^profils/?$"] = ["server_files/controllers/profiles.php"]; |  | ||||||
| $ROUTES["^profils-(orphelins)/?$"] = ["server_files/controllers/profiles.php", "orphans"]; |  | ||||||
| $ROUTES["^rejoindre-equipe/?$"] = ["server_files/controllers/rejoindre_equipe.php"]; |  | ||||||
| $ROUTES["^repondre-questions-3$"] = ["server_files/controllers/repondre_questions.php"]; |  | ||||||
| $ROUTES["^repondre-questions-3/([A-Z]{3})$"] = ["server_files/controllers/repondre_questions.php", "trigram"]; |  | ||||||
| $ROUTES["^suivi-correspondances/?$"] = ["server_files/controllers/suivi_correspondances.php"]; |  | ||||||
| $ROUTES["^suivi-correspondances/([1-4])/?$"] = ["server_files/controllers/suivi_correspondances.php", "problem"]; |  | ||||||
|  |  | ||||||
| # Assets files |  | ||||||
|  |  | ||||||
| $ROUTES["^Autorisation de droit à l'image - majeur.pdf$"] = ["assets/Autorisation de droit à l'image - majeur.pdf", "application/pdf"]; |  | ||||||
| $ROUTES["^Autorisation de droit à l'image - mineur.pdf$"] = ["assets/Autorisation de droit à l'image - mineur.pdf", "application/pdf"]; |  | ||||||
| $ROUTES["^favicon\.ico$"] = ["assets/favicon.ico", "image/x-icon"]; |  | ||||||
| $ROUTES["^logo\.png"] = ["assets/logo.png", "image/png"]; |  | ||||||
| $ROUTES["^style\.css$"] = ["assets/style.css", "text/css"]; |  | ||||||
|  |  | ||||||
| foreach ($ROUTES as $route => $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"; |  | ||||||
							
								
								
									
										12
									
								
								entrypoint.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										12
									
								
								entrypoint.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -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 | ||||||
							
								
								
									
										270
									
								
								locale/fr/LC_MESSAGES/django.po
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										270
									
								
								locale/fr/LC_MESSAGES/django.po
									
									
									
									
									
										Normal file
									
								
							| @@ -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 <EMAIL@ADDRESS>, 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 <yohann.danello@animath.fr>\n" | ||||||
|  | "Language-Team: LANGUAGE <LL@li.org>\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 <code>%(request_path)s</code> was not found on the server." | ||||||
|  | msgstr "" | ||||||
|  | "Le chemin demandé <code>%(request_path)s</code> 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 <a href=\"%(login_url)s\">log in</a>." | ||||||
|  | msgstr "Vous pouvez désormais vous <a href=\"%(login_url)s\">connecter</a>." | ||||||
|  |  | ||||||
|  | #: 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" | ||||||
							
								
								
									
										21
									
								
								manage.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										21
									
								
								manage.py
									
									
									
									
									
										Executable file
									
								
							| @@ -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() | ||||||
							
								
								
									
										19
									
								
								nginx_corres2math.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								nginx_corres2math.conf
									
									
									
									
									
										Normal file
									
								
							| @@ -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/; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										15
									
								
								requirements.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								requirements.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||||
| @@ -1,16 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| require_once "config.php"; |  | ||||||
| require_once "views/header.php"; |  | ||||||
|  |  | ||||||
| http_response_code(403); |  | ||||||
| ?> |  | ||||||
|  |  | ||||||
|     <div class="alert alert-danger mt-4 mb-4"> |  | ||||||
|         <h2 class="display-5"> |  | ||||||
|             Vous n'êtes pas autorisé à accéder à cette page. |  | ||||||
|         </h2> |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
| <?php |  | ||||||
| require_once "views/footer.php"; |  | ||||||
| @@ -1,16 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| require_once "config.php"; |  | ||||||
| require_once "views/header.php"; |  | ||||||
|  |  | ||||||
| http_response_code(404); |  | ||||||
| ?> |  | ||||||
|  |  | ||||||
|     <div class="alert alert-danger mt-4 mb-4"> |  | ||||||
|         <h2 class="display-5"> |  | ||||||
|             Cette page n'existe pas. |  | ||||||
|         </h2> |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
| <?php |  | ||||||
| require_once "views/footer.php"; |  | ||||||
| @@ -1,91 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| class Document |  | ||||||
| { |  | ||||||
| 	private $file_id; |  | ||||||
| 	private $user_id; |  | ||||||
| 	private $team_id; |  | ||||||
| 	private $problem; |  | ||||||
| 	private $uploaded_at; |  | ||||||
| 	private $version; |  | ||||||
|  |  | ||||||
| 	private function __construct() {} |  | ||||||
|  |  | ||||||
| 	public static function fromId($id) |  | ||||||
| 	{ |  | ||||||
| 		global $DB; |  | ||||||
| 		$req = $DB->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; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,68 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| class Phase |  | ||||||
| { |  | ||||||
| 	const INSCRIPTION = 0; |  | ||||||
| 	const PHASE1 = 1; |  | ||||||
| 	const PHASE12 = 2; |  | ||||||
| 	const PHASE2 = 3; |  | ||||||
| 	const PHASE23 = 4; |  | ||||||
| 	const PHASE3 = 5; |  | ||||||
| 	const PHASE34 = 6; |  | ||||||
| 	const PHASE4 = 7; |  | ||||||
| 	const END = 8; |  | ||||||
|  |  | ||||||
| 	public static function getCurrentPhase() |  | ||||||
| 	{ |  | ||||||
| 		global $CONFIG; |  | ||||||
|  |  | ||||||
| 		$date = date("Y-m-d H:i:s"); |  | ||||||
|  |  | ||||||
| 		if ($date < $CONFIG->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"; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,185 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class Question |  | ||||||
| { |  | ||||||
| 	const DEFAULT_QUESTIONS = ["Comment avez-vous obtenu vos résultats ?", |  | ||||||
| 				"Peut-on rendre votre algorithme plus efficace ? Pourquoi ?", |  | ||||||
| 				"Comment élargir vos travaux ?", |  | ||||||
| 				null, |  | ||||||
| 				null, |  | ||||||
| 				null]; |  | ||||||
|  |  | ||||||
| 	private $id; |  | ||||||
| 	private $from; |  | ||||||
| 	private $to; |  | ||||||
| 	private $problem; |  | ||||||
| 	private $number; |  | ||||||
| 	private $question; |  | ||||||
| 	private $attached_file; |  | ||||||
| 	private $answer; |  | ||||||
| 	private $attached_file_answer; |  | ||||||
|  |  | ||||||
| 	private function __construct() |  | ||||||
| 	{ |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	public static function fromId($id) |  | ||||||
| 	{ |  | ||||||
| 		global $DB; |  | ||||||
|  |  | ||||||
| 		$req = $DB->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]); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,41 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class Reason |  | ||||||
| { |  | ||||||
| 	const SOLUTION = 0; |  | ||||||
| 	const ANSWER1 = 1; |  | ||||||
| 	const ANSWER2 = 2; |  | ||||||
|  |  | ||||||
| 	public static function getTranslatedName($class) { |  | ||||||
| 		switch ($class) { |  | ||||||
| 			case self::ANSWER1: |  | ||||||
| 			case self::ANSWER2: |  | ||||||
| 				return "Réponse"; |  | ||||||
| 			default: |  | ||||||
| 				return "Solution"; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	public static function getName($class) { |  | ||||||
| 		switch ($class) { |  | ||||||
| 			case self::ANSWER1: |  | ||||||
| 				return "ANSWER1"; |  | ||||||
| 			case self::ANSWER2: |  | ||||||
| 				return "ANSWER2"; |  | ||||||
| 			default: |  | ||||||
| 				return "SOLUTION"; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	public static function fromName($name) { |  | ||||||
| 		switch ($name) { |  | ||||||
| 			case "ANSWER1": |  | ||||||
| 				return self::ANSWER1; |  | ||||||
| 			case "ANSWER2": |  | ||||||
| 				return self::ANSWER2; |  | ||||||
| 			default: |  | ||||||
| 				return self::SOLUTION; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,41 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| class Role |  | ||||||
| { |  | ||||||
|     const PARTICIPANT = 0; |  | ||||||
|     const ENCADRANT = 1; |  | ||||||
|     const ADMIN = 2; |  | ||||||
|  |  | ||||||
| 	public static function getTranslatedName($role) { |  | ||||||
| 		switch ($role) { |  | ||||||
| 			case self::ENCADRANT: |  | ||||||
| 				return "Encadrant"; |  | ||||||
| 			case self::ADMIN: |  | ||||||
| 				return "Administrateur"; |  | ||||||
| 			default: |  | ||||||
| 				return "Participant"; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	public static function getName($role) { |  | ||||||
| 		switch ($role) { |  | ||||||
| 			case self::ENCADRANT: |  | ||||||
| 				return "ENCADRANT"; |  | ||||||
| 			case self::ADMIN: |  | ||||||
| 				return "ADMIN"; |  | ||||||
| 			default: |  | ||||||
| 				return "PARTICIPANT"; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|     public static function fromName($name) { |  | ||||||
|         switch ($name) { |  | ||||||
|             case "ENCADRANT": |  | ||||||
|                 return self::ENCADRANT; |  | ||||||
|             case "ADMIN": |  | ||||||
|                 return self::ADMIN; |  | ||||||
|             default: |  | ||||||
|                 return self::PARTICIPANT; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,54 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| class SchoolClass |  | ||||||
| { |  | ||||||
| 	const SECONDE = 0; |  | ||||||
| 	const PREMIERE = 1; |  | ||||||
| 	const TERMINALE = 2; |  | ||||||
| 	const ADULT = 3; |  | ||||||
|  |  | ||||||
| 	public static function getTranslatedName($class) { |  | ||||||
| 		switch ($class) { |  | ||||||
| 			case self::SECONDE: |  | ||||||
| 				return "Seconde ou inférieur"; |  | ||||||
| 			case self::PREMIERE: |  | ||||||
| 				return "Première"; |  | ||||||
|             case self::TERMINALE: |  | ||||||
| 				return "Terminale"; |  | ||||||
|             case self::ADULT: |  | ||||||
|                 return "Adulte"; |  | ||||||
|             default: |  | ||||||
|                 return null; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	public static function getName($class) { |  | ||||||
| 		switch ($class) { |  | ||||||
| 			case self::SECONDE: |  | ||||||
| 				return "SECONDE"; |  | ||||||
| 			case self::PREMIERE: |  | ||||||
| 				return "PREMIERE"; |  | ||||||
|             case self::TERMINALE: |  | ||||||
| 				return "TERMINALE"; |  | ||||||
|             case self::ADULT: |  | ||||||
|                 return "ADULT"; |  | ||||||
|             default: |  | ||||||
|                 return null; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	public static function fromName($name) { |  | ||||||
| 		switch ($name) { |  | ||||||
| 			case "SECONDE": |  | ||||||
| 				return self::SECONDE; |  | ||||||
| 			case "PREMIERE": |  | ||||||
| 				return self::PREMIERE; |  | ||||||
| 			case "TERMINALE": |  | ||||||
| 				return self::TERMINALE; |  | ||||||
|             case "ADULT": |  | ||||||
|                 return self::ADULT; |  | ||||||
|             default: |  | ||||||
|                 return null; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,261 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| class Team |  | ||||||
| { |  | ||||||
| 	private $id; |  | ||||||
| 	private $name; |  | ||||||
| 	private $trigram; |  | ||||||
| 	private $problem; |  | ||||||
| 	private $encadrant; |  | ||||||
| 	private $participants; |  | ||||||
| 	private $inscription_date; |  | ||||||
| 	private $allow_publish; |  | ||||||
| 	private $validation_status; |  | ||||||
| 	private $video_team_ids; |  | ||||||
| 	private $access_code; |  | ||||||
| 	private $year; |  | ||||||
|  |  | ||||||
| 	private function __construct() {} |  | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * @param $id |  | ||||||
| 	 * @return Team|null |  | ||||||
| 	 */ |  | ||||||
| 	public static function fromId($id) |  | ||||||
| 	{ |  | ||||||
| 		global $DB; |  | ||||||
| 		$req = $DB->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; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,335 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| class User |  | ||||||
| { |  | ||||||
| 	private $id; |  | ||||||
| 	public $email; |  | ||||||
| 	private $pwd_hash; |  | ||||||
| 	public $surname; |  | ||||||
| 	public $first_name; |  | ||||||
| 	public $school; |  | ||||||
| 	public $city; |  | ||||||
| 	public $country; |  | ||||||
| 	public $class; |  | ||||||
| 	public $description; |  | ||||||
| 	private $role; |  | ||||||
| 	private $team_id; |  | ||||||
| 	private $year; |  | ||||||
| 	private $confirm_email; |  | ||||||
| 	private $forgotten_password; |  | ||||||
| 	private $inscription_date; |  | ||||||
| 	private $receive_animath_mails; |  | ||||||
| 	 |  | ||||||
| 	private function __construct() {} |  | ||||||
|  |  | ||||||
| 	public static function fromId($id) |  | ||||||
| 	{ |  | ||||||
| 		global $DB; |  | ||||||
| 		$req = $DB->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; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,41 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| class ValidationStatus |  | ||||||
| { |  | ||||||
|     const NOT_READY = 0; |  | ||||||
|     const WAITING = 1; |  | ||||||
|     const VALIDATED = 2; |  | ||||||
|  |  | ||||||
|     public static function getTranslatedName($status) { |  | ||||||
|         switch ($status) { |  | ||||||
|             case self::WAITING: |  | ||||||
|                 return "En attente de validation"; |  | ||||||
|             case self::VALIDATED: |  | ||||||
|                 return "Inscription validée"; |  | ||||||
|             default: |  | ||||||
|                 return "Inscription non terminée"; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public static function getName($status) { |  | ||||||
| 		switch ($status) { |  | ||||||
| 			case self::WAITING: |  | ||||||
| 				return "WAITING"; |  | ||||||
| 			case self::VALIDATED: |  | ||||||
| 				return "VALIDATED"; |  | ||||||
| 			default: |  | ||||||
| 				return "NOT_READY"; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|     public static function fromName($name) { |  | ||||||
|         switch ($name) { |  | ||||||
|             case "WAITING": |  | ||||||
|                 return self::WAITING; |  | ||||||
|             case "VALIDATED": |  | ||||||
|                 return self::VALIDATED; |  | ||||||
|             default: |  | ||||||
|                 return self::NOT_READY; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,132 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class Video |  | ||||||
| { |  | ||||||
| 	const NOT_CONTROLLED = 0; |  | ||||||
| 	const REJECTED = -1; |  | ||||||
| 	const ACCEPTED = 1; |  | ||||||
|  |  | ||||||
| 	private $id; |  | ||||||
| 	private $team; |  | ||||||
| 	private $problem; |  | ||||||
| 	private $link; |  | ||||||
| 	private $reason; |  | ||||||
| 	private $validation; |  | ||||||
| 	private $uploaded_at; |  | ||||||
| 	private $year; |  | ||||||
| 	private $version; |  | ||||||
|  |  | ||||||
| 	private function __construct() {} |  | ||||||
|  |  | ||||||
| 	public static function fromId($id) |  | ||||||
| 	{ |  | ||||||
| 		global $DB; |  | ||||||
| 		$req = $DB->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; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,227 +0,0 @@ | |||||||
| <?php |  | ||||||
| /** |  | ||||||
|  * Config options |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| $YEAR = getenv("CORRES2MATH_YEAR"); |  | ||||||
| $URL_BASE = getenv("CORRES2MATH_URL_BASE"); |  | ||||||
| $LOCAL_PATH = getenv("CORRES2MATH_LOCAL_PATH"); |  | ||||||
| $MAIL_DOMAIN = getenv("CORRES2MATH_MAIL_DOMAIN"); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
| * DB infos |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| $DB_HOST = getenv("CORRES2MATH_DB_HOST"); |  | ||||||
| $DB_NAME = getenv("CORRES2MATH_DB_NAME"); |  | ||||||
| $DB_USER = getenv("CORRES2MATH_DB_USER"); |  | ||||||
| $DB_PASSWORD = getenv("CORRES2MATH_DB_PASSWORD"); |  | ||||||
|  |  | ||||||
| try { |  | ||||||
| 	$DB = new PDO("mysql:host=$DB_HOST;dbname=$DB_NAME;charset=utf8", "$DB_USER", "$DB_PASSWORD", array(PDO::ATTR_ERRMODE => 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"); |  | ||||||
| @@ -1,8 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| if ($_SESSION["role"] != Role::ADMIN) |  | ||||||
|     require_once "server_files/403.php"; |  | ||||||
|  |  | ||||||
| $admins = User::getAdmins(); |  | ||||||
|  |  | ||||||
| require_once "server_files/views/admins.php"; |  | ||||||
| @@ -1,56 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| if (!isset($_SESSION["role"]) || $_SESSION["role"] != Role::ADMIN) |  | ||||||
|     require_once "server_files/403.php"; |  | ||||||
|  |  | ||||||
| $has_error = false; |  | ||||||
| $error_message = null; |  | ||||||
|  |  | ||||||
| if (isset($_POST["add_admin"])) { |  | ||||||
| 	$admin = new NewAdmin($_POST); |  | ||||||
| 	try { |  | ||||||
| 		$admin->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"; |  | ||||||
| @@ -1,75 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| if (!isset($_SESSION["role"]) || ($_SESSION["role"] != Role::PARTICIPANT && $_SESSION["role"] != Role::ENCADRANT)) |  | ||||||
| 	require_once "server_files/403.php"; |  | ||||||
|  |  | ||||||
| $has_error = false; |  | ||||||
| $error_message = null; |  | ||||||
|  |  | ||||||
| if (isset($_POST["add_team"])) { |  | ||||||
|     $new_team = new NewTeam($_POST); |  | ||||||
|     try { |  | ||||||
|     	$new_team->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"; |  | ||||||
| @@ -1,76 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| $has_error = false; |  | ||||||
| $error_message = null; |  | ||||||
|  |  | ||||||
| if (isset($_GET["edit"]) && isset($_POST["update_calendar"])) { |  | ||||||
| 	$update_calendar = new UpdateCalendar($_POST); |  | ||||||
| 	try { |  | ||||||
| 		$update_calendar->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"; |  | ||||||
| @@ -1,77 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| if (!isset($_SESSION["user_id"]) || $_SESSION["role"] != Role::PARTICIPANT && $_SESSION["role"] != Role::ENCADRANT || Phase::getCurrentPhase() != Phase::PHASE4) |  | ||||||
| 	require_once "server_files/403.php"; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * @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() || $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"; |  | ||||||
| @@ -1,25 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| $token = $_GET["token"]; |  | ||||||
|  |  | ||||||
| $has_error = false; |  | ||||||
|  |  | ||||||
| if (isset($token)) { |  | ||||||
|     $result = $DB->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 "<div class=\"alert alert-success\">$error_message</div>"; |  | ||||||
| require_once "server_files/views/footer.php"; |  | ||||||
| @@ -1,170 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| $has_error = false; |  | ||||||
| $error_message = null; |  | ||||||
|  |  | ||||||
| if (isset($_POST["login"]) && !isset($_SESSION["user_id"])) { |  | ||||||
| 	$logging_in_user = new LoggingInUser($_POST); |  | ||||||
| 	try { |  | ||||||
| 		$logging_in_user->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). " |  | ||||||
| 				. "<a href=\"/connexion/confirmation-mail\">Cliquez ici pour renvoyer le mail de confirmation</a>."); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	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"; |  | ||||||
| @@ -1,14 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| unset($_SESSION["user_id"]); |  | ||||||
| session_destroy(); |  | ||||||
|  |  | ||||||
| require_once "server_files/views/header.php"; |  | ||||||
| ?> |  | ||||||
|  |  | ||||||
| <div class="alert alert-success"> |  | ||||||
| 	Déconnexion réussie ! |  | ||||||
| </div> |  | ||||||
|  |  | ||||||
| <?php |  | ||||||
| require_once "server_files/views/footer.php"; |  | ||||||
| @@ -1,72 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| if (!isset($_SESSION["user_id"]) || $_SESSION["role"] != Role::PARTICIPANT && $_SESSION["role"] != Role::ENCADRANT) |  | ||||||
| 	require_once "server_files/403.php"; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * @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() || $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"; |  | ||||||
| @@ -1,112 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| if (!isset($_SESSION["user_id"]) || $_SESSION["role"] != Role::ADMIN) |  | ||||||
| 	require_once "server_files/403.php"; |  | ||||||
|  |  | ||||||
| $trigram = htmlspecialchars($_GET["trigram"]); |  | ||||||
|  |  | ||||||
| $team = Team::fromTrigram($trigram); |  | ||||||
|  |  | ||||||
| if ($team === null) |  | ||||||
| 	require_once "server_files/404.php"; |  | ||||||
|  |  | ||||||
| if (isset($_POST["validate"])) { |  | ||||||
|     $team->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"; |  | ||||||
| @@ -1,42 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| if (!isset($_SESSION["user_id"]) || $_SESSION["role"] != Role::ADMIN) |  | ||||||
|     require_once "server_files/403.php"; |  | ||||||
|  |  | ||||||
| if (isset($_POST["export_user_data"])) { |  | ||||||
|     $file_name = exportUserData(); |  | ||||||
|  |  | ||||||
|     header("Content-Type: text/csv"); |  | ||||||
|     header("Content-Disposition: inline; filename=\"Données utilisateurs.csv\""); |  | ||||||
|     header("Content-Length: " . strval(filesize($file_name))); |  | ||||||
|  |  | ||||||
|     readfile($file_name); |  | ||||||
|  |  | ||||||
|     exit(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| if (isset($_POST["export_team_data"])) { |  | ||||||
|     $file_name = exportTeamData(); |  | ||||||
|  |  | ||||||
|     header("Content-Type: text/csv"); |  | ||||||
|     header("Content-Disposition: attachment; filename=\"Données équipes.csv\""); |  | ||||||
|     header("Content-Length: " . strval(filesize($file_name))); |  | ||||||
|  |  | ||||||
|     readfile($file_name); |  | ||||||
|  |  | ||||||
|     exit(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| if (isset($_POST["export_problems_data"])) { |  | ||||||
|     $file_name = exportProblemsData(); |  | ||||||
|  |  | ||||||
|     header("Content-Type: text/csv"); |  | ||||||
|     header("Content-Disposition: attachment; filename=\"Données problèmes.csv\""); |  | ||||||
|     header("Content-Length: " . strval(filesize($file_name))); |  | ||||||
|  |  | ||||||
|     readfile($file_name); |  | ||||||
|  |  | ||||||
|     exit(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| require_once "server_files/views/exporter_donnees.php"; |  | ||||||
| @@ -1,16 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| if (isset($_GET["edit"])) { |  | ||||||
|     if (!isset($_SESSION["user_id"]) || $_SESSION["role"] != Role::ADMIN) |  | ||||||
|         require_once "server_files/403.php"; |  | ||||||
|  |  | ||||||
|     if (isset($_POST["edit_page"])) { |  | ||||||
|         $content = $_POST["content"]; |  | ||||||
|  |  | ||||||
|         $CONFIG->setIndexPage(htmlspecialchars($content)); |  | ||||||
|         header("Location: /"); |  | ||||||
|         exit(0); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| require_once "server_files/views/index.php"; |  | ||||||
| @@ -1,117 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| if (!isset($_SESSION["role"])) |  | ||||||
| 	require_once "server_files/403.php"; |  | ||||||
|  |  | ||||||
| $id = $_GET["id"]; |  | ||||||
| $user = User::fromId($id); |  | ||||||
|  |  | ||||||
| if ($_SESSION["role"] != Role::ADMIN) { |  | ||||||
| 	if ($user->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"; |  | ||||||
| @@ -1,84 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| $has_error = false; |  | ||||||
| $error_message = null; |  | ||||||
|  |  | ||||||
| if (isset($_POST["register"])) { |  | ||||||
| 	$user = new NewUser($_POST); |  | ||||||
|  |  | ||||||
| 	try { |  | ||||||
| 		$user->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"; |  | ||||||
| @@ -1,23 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| if (isset($_SESSION["user_id"]) && isset($_SESSION["teams"]) && sizeof($_SESSION["teams"]) > 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"; |  | ||||||
| @@ -1,177 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| if (!isset($_SESSION["user_id"])) |  | ||||||
| 	require_once "server_files/403.php"; |  | ||||||
|  |  | ||||||
| /** @var User $user */ |  | ||||||
| $user = $_SESSION["user"]; |  | ||||||
|  |  | ||||||
| $has_error = false; |  | ||||||
| $error_message = null; |  | ||||||
|  |  | ||||||
| if (isset($_POST["update_account"])) { |  | ||||||
|     $my_account = new MyAccount($_POST); |  | ||||||
|     try { |  | ||||||
|     	$my_account->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"; |  | ||||||
| @@ -1,112 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| if (isset($_POST["leave_team"])) { |  | ||||||
| 	quitTeam(); |  | ||||||
| 	exit(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| $has_error = false; |  | ||||||
| $error_message = null; |  | ||||||
|  |  | ||||||
| if (isset($_POST["team_edit"])) { |  | ||||||
| 	$my_team = new MyTeam($_POST); |  | ||||||
| 	try { |  | ||||||
| 		$my_team->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"; |  | ||||||
| @@ -1,137 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| if (!isset($_SESSION["user_id"]) || $_SESSION["role"] != Role::PARTICIPANT && $_SESSION["role"] != Role::ENCADRANT || Phase::getCurrentPhase() != Phase::PHASE2) |  | ||||||
| 	require_once "server_files/403.php"; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * @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() || $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"; |  | ||||||
| @@ -1,26 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| $problem = htmlspecialchars($_GET["probleme"]); |  | ||||||
|  |  | ||||||
| if (!preg_match("#[0-4]#", $problem)) |  | ||||||
| 	require_once "server_files/404.php"; |  | ||||||
|  |  | ||||||
| if (!isset($_SESSION["user_id"]) || $_SESSION["role"] != Role::ADMIN) |  | ||||||
|     require_once "server_files/403.php"; |  | ||||||
|  |  | ||||||
| $has_error = false; |  | ||||||
| $error_message = null; |  | ||||||
|  |  | ||||||
| $teams = Team::getAllTeams($problem); |  | ||||||
|  |  | ||||||
| $validated_emails = []; |  | ||||||
| $not_validated_emails = []; |  | ||||||
|  |  | ||||||
| foreach ($teams as $team) { |  | ||||||
| 	if ($team->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"; |  | ||||||
| @@ -1,9 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| if (!isset($_SESSION["user_id"]) || $_SESSION["role"] != Role::ADMIN) |  | ||||||
| 	require_once "server_files/403.php"; |  | ||||||
|  |  | ||||||
| $orphans = isset($_GET["orphans"]); |  | ||||||
| $users = $orphans ? User::getOrphanUsers() : User::getAllUsers(); |  | ||||||
|  |  | ||||||
| require_once "server_files/views/profiles.php"; |  | ||||||
| @@ -1,71 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| if ((isset($_SESSION["team"]) && $_SESSION["role"] == Role::PARTICIPANT) || !isset($_SESSION["user"]) || ($_SESSION["role"] != Role::PARTICIPANT && $_SESSION["role"] != Role::ENCADRANT)) |  | ||||||
| 	require_once "server_files/403.php"; |  | ||||||
|  |  | ||||||
| $has_error = false; |  | ||||||
| $error_message = null; |  | ||||||
|  |  | ||||||
| if (isset($_POST["join_team"])) { |  | ||||||
| 	$join_team = new JoinTeam($_POST); |  | ||||||
| 	try { |  | ||||||
| 		$join_team->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"; |  | ||||||
| @@ -1,126 +0,0 @@ | |||||||
| <?php |  | ||||||
| if (!isset($_SESSION["user_id"]) || $_SESSION["role"] != Role::PARTICIPANT && $_SESSION["role"] != Role::ENCADRANT || Phase::getCurrentPhase() != Phase::PHASE3) |  | ||||||
| 	require_once "server_files/403.php"; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * @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() || $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"; |  | ||||||
| @@ -1,141 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| if (!isset($_SESSION["user_id"]) || $_SESSION["role"] != Role::ADMIN) |  | ||||||
| 	require_once "server_files/403.php"; |  | ||||||
|  |  | ||||||
| $has_error = false; |  | ||||||
| $error_message = null; |  | ||||||
|  |  | ||||||
| if (isset($_POST["validate_video"])) { |  | ||||||
| 	$validate_video = new ValidateVideo($_POST); |  | ||||||
| 	try { |  | ||||||
| 		$validate_video->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"; |  | ||||||
| @@ -1,51 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| if (!isset($_GET["file_id"])) { |  | ||||||
| 	header("Location: $URL_BASE"); |  | ||||||
| 	exit(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| if (!isset($_SESSION["user_id"])) |  | ||||||
| 	require_once "server_files/403.php"; |  | ||||||
|  |  | ||||||
| $id = htmlspecialchars($_GET["file_id"]); |  | ||||||
|  |  | ||||||
| $file = Document::fromId($id); |  | ||||||
|  |  | ||||||
| if ($file !== null) { |  | ||||||
| 	$team = Team::fromId($file->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(); |  | ||||||
| @@ -1,326 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| function loadUserValues() |  | ||||||
| { |  | ||||||
| 	$_SESSION["user"] = $_SESSION["team"] = null; |  | ||||||
| 	unset($_SESSION["user"]); |  | ||||||
| 	unset($_SESSION["role"]); |  | ||||||
| 	unset($_SESSION["team"]); |  | ||||||
| 	unset($_SESSION["teams"]); |  | ||||||
|  |  | ||||||
| 	if (isset($_SESSION["user_id"])) { |  | ||||||
| 		$user = $_SESSION["user"] = User::fromId($_SESSION["user_id"]); |  | ||||||
| 		if ($user == null) { |  | ||||||
| 			unset($_SESSION["user_id"]); |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		$_SESSION["role"] = $user->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 "<div class=\"alert alert-warning\">\nPas de document envoyé pour le moment.\n</div>\n"; |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| 	echo "<div class=\"alert alert-info\">\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) : <a href=\"/file/$file_id\"><strong>Télécharger</strong></a><br />\n"; |  | ||||||
| 	} |  | ||||||
| 	echo "</div>\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 "<center><iframe width=\"854px\" height=\"480px\" src=\"https://www.youtube.com/embed/$code\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe></center><br />\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 "<center><iframe width=\"854px\" height=\"480px\" src=\"https://drive.google.com/file/d/$code/preview\" allowfullscreen></iframe></center><br />\n"; |  | ||||||
| 	} |  | ||||||
| 	elseif (preg_match("#(https?://|)(www\.|)vimeo\.com/([0-9]*)#", $link, $matches)) { |  | ||||||
| 		$code = $matches[3]; |  | ||||||
|         /** @noinspection HtmlDeprecatedAttribute */ |  | ||||||
|         /** @noinspection HtmlDeprecatedTag */ |  | ||||||
|         echo "<center><iframe src=\"https://player.vimeo.com/video/$code?color=3be6c3\" width=\"853\" height=\"480\" frameborder=\"0\" allow=\"autoplay; fullscreen\" allowfullscreen></iframe></center>"; |  | ||||||
|  |  | ||||||
| 	} |  | ||||||
| 	elseif (preg_match("#(https?://|)(www\.|)dailymotion\.com/video/(.*)#", $link, $matches)) { |  | ||||||
| 		$code = $matches[3]; |  | ||||||
|         /** @noinspection HtmlDeprecatedAttribute */ |  | ||||||
|         /** @noinspection HtmlDeprecatedTag */ |  | ||||||
| 		echo "<center><iframe frameborder=\"0\" width=\"853\" height=\"480\" src=\"https://www.dailymotion.com/embed/video/$code\" allowfullscreen allow=\"autoplay\"></iframe></center>"; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,256 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| class Mailer |  | ||||||
| { |  | ||||||
| 	private static function sendMail($email, $subject, $content, $from = "contact") |  | ||||||
| 	{ |  | ||||||
| 		global $MAIL_DOMAIN, $URL_BASE, $YEAR; |  | ||||||
|  |  | ||||||
| 		$content = preg_replace("#{URL_BASE}#", $URL_BASE, $content); |  | ||||||
| 		$content = preg_replace("#{YEAR}#", $YEAR . "- " . ($YEAR + 1), $content); |  | ||||||
|  |  | ||||||
| 		$headers = "From: \"Contact Corres2Math\" <" . $from . "@" . $MAIL_DOMAIN . ">\r\n"; |  | ||||||
| 		$headers .= "Reply-To: \"Contact corres2Math\" <contact@" . $MAIL_DOMAIN . ">\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#", "<br/>\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#", "<br/>\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#", "<br/>\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); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,22 +0,0 @@ | |||||||
| <!DOCTYPE html> |  | ||||||
| <html lang="fr"> |  | ||||||
| <head> |  | ||||||
|     <meta charset="UTF-8"> |  | ||||||
|     <title>Administrateur des Correspondances des Jeunes Mathématicien·ne·s</title> |  | ||||||
| </head> |  | ||||||
| <body> |  | ||||||
| Bonjour {FIRST_NAME} {SURNAME},<br /> |  | ||||||
| <br /> |  | ||||||
| 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.<br /> |  | ||||||
| <br /> |  | ||||||
| Votre mot de passe est : <strong style="color: red; font-size: 18px;">{PASSWORD}</strong><br /> |  | ||||||
| Vous pouvez vous connecter ici : <a href="{URL_BASE}/connexion">{URL_BASE}/connexion</a><br /> |  | ||||||
| <br /> |  | ||||||
| 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.<br /> |  | ||||||
| <br /> |  | ||||||
| Merci beaucoup pour votre aide !<br /> |  | ||||||
| <br /> |  | ||||||
| L'organisation des Correspondances des Jeunes Mathématicien·ne·s |  | ||||||
| </body> |  | ||||||
| </html> |  | ||||||
| @@ -1,17 +0,0 @@ | |||||||
| <!DOCTYPE html> |  | ||||||
| <html lang="fr"> |  | ||||||
| <head> |  | ||||||
|     <meta charset="UTF-8"> |  | ||||||
|     <title>Nouvelle équipe Correspondances des Jeunes Mathématicien·ne·s {YEAR}</title> |  | ||||||
| </head> |  | ||||||
| <body> |  | ||||||
| Bonjour {FIRST_NAME} {SURNAME},<br /> |  | ||||||
| <br /> |  | ||||||
| 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.<br /> |  | ||||||
| Afin de permettre aux autres membres de votre équipe de vous rejoindre, veuillez leur transmettre le code d'accès : |  | ||||||
| <strong>{ACCESS_CODE}</strong><br/> |  | ||||||
| <br /> |  | ||||||
| Le comité d'organisation des Correspondances des Jeunes Mathématicien·ne·s |  | ||||||
| </body> |  | ||||||
| </html> |  | ||||||
| @@ -1,16 +0,0 @@ | |||||||
| <!DOCTYPE html> |  | ||||||
| <!--suppress HtmlUnknownTarget --> |  | ||||||
| <html lang="fr"> |  | ||||||
| <head> |  | ||||||
|     <meta charset="UTF-8"> |  | ||||||
|     <title>Changement d'adresse e-mail – Correspondances des Jeunes Mathématicien·ne·s</title> |  | ||||||
| </head> |  | ||||||
| <body> |  | ||||||
| Bonjour {FIRST_NAME} {SURNAME},<br/> |  | ||||||
| <br/> |  | ||||||
| Vous venez de changer votre adresse e-mail. Veuillez désormais la confirmer en cliquant ici : <a |  | ||||||
|         href="{URL_BASE}/confirmer-mail/{TOKEN}">{URL_BASE}/confirmer-mail/{TOKEN}</a><br/> |  | ||||||
| <br/> |  | ||||||
| Le comité d'organisation des Correspondances des Jeunes Mathématicien·ne·s |  | ||||||
| </body> |  | ||||||
| </html> |  | ||||||
| @@ -1,18 +0,0 @@ | |||||||
| <!DOCTYPE html> |  | ||||||
| <html lang="fr"> |  | ||||||
| <head> |  | ||||||
|     <meta charset="UTF-8"> |  | ||||||
|     <title>Mot de passe changé – Correspondances des Jeunes Mathématicien·ne·s</title> |  | ||||||
| </head> |  | ||||||
| <body> |  | ||||||
| Bonjour {FIRST_NAME} {SURNAME},<br/> |  | ||||||
| <br/> |  | ||||||
| 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.<br/> |  | ||||||
| <br/> |  | ||||||
| Cordialement,<br/> |  | ||||||
| <br/> |  | ||||||
| Le comité d'organisation des Correspondances des Jeunes Mathématicien·ne·s |  | ||||||
| </body> |  | ||||||
| </html> |  | ||||||
| @@ -1,18 +0,0 @@ | |||||||
| <!DOCTYPE html> |  | ||||||
| <!--suppress HtmlUnknownTarget --> |  | ||||||
| <html lang="fr"> |  | ||||||
| <head> |  | ||||||
|     <meta charset="UTF-8"> |  | ||||||
|     <title>Inscription aux Correspondances des Jeunes Mathématicien·ne·s {YEAR}</title> |  | ||||||
| </head> |  | ||||||
| <body> |  | ||||||
| Bonjour {FIRST_NAME} {SURNAME},<br/> |  | ||||||
| <br/> |  | ||||||
| Vous êtes inscrit aux Correspondances des Jeunes Mathématicien·ne·s {YEAR} et nous vous en remercions.<br/> |  | ||||||
| Pour valider votre adresse e-mail, veuillez cliquer sur le lien : <a href="{URL_BASE}/confirmer-mail/{TOKEN}">{URL_BASE}/confirmer-mail/{TOKEN}</a><br/> |  | ||||||
| <br/> |  | ||||||
| Cordialement,<br/> |  | ||||||
| <br/> |  | ||||||
| Le comité d'organisation des Correspondances des Jeunes Mathématicien·ne·s |  | ||||||
| </body> |  | ||||||
| </html> |  | ||||||
| @@ -1,20 +0,0 @@ | |||||||
| <!DOCTYPE html> |  | ||||||
| <!--suppress HtmlUnknownTarget --> |  | ||||||
| <html lang="fr"> |  | ||||||
| <head> |  | ||||||
|     <meta charset="UTF-8"> |  | ||||||
|     <title>Mot de passe oublié – Correspondances des Jeunes Mathématicien·ne·s</title> |  | ||||||
| </head> |  | ||||||
| <body> |  | ||||||
| Bonjour,<br/> |  | ||||||
| <br/> |  | ||||||
| Vous avez indiqué avoir oublié votre mot de passe. Veuillez cliquer ici pour le réinitialiser : <a |  | ||||||
|         href="{URL_BASE}/connexion/reinitialiser_mdp/{TOKEN}">{URL_BASE}/connexion/reinitialiser_mdp/{TOKEN}</a><br/> |  | ||||||
| <br/> |  | ||||||
| Si vous n'êtes pas à l'origine de cette manipulation, vous pouvez ignorer ce message.<br/> |  | ||||||
| <br/> |  | ||||||
| Cordialement,<br/> |  | ||||||
| <br/> |  | ||||||
| Le comité d'organisation des Correspondances des Jeunes Mathématicien·ne·s |  | ||||||
| </body> |  | ||||||
| </html> |  | ||||||
| @@ -1,17 +0,0 @@ | |||||||
| <!DOCTYPE html> |  | ||||||
| <html lang="fr"> |  | ||||||
| <head> |  | ||||||
|     <meta charset="UTF-8"> |  | ||||||
|     <title>Équipe rejointe – Correspondances des Jeunes Mathématicien·ne·s {YEAR}</title> |  | ||||||
| </head> |  | ||||||
| <body> |  | ||||||
| Bonjour {FIRST_NAME} {SURNAME},<br/> |  | ||||||
| <br/> |  | ||||||
| Vous venez de rejoindre l'équipe « {TEAM_NAME} » ({TRIGRAM}) pour les Correspondances des Jeunes Mathématicien·ne·s |  | ||||||
| {PROBLEM} et nous vous en remercions.<br/> |  | ||||||
| <br/> |  | ||||||
| Cordialement,<br/> |  | ||||||
| <br/> |  | ||||||
| Le comité d'organisation des Correspondances des Jeunes Mathématicien·ne·s |  | ||||||
| </body> |  | ||||||
| </html> |  | ||||||
| @@ -1,19 +0,0 @@ | |||||||
| <!DOCTYPE html> |  | ||||||
| <html lang="fr"> |  | ||||||
| <head> |  | ||||||
|     <meta charset="UTF-8"> |  | ||||||
|     <title>Nouvelle vidéo – Correspondances des Jeunes Mathématicien·ne·s {YEAR}</title> |  | ||||||
| </head> |  | ||||||
| <body> |  | ||||||
| Bonjour {FIRST_NAME} {SURNAME},<br/> |  | ||||||
| <br/> |  | ||||||
| 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 : <a href="{VIDEO_LINK}">{VIDEO_LINK}</a>. |  | ||||||
| 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) : |  | ||||||
| <a href="{URL_BASE}/suivi-correspondances">{URL_BASE}/suivi-correspondances</a><br/> |  | ||||||
| <br/> |  | ||||||
| Cordialement,<br/> |  | ||||||
| <br/> |  | ||||||
| Le comité d'organisation des Correspondances des Jeunes Mathématicien·ne·s |  | ||||||
| </body> |  | ||||||
| </html> |  | ||||||
| @@ -1,18 +0,0 @@ | |||||||
| <!DOCTYPE html> |  | ||||||
| <html lang="fr"> |  | ||||||
| <head> |  | ||||||
|     <meta charset="UTF-8"> |  | ||||||
|     <title>Nouvelle vidéo – Correspondances des Jeunes Mathématicien·ne·s {YEAR}</title> |  | ||||||
| </head> |  | ||||||
| <body> |  | ||||||
| Bonjour {FIRST_NAME} {SURNAME},<br/> |  | ||||||
| <br/> |  | ||||||
| L'équipe « {TEAM_NAME} » ({TRIGRAM}) vient d'ajouter une vidéo pour le problème {PROBLEM} des Correspondances des Jeunes Mathématicien·ne·s : <a href="{VIDEO_LINK}">{VIDEO_LINK}</a>. |  | ||||||
| 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) : |  | ||||||
| <a href="{URL_BASE}/suivi-correspondances">{URL_BASE}/suivi-correspondances</a><br/> |  | ||||||
| <br/> |  | ||||||
| Cordialement,<br/> |  | ||||||
| <br/> |  | ||||||
| Le comité d'organisation des Correspondances des Jeunes Mathématicien·ne·s |  | ||||||
| </body> |  | ||||||
| </html> |  | ||||||
| @@ -1,16 +0,0 @@ | |||||||
| <!DOCTYPE html> |  | ||||||
| <!--suppress HtmlUnknownTarget --> |  | ||||||
| <html lang="fr"> |  | ||||||
| <head> |  | ||||||
|     <meta charset="UTF-8"> |  | ||||||
|     <title>Inscription aux Correspondances des Jeunes Mathématicien·ne·s {YEAR}</title> |  | ||||||
| </head> |  | ||||||
| <body> |  | ||||||
| Bonjour {FIRST_NAME} {SURNAME},<br /> |  | ||||||
| <br /> |  | ||||||
| Vous venez de vous inscrire aux Correspondances des Jeunes Mathématicien·ne·s {YEAR} et nous vous en remercions.<br /> |  | ||||||
| Pour valider votre adresse e-mail, veuillez cliquer sur le lien : <a href="{URL_BASE}/confirmer-mail/{TOKEN}">{URL_BASE}/confirmer-mail/{TOKEN}</a><br /> |  | ||||||
| <br /> |  | ||||||
| Le comité d'organisation des Correspondances des Jeunes Mathématicien·ne·s |  | ||||||
| </body> |  | ||||||
| </html> |  | ||||||
| @@ -1,19 +0,0 @@ | |||||||
| <!DOCTYPE html> |  | ||||||
| <!--suppress HtmlUnknownTarget --> |  | ||||||
| <html lang="fr"> |  | ||||||
| <head> |  | ||||||
|     <meta charset="UTF-8"> |  | ||||||
|     <title>Demande de validation - Correspondances des Jeunes Mathématicien·ne·s</title> |  | ||||||
| </head> |  | ||||||
| <body> |  | ||||||
| Bonjour {FIRST_NAME} {SURNAME},<br /> |  | ||||||
| <br /> |  | ||||||
| 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 : <a href="{URL_BASE}/equipe/{TRIGRAM}">{URL_BASE}/equipe/{TRIGRAM}</a><br/> |  | ||||||
| <br/> |  | ||||||
| Cordialement,<br/> |  | ||||||
| <br /> |  | ||||||
| L'organisation des Correspondances des Jeunes Mathématicien·ne·s |  | ||||||
| </body> |  | ||||||
| </html> |  | ||||||
| @@ -1,21 +0,0 @@ | |||||||
| <!DOCTYPE html> |  | ||||||
| <html lang="fr"> |  | ||||||
| <head> |  | ||||||
|     <meta charset="UTF-8"> |  | ||||||
|     <title>Équipe non validée – Correspondances des Jeunes Mathématicien·ne·s {YEAR}</title> |  | ||||||
| </head> |  | ||||||
| <body> |  | ||||||
| Bonjour {FIRST_NAME} {SURNAME},<br/> |  | ||||||
| <br/> |  | ||||||
| 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}<br /> |  | ||||||
| <br /> |  | ||||||
| N'hésitez pas à nous contacter à l'adresse <a href="contact@correspondances-maths.fr">contact@correspondances-maths.fr</a> |  | ||||||
| pour plus d'informations. |  | ||||||
| <br/> |  | ||||||
| Cordialement,<br/> |  | ||||||
| <br/> |  | ||||||
| Le comité d'organisation des Correspondances des Jeunes Mathématicien·ne·s |  | ||||||
| </body> |  | ||||||
| </html> |  | ||||||
| @@ -1,18 +0,0 @@ | |||||||
| <!DOCTYPE html> |  | ||||||
| <html lang="fr"> |  | ||||||
| <head> |  | ||||||
|     <meta charset="UTF-8"> |  | ||||||
|     <title>Équipe validée – Correspondances des Jeunes Mathématicien·ne·s {YEAR}</title> |  | ||||||
| </head> |  | ||||||
| <body> |  | ||||||
| Bonjour {FIRST_NAME} {SURNAME},<br/> |  | ||||||
| <br/> |  | ||||||
| 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}<br /> |  | ||||||
| <br/> |  | ||||||
| Cordialement,<br/> |  | ||||||
| <br/> |  | ||||||
| Le comité d'organisation des Correspondances des Jeunes Mathématicien·ne·s |  | ||||||
| </body> |  | ||||||
| </html> |  | ||||||
| @@ -1,21 +0,0 @@ | |||||||
| <!DOCTYPE html> |  | ||||||
| <html lang="fr"> |  | ||||||
| <head> |  | ||||||
|     <meta charset="UTF-8"> |  | ||||||
|     <title>Vidéo acceptée – Correspondances des Jeunes Mathématicien·ne·s {YEAR}</title> |  | ||||||
| </head> |  | ||||||
| <body> |  | ||||||
| Bonjour {FIRST_NAME} {SURNAME},<br /> |  | ||||||
| <br /> |  | ||||||
| Félicitations, votre vidéo de réponse pour le problème {PROBLEM} a été validée ! Pour rappel, vous aviez soumis ce lien : <a href="{VIDEO_LINK}">{VIDEO_LINK}</a>.<br /> |  | ||||||
| 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.<br /> |  | ||||||
| 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.<br /> |  | ||||||
| <br /> |  | ||||||
| N'oubliez pas de contrôler que les paramètres de diffusion de vidéo sont cohérents avec ce que vous souhaitez : <a href="{URL_BASE}/mon-equipe">{URL_BASE}/mon-equipe</a><br /> |  | ||||||
| <br /> |  | ||||||
| {MESSAGE} |  | ||||||
| Cordialement,<br /> |  | ||||||
| <br /> |  | ||||||
| Le comité d'organisation des Correspondances des Jeunes Mathématicien·ne·s |  | ||||||
| </body> |  | ||||||
| </html> |  | ||||||
| @@ -1,21 +0,0 @@ | |||||||
| <!DOCTYPE html> |  | ||||||
| <html lang="fr"> |  | ||||||
| <head> |  | ||||||
|     <meta charset="UTF-8"> |  | ||||||
|     <title>Vidéo acceptée – Correspondances des Jeunes Mathématicien·ne·s {YEAR}</title> |  | ||||||
| </head> |  | ||||||
| <body> |  | ||||||
| Bonjour {FIRST_NAME} {SURNAME},<br /> |  | ||||||
| <br/> |  | ||||||
| Félicitations, votre vidéo pour le problème {PROBLEM} a été validée ! Pour rappel, vous aviez soumis ce lien : <a href="{VIDEO_LINK}">{VIDEO_LINK}</a>.<br /> |  | ||||||
| Votre travail est à présent terminé, et vous pouvez attendre les prochaines phases. Bravo à vous !<br /> |  | ||||||
| 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.<br /> |  | ||||||
| <br /> |  | ||||||
| N'oubliez pas de contrôler que les paramètres de diffusion de vidéo sont cohérents avec ce que vous souhaitez : <a href="{URL_BASE}/mon-equipe">{URL_BASE}/mon-equipe</a><br /> |  | ||||||
| <br /> |  | ||||||
| {MESSAGE} |  | ||||||
| Cordialement,<br /> |  | ||||||
| <br /> |  | ||||||
| Le comité d'organisation des Correspondances des Jeunes Mathématicien·ne·s |  | ||||||
| </body> |  | ||||||
| </html> |  | ||||||
| @@ -1,23 +0,0 @@ | |||||||
| <!DOCTYPE html> |  | ||||||
| <html lang="fr"> |  | ||||||
| <head> |  | ||||||
|     <meta charset="UTF-8"> |  | ||||||
|     <title>Vidéo refusée – Correspondances des Jeunes Mathématicien·ne·s {YEAR}</title> |  | ||||||
| </head> |  | ||||||
| <body> |  | ||||||
| Bonjour {FIRST_NAME} {SURNAME},<br/> |  | ||||||
| <br/> |  | ||||||
| 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 : <a href="{VIDEO_LINK}">{VIDEO_LINK}</a>.<br /> |  | ||||||
| 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 à |  | ||||||
| <a href="mailto:contact@correspondances-maths.fr">contact@correspondances-maths.fr</a> si vous souhaitez avoir plus |  | ||||||
| d'informations ou contester ce refus.<br /> |  | ||||||
| <br/> |  | ||||||
| {MESSAGE} |  | ||||||
| Cordialement,<br/> |  | ||||||
| <br/> |  | ||||||
| Le comité d'organisation des Correspondances des Jeunes Mathématicien·ne·s |  | ||||||
| </body> |  | ||||||
| </html> |  | ||||||
| @@ -1,23 +0,0 @@ | |||||||
| <!DOCTYPE html> |  | ||||||
| <html lang="fr"> |  | ||||||
| <head> |  | ||||||
|     <meta charset="UTF-8"> |  | ||||||
|     <title>Vidéo refusée – Correspondances des Jeunes Mathématicien·ne·s {YEAR}</title> |  | ||||||
| </head> |  | ||||||
| <body> |  | ||||||
| Bonjour {FIRST_NAME} {SURNAME},<br/> |  | ||||||
| <br/> |  | ||||||
| Malheureusement, votre vidéo pour le problème {PROBLEM} n'a pas été validée. Pour rappel, vous aviez soumis ce lien : |  | ||||||
| <a href="{VIDEO_LINK}">{VIDEO_LINK}</a>.<br /> |  | ||||||
| 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 à |  | ||||||
| <a href="mailto:contact@correspondances-maths.fr">contact@correspondances-maths.fr</a> si vous souhaitez avoir plus |  | ||||||
| d'informations ou contester ce refus.<br /> |  | ||||||
| <br/> |  | ||||||
| {MESSAGE} |  | ||||||
| Cordialement,<br/> |  | ||||||
| <br/> |  | ||||||
| Le comité d'organisation des Correspondances des Jeunes Mathématicien·ne·s |  | ||||||
| </body> |  | ||||||
| </html> |  | ||||||
| @@ -1,48 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| function ensure($bool, $error_msg = "") |  | ||||||
| { |  | ||||||
| 	if (!$bool) |  | ||||||
| 		throw new AssertionError($error_msg); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function formatDate($date = NULL, $with_time = false) |  | ||||||
| { |  | ||||||
| 	if ($date == NULL) |  | ||||||
| 		$date = date("yyyy-mm-dd"); |  | ||||||
|  |  | ||||||
| 	return strftime("%d %B %G" . ($with_time ? " %H:%M" : ""), strtotime($date)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function dateWellFormed($date, $with_time = false) |  | ||||||
| { |  | ||||||
| 	return date_parse_from_format($with_time ? "yyyy-mm-dd HH-MM:ss" : "yy-mm-dd", $date) !== false; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function genRandomPhrase($size, $uppercase = false) |  | ||||||
| { |  | ||||||
| 	$alphabet = $uppercase ? "0123456789abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" : "0123456789abcdefghijklmnopqrstuvwxyz0123456789"; |  | ||||||
|  |  | ||||||
| 	$phrase = ""; |  | ||||||
| 	for ($i = 0; $i < $size; ++$i) { |  | ||||||
| 		$phrase .= $alphabet[rand(0, strlen($alphabet) - 1)]; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return $phrase; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function getExtFromMimeType($mime_type) |  | ||||||
| { |  | ||||||
| 	switch ($mime_type) { |  | ||||||
| 		case "application/pdf": |  | ||||||
| 			return ".pdf"; |  | ||||||
| 		case "image/png": |  | ||||||
| 			return ".png"; |  | ||||||
| 		case "image/jpg": |  | ||||||
| 		case "image/jpeg": |  | ||||||
| 			return ".jpg"; |  | ||||||
| 		case "application/zip": |  | ||||||
| 			return ".zip"; |  | ||||||
| 	} |  | ||||||
| 	return ""; |  | ||||||
| } |  | ||||||
| @@ -1,67 +0,0 @@ | |||||||
| <?php |  | ||||||
| require_once "header.php"; |  | ||||||
| ?> |  | ||||||
|  |  | ||||||
| <div class="mt-4 mb-4"> |  | ||||||
|     <h1 class="display-4">Liste des administrateurs</h1> |  | ||||||
| </div> |  | ||||||
|  |  | ||||||
| <hr /> |  | ||||||
|  |  | ||||||
|     <table class="table table-striped table-bordered table-hover"> |  | ||||||
|         <thead> |  | ||||||
|         <tr> |  | ||||||
|             <th scope="col"> |  | ||||||
|                 Nom |  | ||||||
|             </th> |  | ||||||
|             <th scope="col"> |  | ||||||
|                 Prénom |  | ||||||
|             </th> |  | ||||||
|             <th scope="col"> |  | ||||||
|                 Adresse e-mail |  | ||||||
|             </th> |  | ||||||
|         </tr> |  | ||||||
|         </thead> |  | ||||||
|         <tbody> |  | ||||||
|         <?php |  | ||||||
|         /** @var User $admin */ |  | ||||||
|         foreach ($admins as $admin) { |  | ||||||
|             ?> |  | ||||||
|             <tr> |  | ||||||
|                 <td> |  | ||||||
|                     <a href="/informations/<?= $admin->getId() ?>/<?= $admin->getFirstName() . " " . $admin->getSurname() ?>"> |  | ||||||
|                         <?= $admin->getSurname() ?> |  | ||||||
|                     </a> |  | ||||||
|                 </td> |  | ||||||
|                 <td> |  | ||||||
|                     <a href="/informations/<?= $admin->getId() ?>/<?= $admin->getFirstName() . " " . $admin->getSurname() ?>"> |  | ||||||
|                         <?= $admin->getFirstName() ?> |  | ||||||
|                     </a> |  | ||||||
|                 </td> |  | ||||||
|                 <td> |  | ||||||
|                     <a href="mailto:<?= $admin->getEmail() ?>"> |  | ||||||
|                         <?= $admin->getEmail() ?> |  | ||||||
|                     </a> |  | ||||||
|                 </td> |  | ||||||
|             </tr> |  | ||||||
|             <?php |  | ||||||
|         } |  | ||||||
|         ?> |  | ||||||
|         </tbody> |  | ||||||
|         <tfoot> |  | ||||||
|         <tr> |  | ||||||
|             <th> |  | ||||||
|                 Nom |  | ||||||
|             </th> |  | ||||||
|             <th> |  | ||||||
|                 Prénom |  | ||||||
|             </th> |  | ||||||
|             <th> |  | ||||||
|                 Adresse e-mail |  | ||||||
|             </th> |  | ||||||
|         </tr> |  | ||||||
|         </tfoot> |  | ||||||
|     </table> |  | ||||||
|  |  | ||||||
| <?php |  | ||||||
| require_once "footer.php"; |  | ||||||
| @@ -1,43 +0,0 @@ | |||||||
| <?php |  | ||||||
| require_once "header.php"; |  | ||||||
| ?> |  | ||||||
|  |  | ||||||
|     <div class="mt-4 mb-4"> |  | ||||||
|         <h1 class="display-4">Ajouter un administrateur</h1> |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
| <?php if (isset($admin) && !$has_error) { ?> |  | ||||||
|     <div class="alert alert-success"> |  | ||||||
|         Administrateur ajouté avec succès ! Ses identifiants ont été transmis par mail. |  | ||||||
|     </div> |  | ||||||
| <?php } ?> |  | ||||||
|  |  | ||||||
| <form method="POST"> |  | ||||||
|     <div class="form-row"> |  | ||||||
|         <div class="form-group col-md-6"> |  | ||||||
|             <label for="surname">Nom :</label> |  | ||||||
|             <input class="form-control" type="text" id="surname" name="surname" |  | ||||||
|                    value="<?php if (isset($admin)) echo $admin->surname ?>" required/> |  | ||||||
|         </div> |  | ||||||
|  |  | ||||||
|         <div class="form-group col-md-6"> |  | ||||||
|             <label for="first_name">Prénom :</label> |  | ||||||
|             <input class="form-control" type="text" id="first_name" name="first_name" |  | ||||||
|                    value="<?php if (isset($admin)) echo $admin->first_name ?>" required/> |  | ||||||
|         </div> |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
|     <div class="form-row"> |  | ||||||
|         <div class="form-group col-md-12"> |  | ||||||
|             <label for="email">E-mail :</label> |  | ||||||
|             <input class="form-control" type="email" id="email" name="email" |  | ||||||
|                    value="<?php if (isset($admin)) echo $admin->email ?>" required/> |  | ||||||
|         </div> |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
|     <div class="form-group row"> |  | ||||||
|         <input class="btn btn-primary btn-lg btn-block" name="add_admin" type="submit" value="Ajouter un administrateur" /> |  | ||||||
|     </div> |  | ||||||
| </form> |  | ||||||
|  |  | ||||||
| <?php require_once "footer.php" ?> |  | ||||||
| @@ -1,78 +0,0 @@ | |||||||
| <?php |  | ||||||
| require_once "header.php"; |  | ||||||
| ?> |  | ||||||
|  |  | ||||||
| <div class="mt-4 mb-4"> |  | ||||||
|     <h1 class="display-4">Ajouter une équipe</h1> |  | ||||||
| </div> |  | ||||||
|  |  | ||||||
| <?php if (isset($new_team) && !$has_error) { ?> |  | ||||||
|     <div class="alert alert-success"> |  | ||||||
|         Votre équipe a bien été créée ! Voici le code d'accès à transmettre aux autres membres de votre équipe : |  | ||||||
|         <strong><?= $new_team->access_code ?></strong> |  | ||||||
|     </div> |  | ||||||
| <?php } elseif ($_SESSION["team"] != NULL && $_SESSION["role"] == Role::PARTICIPANT) { ?> |  | ||||||
|     <div class="alert alert-danger"> |  | ||||||
|         Vous êtes déjà dans une équipe. |  | ||||||
|     </div> |  | ||||||
| <?php } elseif(date("Y-m-d H:i:s") >= $CONFIG->getInscriptionDate()) { ?> |  | ||||||
|     <div class="alert alert-danger"> |  | ||||||
|         La date limite d'inscription est dépassée. |  | ||||||
|     </div> |  | ||||||
| <?php } else { ?> |  | ||||||
|  |  | ||||||
|     <?php if ($_SESSION["role"] == Role::ENCADRANT && sizeof($_SESSION["teams"]) > 0) { ?> |  | ||||||
|         <div class="alert alert-warning"> |  | ||||||
|             Vous êtes déjà inscrit dans une équipe. Vous pouvez toutefois encadrer plusieurs équipes. |  | ||||||
|         </div> |  | ||||||
|     <?php } ?> |  | ||||||
|  |  | ||||||
|     <div class="alert alert-info"> |  | ||||||
|         Chacune des informations pourra être modifiée avant que l'équipe tant que l'équipe n'est pas validée. |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
| <form method="POST"> |  | ||||||
|     <div class="form-row"> |  | ||||||
|         <div class="form-group col-md-6"> |  | ||||||
|             <label for="name">Nom (<em>Pas de caractères spéciaux</em>) :</label> |  | ||||||
|             <input class="form-control" type="text" id="name" name="name" pattern="[A-Za-zÀ-ÿ ]+" |  | ||||||
|                    value="<?php if (isset($new_team)) echo $new_team->name ?>" required/> |  | ||||||
|         </div> |  | ||||||
|  |  | ||||||
|         <div class="form-group col-md-6"> |  | ||||||
|             <label for="trigram">Trigramme (<em>identifiant unique à trois lettres de l'équipe</em>) :</label> |  | ||||||
|             <input class="form-control" type="text" id="trigram" name="trigram" |  | ||||||
|                    value="<?php if (isset($new_team)) echo $new_team->trigram ?>" pattern="[A-Z]{3}" maxlength="3" required/> |  | ||||||
|         </div> |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
|     <div class="form-group row"> |  | ||||||
|         <label for="problem">Problème :</label> |  | ||||||
|         <select id="problem" name="problem" class="custom-select"> |  | ||||||
|             <option value="0">Choisir un problème ...</option> |  | ||||||
| 			<?php |  | ||||||
| 			for ($i = 1; $i <= 4; ++$i) |  | ||||||
| 				echo "<option value='$i' " . (isset($new_team) && $new_team->problem == $i ? "selected" : "") . ">Problème $i</option>"; |  | ||||||
| 			?> |  | ||||||
|         </select> |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
|     <label for="allow_other_teams">J'accepte que mes vidéos soient diffusées aux équipes avec lesquelles je vais concourir :</label> |  | ||||||
|     <input type="checkbox" id="allow_other_teams" name="allow_other_teams" |  | ||||||
|         <?= isset($new_team) && $new_team->allow_other_teams ? "checked" : "" ?> required/><br /> |  | ||||||
|  |  | ||||||
|     <label for="allow_publish">J'accepte qu'Animath diffuse mes vidéos à la fin des Correspondances (<em>facultatif</em>) :</label> |  | ||||||
|     <input type="checkbox" id="allow_publish" name="allow_publish" |  | ||||||
|         <?= isset($new_team) && $new_team->allow_publish ? "checked" : "" ?> /> |  | ||||||
|  |  | ||||||
|     <div class="alert alert-info"> |  | ||||||
|         Cette dernière option est modifiable à tout moment, et permet à <em>Animath</em> de diffuser les vidéos primées. |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
|     <div class="form-group row"> |  | ||||||
|         <input class="btn btn-primary btn-lg btn-block" name="add_team" type="submit" value="Ajouter une équipe"/> |  | ||||||
|     </div> |  | ||||||
| </form> |  | ||||||
| <?php } ?> |  | ||||||
|  |  | ||||||
| <?php require_once "footer.php" ?> |  | ||||||
| @@ -1,138 +0,0 @@ | |||||||
| <?php require_once "header.php"; ?> |  | ||||||
|  |  | ||||||
|     <div class="mt-4 mb-4"> |  | ||||||
|         <h1 class="display-4">Calendrier</h1> |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
| <?php if (isset($_GET["edit"])) { ?> |  | ||||||
|  |  | ||||||
|     <form method="POST"> |  | ||||||
|         <div class="form-group row"> |  | ||||||
|             <label for="inscription">Fin des inscriptions :</label> |  | ||||||
|             <div class="form-group col-md-10"> |  | ||||||
|                 <input class="form-control" type="date" id="inscription" name="date_inscription" |  | ||||||
|                        value="<?= substr($CONFIG->getInscriptionDate(), 0, 10) ?>"/> |  | ||||||
|                 <input class="form-control" type="time" id="inscription" name="time_inscription" |  | ||||||
|                        value="<?= substr($CONFIG->getInscriptionDate(), 11, 5) ?>"/> |  | ||||||
|             </div> |  | ||||||
|         </div> |  | ||||||
|  |  | ||||||
|         <div class="form-group row"> |  | ||||||
|             <label for="phase1">Dates de la phase 1 :</label> |  | ||||||
|             <div class="form-group col-md-5"> |  | ||||||
|                 <input class="form-control" type="date" id="phase1" name="date_start_phase1" |  | ||||||
|                        value="<?= substr($CONFIG->getStartPhase1Date(), 0, 10) ?>"/> |  | ||||||
|                 <input class="form-control" type="time" id="phase1" name="time_start_phase1" |  | ||||||
|                        value="<?= substr($CONFIG->getStartPhase1Date(), 11, 5) ?>"/> |  | ||||||
|             </div> |  | ||||||
|             <div class="form-group col-md-5"> |  | ||||||
|                 <input class="form-control" type="date" id="phase1" name="date_end_phase1" |  | ||||||
|                        value="<?= substr($CONFIG->getEndPhase1Date(), 0, 10) ?>"/> |  | ||||||
|                 <input class="form-control" type="time" id="phase1" name="time_end_phase1" |  | ||||||
|                        value="<?= substr($CONFIG->getEndPhase1Date(), 11, 5) ?>"/> |  | ||||||
|             </div> |  | ||||||
|         </div> |  | ||||||
|  |  | ||||||
|         <div class="form-group row"> |  | ||||||
|             <label for="phase2">Dates de la phase 2 :</label> |  | ||||||
|             <div class="form-group col-md-5"> |  | ||||||
|                 <input class="form-control" type="date" id="phase2" name="date_start_phase2" |  | ||||||
|                        value="<?= substr($CONFIG->getStartPhase2Date(), 0, 10) ?>"/> |  | ||||||
|                 <input class="form-control" type="time" id="phase1" name="time_start_phase2" |  | ||||||
|                        value="<?= substr($CONFIG->getStartPhase2Date(), 11, 5) ?>"/> |  | ||||||
|             </div> |  | ||||||
|             <div class="form-group col-md-5"> |  | ||||||
|                 <input class="form-control" type="date" id="phase2" name="date_end_phase2" |  | ||||||
|                        value="<?= substr($CONFIG->getEndPhase2Date(), 0, 10) ?>"/> |  | ||||||
|                 <input class="form-control" type="time" id="phase2" name="time_end_phase2" |  | ||||||
|                        value="<?= substr($CONFIG->getEndPhase2Date(), 11, 5) ?>"/> |  | ||||||
|             </div> |  | ||||||
|         </div> |  | ||||||
|  |  | ||||||
|         <div class="form-group row"> |  | ||||||
|             <label for="phase3">Dates de la phase 3 :</label> |  | ||||||
|             <div class="form-group col-md-5"> |  | ||||||
|                 <input class="form-control" type="date" id="phase3" name="date_start_phase3" |  | ||||||
|                        value="<?= substr($CONFIG->getStartPhase3Date(), 0, 10) ?>"/> |  | ||||||
|                 <input class="form-control" type="time" id="phase3" name="time_start_phase3" |  | ||||||
|                        value="<?= substr($CONFIG->getStartPhase3Date(), 11, 5) ?>"/> |  | ||||||
|             </div> |  | ||||||
|             <div class="form-group col-md-5"> |  | ||||||
|                 <input class="form-control" type="date" id="phase3" name="date_end_phase3" |  | ||||||
|                        value="<?= substr($CONFIG->getEndPhase3Date(), 0, 10) ?>"/> |  | ||||||
|                 <input class="form-control" type="time" id="phase3" name="time_end_phase3" |  | ||||||
|                        value="<?= substr($CONFIG->getEndPhase3Date(), 11, 5) ?>"/> |  | ||||||
|             </div> |  | ||||||
|         </div> |  | ||||||
|  |  | ||||||
|         <div class="form-group row"> |  | ||||||
|             <label for="phase4">Dates de la phase 4 :</label> |  | ||||||
|             <div class="form-group col-md-5"> |  | ||||||
|                 <input class="form-control" type="date" id="phase4" name="date_start_phase4" |  | ||||||
|                        value="<?= substr($CONFIG->getStartPhase4Date(), 0, 10) ?>"/> |  | ||||||
|                 <input class="form-control" type="time" id="phase4" name="time_start_phase4" |  | ||||||
|                        value="<?= substr($CONFIG->getStartPhase4Date(), 11, 5) ?>"/> |  | ||||||
|             </div> |  | ||||||
|             <div class="form-group col-md-5"> |  | ||||||
|                 <input class="form-control" type="date" id="phase4" name="date_end_phase4" |  | ||||||
|                        value="<?= substr($CONFIG->getEndPhase4Date(), 0, 10) ?>"/> |  | ||||||
|                 <input class="form-control" type="time" id="phase4" name="time_end_phase4" |  | ||||||
|                        value="<?= substr($CONFIG->getEndPhase4Date(), 11, 5) ?>"/> |  | ||||||
|             </div> |  | ||||||
|         </div> |  | ||||||
|  |  | ||||||
|         <div class="form-group row"> |  | ||||||
|             <input class="btn btn-primary btn-lg btn-block" type="submit" name="update_calendar" |  | ||||||
|                    value="Mettre à jour le calendrier"/> |  | ||||||
|         </div> |  | ||||||
|     </form> |  | ||||||
|  |  | ||||||
| <?php } else { ?> |  | ||||||
|  |  | ||||||
|     <div class="alert alert-<?= date("Y-m-d H:i:s") <= $CONFIG->getInscriptionDate() ? "warning" : "success" ?>"> |  | ||||||
|         <?= Phase::getTranslatedName(Phase::INSCRIPTION) ?> : |  | ||||||
|         <strong><?= formatDate($CONFIG->getInscriptionDate(), true) ?></strong> |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
|     <div class="alert alert-<?= Phase::getCurrentPhase() < Phase::PHASE1 ? "danger" : (Phase::getCurrentPhase() == Phase::PHASE1 ? "warning" : "success") ?>"> |  | ||||||
|         <?= Phase::getTranslatedName(Phase::PHASE1) ?> : |  | ||||||
|         Du <strong><?= formatDate($CONFIG->getStartPhase1Date(), true) ?></strong> au |  | ||||||
|         <strong><?= formatDate($CONFIG->getEndPhase1Date(), true) ?></strong> |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
|     <div class="alert alert-<?= Phase::getCurrentPhase() < Phase::PHASE2 ? "danger" : (Phase::getCurrentPhase() == Phase::PHASE2 ? "warning" : "success") ?>"> |  | ||||||
|         <?= Phase::getTranslatedName(Phase::PHASE2) ?> : |  | ||||||
|         Du <strong><?= formatDate($CONFIG->getStartPhase2Date(), true) ?></strong> au |  | ||||||
|         <strong><?= formatDate($CONFIG->getEndPhase2Date(), true) ?></strong> |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
|     <div class="alert alert-<?= Phase::getCurrentPhase() < Phase::PHASE3 ? "danger" : (Phase::getCurrentPhase() == Phase::PHASE3 ? "warning" : "success") ?>"> |  | ||||||
|         <?= Phase::getTranslatedName(Phase::PHASE3) ?> : |  | ||||||
|         Du <strong><?= formatDate($CONFIG->getStartPhase3Date(), true) ?></strong> au |  | ||||||
|         <strong><?= formatDate($CONFIG->getEndPhase3Date(), true) ?></strong> |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
|     <div class="alert alert-<?= Phase::getCurrentPhase() < Phase::PHASE4 ? "danger" : (Phase::getCurrentPhase() == Phase::PHASE4 ? "warning" : "success") ?>"> |  | ||||||
|         <?= Phase::getTranslatedName(Phase::PHASE4) ?> : |  | ||||||
|         Du <strong><?= formatDate($CONFIG->getStartPhase4Date(), true) ?></strong> au |  | ||||||
|         <strong><?= formatDate($CONFIG->getEndPhase4Date(), true) ?></strong> |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
|     <?php if ($_SESSION["role"] == Role::ADMIN) { ?> |  | ||||||
|         <!--suppress HtmlUnknownTarget --> |  | ||||||
|         <a href="/calendrier/modifier"> |  | ||||||
|             <button class="btn btn-primary btn-lg btn-block">Modifier le calendrier</button> |  | ||||||
|         </a> |  | ||||||
|     <?php } ?> |  | ||||||
|  |  | ||||||
|     <hr/> |  | ||||||
|  |  | ||||||
|     <a href="https://correspondances-maths.fr/participer/" target="_blank"> |  | ||||||
|         <button class="btn btn-primary btn-lg btn-block"> |  | ||||||
|             Comment participer aux Correspondances ? |  | ||||||
|         </button> |  | ||||||
|     </a> |  | ||||||
|  |  | ||||||
| <?php } |  | ||||||
|  |  | ||||||
| require_once "footer.php"; |  | ||||||
| @@ -1,131 +0,0 @@ | |||||||
| <?php |  | ||||||
| require_once "header.php"; |  | ||||||
| ?> |  | ||||||
|  |  | ||||||
|     <div class="mt-4 mb-4"> |  | ||||||
|         <h1 class="display-4">Répondre aux questions</h1> |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
| <?php if (isset($new_answer) && !$has_error) { ?> |  | ||||||
|     <div class="alert alert-success"> |  | ||||||
|         Votre vidéo a bien été envoyée ! |  | ||||||
|     </div> |  | ||||||
| <?php } ?> |  | ||||||
|  |  | ||||||
|     <div class="alert alert-info"> |  | ||||||
|         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. |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
|     <div class="alert alert-warning"> |  | ||||||
|         <strong>Date limite de soumission :</strong> <?= formatDate($CONFIG->getEndPhase4Date(), true) ?> |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
| <?php |  | ||||||
| for ($i = 0; $i < 2; ++$i) { |  | ||||||
| 	/** @var Team $answer_team */ |  | ||||||
| 	$answer_team = $teams[$i]; |  | ||||||
| 	/** @var Video $sol */ |  | ||||||
| 	$sol = $sols[$i]; |  | ||||||
| 	/** @var Video $answer */ |  | ||||||
| 	$answer = $answers[$i]; |  | ||||||
| 	/** @var Video $answer_validated */ |  | ||||||
| 	$answer_validated = $answers_validated[$i]; |  | ||||||
| 	/** @var Question[] $questions */ |  | ||||||
| 	$questions = Question::getQuestions($team, $answer_team); |  | ||||||
| 	?> |  | ||||||
|     <div class="jumbotron"> |  | ||||||
|     <h2>Vidéo de l'équipe <?= $answer_team->getName() ?> (<?= $answer_team->getTrigram() ?>) :</h2> |  | ||||||
|     <div class="alert alert-info"> |  | ||||||
|         <strong>Lien de la vidéo de présentation de la solution au problème :</strong> |  | ||||||
|         <a href="<?= $sol->getLink() ?>"><?= $sol->getLink() ?></a> |  | ||||||
|     </div> |  | ||||||
| 	<?php displayVideo($sol->getLink()) ?> |  | ||||||
|  |  | ||||||
|     <h5>Questions échangées :</h5> |  | ||||||
| 	<?php |  | ||||||
|  |  | ||||||
| 	if (!strcmp($questions[1]->getQuestion(), Question::DEFAULT_QUESTIONS[0]) |  | ||||||
| 		&& !strcmp($questions[2]->getQuestion(), Question::DEFAULT_QUESTIONS[1]) |  | ||||||
| 		&& !strcmp($questions[3]->getQuestion(), Question::DEFAULT_QUESTIONS[2])) { ?> |  | ||||||
|         <div class="alert alert-danger"> |  | ||||||
|             L'équipe n'a malheureusement transmis aucune question. Vous n'avez donc pas de réponse à donner. |  | ||||||
|         </div> |  | ||||||
| 	<?php } else { |  | ||||||
| 		for ($j = 0; $j <= 6; ++$j) { |  | ||||||
| 			/** @var Question $question */ |  | ||||||
| 			$question = $questions[$j]; |  | ||||||
| 			if ($j > 0 && $question->getQuestion() === null) |  | ||||||
| 				continue; |  | ||||||
| 			?> |  | ||||||
|             <div class="alert alert-info"> |  | ||||||
|                 <strong><?= $j == 0 ? "Remarques générales :" : "Question " . $question->getNumber() . " :" ?></strong> |  | ||||||
| 				<?= $question->getQuestion() ?><br/> |  | ||||||
| 				<?php |  | ||||||
| 				if ($question->getAttachedFile() !== null) { ?> |  | ||||||
|                     <em>Pièce jointe attachée :</em> |  | ||||||
|                     <a href="/file/<?= $question->getAttachedFile() ?>"><strong>Télécharger</strong></a><br/> |  | ||||||
| 				<?php } ?> |  | ||||||
|                 <strong>Réponse :</strong> <?= $question->getAnswer() ?><br/> |  | ||||||
| 				<?php |  | ||||||
| 				if ($question->getAttachedFileAnswer() !== null) { ?> |  | ||||||
|                     <em>Pièce jointe attachée :</em> |  | ||||||
|                     <a href="/file/<?= $question->getAttachedFileAnswer() ?>"><strong>Télécharger</strong></a><br/> |  | ||||||
| 				<?php } ?> |  | ||||||
|             </div> |  | ||||||
| 		<?php } ?> |  | ||||||
|         <br/> |  | ||||||
|         <h5>Vidéo de réponse :</h5> |  | ||||||
|  |  | ||||||
| 		<?php |  | ||||||
| 		if ($answer !== null) { |  | ||||||
| 			$link = $answer->getLink(); |  | ||||||
| 			echo "<div class=\"alert alert-info\"><strong>Lien de la vidéo déjà envoyée :</strong> <a href=\"$link\">$link</a> (version " . $answer->getVersion() . ")</div>\n"; |  | ||||||
| 			displayVideo($link); |  | ||||||
| 			switch ($answer->getValidation()) { |  | ||||||
| 				case 0: |  | ||||||
| 					echo "<div class=\"alert alert-warning\">La vidéo n'a pas encore été vérifiée par l'équipe d'organisation.</div>"; |  | ||||||
| 					break; |  | ||||||
| 				case 1: |  | ||||||
| 					echo "<div class=\"alert alert-success\">La vidéo a été acceptée par l'équipe d'organisation.</div>"; |  | ||||||
| 					break; |  | ||||||
| 				case -1: |  | ||||||
| 					echo "<div class=\"alert alert-danger\">La vidéo a été rejetée par l'équipe d'organisation.</div>"; |  | ||||||
| 					break; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		if ($answer_validated != null && $answer_validated->getId() != $answer->getId()) { |  | ||||||
| 			$link = $answer_validated->getLink(); |  | ||||||
| 			echo "<hr />\n<div class=\"alert alert-info\">Lien de la dernière vidéo validée : <a href=\"$link\">$link</a></div>\n"; |  | ||||||
| 			displayVideo($link); |  | ||||||
| 		} |  | ||||||
| 		?> |  | ||||||
|  |  | ||||||
|         <form method="POST"> |  | ||||||
|             <input type="hidden" name="team" value="<?= $i + 1 ?>"/> |  | ||||||
|             <div class="form-row"> |  | ||||||
|                 <div class="form-group col-md-12"> |  | ||||||
|                     <label for="link_<?= $i ?>">Lien de la vidéo à soumettre :</label> |  | ||||||
|                     <input class="form-control" type="url" id="link_<?= $i ?>" name="link"/> |  | ||||||
|                 </div> |  | ||||||
|             </div> |  | ||||||
|  |  | ||||||
|             <input type="checkbox" name="valid_link" id="valid_link_<?= $i ?>" required/> <label |  | ||||||
|                     for="valid_link_<?= $i ?>">Je |  | ||||||
|                 confirme que le lien est valide</label><br/> |  | ||||||
|  |  | ||||||
|             <input type="checkbox" name="no_change" id="no_change_<?= $i ?>" required/> <label |  | ||||||
|                     for="no_change_<?= $i ?>">Je m'engage |  | ||||||
|                 à ne pas changer le contenu du lien et de la vidéo</label> |  | ||||||
|  |  | ||||||
|             <input class="btn btn-primary btn-lg btn-block" type="submit" name="upload_answer" |  | ||||||
|                    value="Envoyer la vidéo"/> |  | ||||||
|         </form> |  | ||||||
|         </div> |  | ||||||
| 		<?php |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| require_once "footer.php"; |  | ||||||
| @@ -1,65 +0,0 @@ | |||||||
| <?php |  | ||||||
| require_once "header.php"; |  | ||||||
|  |  | ||||||
| if (!$has_error) { |  | ||||||
| 	if (isset($recuperate_account)) |  | ||||||
| 		echo "<div class=\"alert alert-warning\">Le mail de récupération de mot de passe a bien été envoyé.</div>"; |  | ||||||
|     elseif (isset($reset_password) && isset($_POST["password"])) |  | ||||||
| 		echo "<div class=\"alert alert-success\">Le mot de passe a bien été changé. Vous pouvez désormais vous connecter.</div>"; |  | ||||||
|     elseif (isset($_GET["confirmation-mail"])) |  | ||||||
| 		echo "<div class=\"alert alert-success\">Le mail a bien été renvoyé.</div>"; |  | ||||||
| 	else if (isset($logging_in_user)) { |  | ||||||
| 		echo "<div class=\"alert alert-success\">Connexion réussie !</div>"; |  | ||||||
| 		require_once "footer.php"; |  | ||||||
| 	} else if (isset($_SESSION["user_id"])) { |  | ||||||
| 		echo "<div class=\"alert alert-danger\">Vous êtes déjà connecté !</div>"; |  | ||||||
| 		require_once "footer.php"; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| if (isset($_GET["mdp_oublie"])) { ?> |  | ||||||
|     <form method="POST" class="jumbotron mt-5"> |  | ||||||
|         <h1 class="display-4">Réinitialisation du mot de passe</h1> |  | ||||||
|         <label for="email">E-mail associée au compte :</label> |  | ||||||
|         <input type="email" class="form-control" id="email" name="email" required/> |  | ||||||
|         <input class="btn btn-lg btn-primary btn-block" type="submit" name="forgotten_password" |  | ||||||
|                value="Envoyer l'e-mail de récupération"/> |  | ||||||
|     </form> |  | ||||||
| <?php } elseif (isset($reset_password) && $reset_password->user != null && ($has_error || !isset($_POST["password"]))) { ?> |  | ||||||
|     <form method="POST" class="jumbotron mt-5"> |  | ||||||
|         <h1 class="display-4">Connexion</h1> |  | ||||||
|         <input type="hidden" name="token" value="<?= $_GET["token"] ?>"/> |  | ||||||
|         <div class="form-group"> |  | ||||||
|             <label for="password">Nouveau mot de passe :</label> |  | ||||||
|             <input type="password" id="password" name="password" class="form-control" required/> |  | ||||||
|         </div> |  | ||||||
|         <div class="form-group"> |  | ||||||
|             <label for="confirm_password">Confirmer le mot de passe :</label> |  | ||||||
|             <input type="password" id="confirm_password" name="confirm_password" class="form-control" required/> |  | ||||||
|         </div> |  | ||||||
|         <input type="submit" name="reset_password" class="btn btn-block btn-primary" |  | ||||||
|                value="Changer le mot de passe"/> |  | ||||||
|     </form> |  | ||||||
| <?php } elseif (isset($_GET["confirmation-mail"])) { ?> |  | ||||||
| <?php } else { ?> |  | ||||||
|     <form method="POST" class="jumbotron mt-5"> |  | ||||||
|         <h1 class="display-4">Connexion</h1> |  | ||||||
|         <hr class="mt-2 mb-4"/> |  | ||||||
|         <div class="form-group"> |  | ||||||
|             <label for="email">E-mail :</label> |  | ||||||
|             <input class="form-control" type="email" id="email" name="email" |  | ||||||
|                    value="<?php if (isset($email)) echo $email ?>" required/> |  | ||||||
|         </div> |  | ||||||
|         <div class="form-group"> |  | ||||||
|             <label for="password">Mot de passe :</label> |  | ||||||
|             <input class="form-control" type="password" id="password" name="password" required/> |  | ||||||
|         </div> |  | ||||||
|         <input class="btn btn-primary btn-block" name="login" type="submit" value="Se connecter"/> |  | ||||||
|     </form> |  | ||||||
|     <div class="alert"> |  | ||||||
|         <!--suppress HtmlUnknownTarget --> |  | ||||||
|         <a href="/connexion/mdp-oublie">Mot de passe oublié ?</a> |  | ||||||
|     </div> |  | ||||||
| <?php } ?> |  | ||||||
|  |  | ||||||
| <?php require_once "footer.php" ?> |  | ||||||
| @@ -1,87 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| require_once "header.php"; |  | ||||||
| ?> |  | ||||||
|  |  | ||||||
|     <div class="mt-4 mb-4"> |  | ||||||
|         <h1 class="display-4">Envoyer la vidéo de solution</h1> |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
| <?php if (isset($new_video) && !$has_error) { ?> |  | ||||||
|     <div class="alert alert-success"> |  | ||||||
|         Votre vidéo a bien été envoyée ! |  | ||||||
|     </div> |  | ||||||
| <?php } ?> |  | ||||||
|  |  | ||||||
|     <div class="alert alert-info"> |  | ||||||
|         <ul> |  | ||||||
|             <li>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.</li> |  | ||||||
|             <li>La vidéo doit durer au maximum <strong>8 minutes</strong>.</li> |  | ||||||
|             <li>Un travail de recherche, en équipe sur les problèmes, supervisé par l'encadrant·e, est attendu.</li> |  | ||||||
|             <li>Au début de la vidéo, une brève présentation de l'énoncé est appréciée.</li> |  | ||||||
|             <li>L'équipe doit présenter ses réponses trouvées aux questions de l'énoncé.</li> |  | ||||||
|             <li>Toutes les plateformes d'hébergement vidéo sont supportées. Néanmoins, les plateformes |  | ||||||
|                     <a href="https://vimeo.com/">Viméo</a>, <a href="https://www.youtube.com/">YouTube</a> |  | ||||||
|                     et <a href="https://dailymotion.com/fr">Dailymotion</a> permettent une prévisualisation de la vidéo. |  | ||||||
|                     Cette liste pourra être étendue si besoin est.</li> |  | ||||||
|             <li>Les liens de vos vidéos sont soumis à validation à l'équipe d'organisation.</li> |  | ||||||
|         </ul> |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
|     <div class="alert alert-warning"> |  | ||||||
|         <strong>Date limite de soumission :</strong> <?= formatDate($CONFIG->getEndPhase1Date(), true) ?> |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
| 	<?php if (Phase::getCurrentPhase() == Phase::PHASE12) { ?> |  | ||||||
| 		<div class="alert alert-danger"> |  | ||||||
| 			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 <strong>8 minutes</strong>. |  | ||||||
| 		</div> |  | ||||||
| 	<?php } ?> |  | ||||||
|  |  | ||||||
| <?php |  | ||||||
| if ($video !== null) { |  | ||||||
| 	$link = $video->getLink(); |  | ||||||
| 	echo "<div class=\"alert alert-info\"><strong>Lien de la vidéo déjà envoyée :</strong> <a href=\"$link\">$link</a> (version " . $video->getVersion() . ")</div>\n"; |  | ||||||
| 	displayVideo($link); |  | ||||||
| 	switch ($video->getValidation()) { |  | ||||||
| 		case 0: |  | ||||||
| 			echo "<div class=\"alert alert-warning\">La vidéo n'a pas encore été vérifiée par l'équipe d'organisation.</div>"; |  | ||||||
| 			break; |  | ||||||
| 		case 1: |  | ||||||
| 			echo "<div class=\"alert alert-success\">La vidéo a été acceptée par l'équipe d'organisation.</div>"; |  | ||||||
| 			break; |  | ||||||
| 		case -1: |  | ||||||
| 			echo "<div class=\"alert alert-danger\">La vidéo a été rejetée par l'équipe d'organisation.</div>"; |  | ||||||
| 			break; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| if ($video_validated != null && $video_validated->getId() != $video->getId()) { |  | ||||||
| 	$link = $video_validated->getLink(); |  | ||||||
| 	echo "<hr />\n<div class=\"alert alert-info\">Lien de la dernière vidéo validée : <a href=\"$link\">$link</a></div>\n"; |  | ||||||
| 	displayVideo($link); |  | ||||||
| } |  | ||||||
| ?> |  | ||||||
|  |  | ||||||
|     <hr/> |  | ||||||
|  |  | ||||||
|     <form method="POST"> |  | ||||||
|         <div class="form-row"> |  | ||||||
|             <div class="form-group col-md-12"> |  | ||||||
|                 <label for="link">Lien de la vidéo à soumettre :</label> |  | ||||||
|                 <input class="form-control" type="url" id="link" name="link"/> |  | ||||||
|             </div> |  | ||||||
|         </div> |  | ||||||
|  |  | ||||||
|         <input type="checkbox" name="valid_link" id="valid_link" required/> <label for="valid_link">Je |  | ||||||
|             confirme que le lien est valide</label><br/> |  | ||||||
|  |  | ||||||
|         <input type="checkbox" name="no_change" id="no_change" required/> <label for="no_change">Je m'engage |  | ||||||
|             à ne pas changer le contenu du lien et de la vidéo</label> |  | ||||||
|  |  | ||||||
|         <input class="btn btn-primary btn-lg btn-block" type="submit" name="upload" value="Envoyer la vidéo"/> |  | ||||||
|     </form> |  | ||||||
|  |  | ||||||
| <?php require_once "footer.php"; |  | ||||||
| @@ -1,134 +0,0 @@ | |||||||
| <?php require_once "header.php" ?> |  | ||||||
|  |  | ||||||
|     <div class="mt-4 mb-4"> |  | ||||||
|         <h1 class="display-4">Informations sur l'équipe</h1> |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
|     <div class="alert alert-info"> |  | ||||||
|         <strong>Nom de l'équipe :</strong> <?= $team->getName() ?> |  | ||||||
|     </div> |  | ||||||
|     <div class="alert alert-info"> |  | ||||||
|         <strong>Trigramme :</strong> <?= $team->getTrigram() ?> |  | ||||||
|     </div> |  | ||||||
|     <div class="alert alert-info"> |  | ||||||
|         <?php if (date("Y-m-d H:i:s") < $CONFIG->getInscriptionDate() && $team->getValidationStatus() == ValidationStatus::NOT_READY) { ?> |  | ||||||
|             <label for="problem">Problème :</label> |  | ||||||
|             <form method="POST"> |  | ||||||
|                 <select class="custom-select" id="problem" name="select_problem" onchange="this.form.submit()"> |  | ||||||
|                     <option value="0">Pas de problème choisi</option> |  | ||||||
|                     <?php |  | ||||||
|                     for ($i = 1; $i <= 4; ++$i) { ?> |  | ||||||
|                         <option value="<?= $i ?>" <?= $team->getProblem() == $i ? "selected" : "" ?>> |  | ||||||
|                             Problème <?= $i ?></option> |  | ||||||
|                     <?php } ?> |  | ||||||
|                 </select> |  | ||||||
|             </form> |  | ||||||
|         <?php } else { ?> |  | ||||||
|             <strong>Problème :</strong> <a href="/probleme/<?= $team->getProblem() ?>"> |  | ||||||
|                 <?= $team->getProblem() == 0 ? "Pas de problème choisi" : $team->getProblem() ?> |  | ||||||
|             </a> |  | ||||||
|         <?php } ?> |  | ||||||
|     </div> |  | ||||||
|     <div class="alert alert-<?= $team->getValidationStatus() == ValidationStatus::VALIDATED ? "success" : ($team->getValidationStatus() == ValidationStatus::WAITING ? "warning" : "danger") ?>"> |  | ||||||
|         <strong>Validation de l'équipe |  | ||||||
|             :</strong> <?= ValidationStatus::getTranslatedName($team->getValidationStatus()) ?> |  | ||||||
|     </div> |  | ||||||
|     <div class="alert alert-info"> |  | ||||||
|         <?php |  | ||||||
|         if ($team->getEncadrantId() !== null) { |  | ||||||
|             $encadrant = User::fromId($team->getEncadrantId()); |  | ||||||
|             $id = $encadrant->getId(); |  | ||||||
|             echo "<strong>Encadrant :</strong> <a href=\"$URL_BASE/informations/$id/" . $encadrant->getFirstName() . " " . $encadrant->getSurname() . "\">" . $encadrant->getFirstName() . " " . $encadrant->getSurname() . "</a><br />"; |  | ||||||
|         } |  | ||||||
|         for ($i = 1; $i <= 5; ++$i) { |  | ||||||
|             if ($team->getParticipants()[$i - 1] == NULL) |  | ||||||
|                 continue; |  | ||||||
|             $participant = User::fromId($team->getParticipants()[$i - 1]); |  | ||||||
|             $id = $participant->getId(); |  | ||||||
|             echo "<strong>Participant $i :</strong> <a href=\"$URL_BASE/informations/$id/" . $participant->getFirstName() . " " . $participant->getSurname() . "\">" . $participant->getFirstName() . " " . $participant->getSurname() . "</a><br />"; |  | ||||||
|         } |  | ||||||
|         ?> |  | ||||||
|     </div> |  | ||||||
|     <div class="alert alert-info"> |  | ||||||
|         <strong>Autorise Animath à diffuser les vidéos :</strong> <?= $team->allowPublish() ? "oui" : "non" ?> |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
|     <div class="alert alert-info"> |  | ||||||
|         <a href="mailto:contact@correspondances-maths.fr?<? foreach ($team->getAllEmails() as $email) echo "bcc=" . $email . "&" ?>subject=Correspondances de Jeunes Mathématicien·ne·s" target="_blank">Envoyer un mail à toute l'équipe</a> |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
| <? if ($team->getValidationStatus() == ValidationStatus::VALIDATED && $team->getSolution() != null && $team->getSolution()->getValidation() == ValidationStatus::VALIDATED - 1) { ?> |  | ||||||
|     <hr/> |  | ||||||
|     <!--suppress HtmlUnknownTarget --> |  | ||||||
|     <a href="/suivi-correspondances#team-<?= $team->getTrigram() ?>"> |  | ||||||
|         <button class="btn btn-primary btn-lg btn-block"> |  | ||||||
|             Aller aux vidéos de l'équipe |  | ||||||
|         </button> |  | ||||||
|     </a><br/> |  | ||||||
|     <form method="POST"> |  | ||||||
|         <div class="form-group row"> |  | ||||||
|             <div class="form-group col-md-12"> |  | ||||||
|                 <label for="other_teams">L'équipe va recevoir les vidéos des équipes suivantes (merci d'en |  | ||||||
|                     sélectionner exactement 2) :</label> |  | ||||||
|                 <select class="custom-select" id="other_teams" name="other_teams[]" |  | ||||||
|                         multiple <?= Phase::getCurrentPhase() >= Phase::PHASE2 ? "disabled" : "" ?>> |  | ||||||
|                     <?php |  | ||||||
|                     /** @var Team $other_team */ |  | ||||||
|                     foreach ($other_teams as $other_team) { |  | ||||||
|                         if ($other_team->getId() == $team->getId()) |  | ||||||
|                             continue; |  | ||||||
|  |  | ||||||
|                         $team_name = $other_team->getName() . " (" . $other_team->getTrigram() . ")"; |  | ||||||
|                         $team_id = $other_team->getId(); |  | ||||||
|                         echo "<option value=\"$team_id\" " . (in_array($other_team->getId(), $team->getVideoTeamIds()) ? "selected" : "") . ">$team_name</option>\n"; |  | ||||||
|                     } |  | ||||||
|                     ?> |  | ||||||
|                 </select> |  | ||||||
|             </div> |  | ||||||
|         </div> |  | ||||||
|         <div class="form-group row"> |  | ||||||
|             <?php if (Phase::getCurrentPhase() < Phase::PHASE2) { ?> |  | ||||||
|                 <input type="submit" class="btn btn-secondary btn-lg btn-block" name="update_video_teams" |  | ||||||
|                        value="Mettre à jour"/> |  | ||||||
|             <?php } ?> |  | ||||||
|         </div> |  | ||||||
|     </form> |  | ||||||
| <?php } ?> |  | ||||||
|  |  | ||||||
|     <hr/> |  | ||||||
|  |  | ||||||
|     <h2>Autorisations de droit à l'image</h2> |  | ||||||
|  |  | ||||||
| <?php printDocuments($documents) ?> |  | ||||||
|  |  | ||||||
|     <form method="POST"> |  | ||||||
|         <input type="submit" class="btn btn-secondary btn-lg btn-block" name="download_zip" |  | ||||||
|                value="Télécharger l'archive"/> |  | ||||||
|     </form> |  | ||||||
|  |  | ||||||
| <?php if ($team->getValidationStatus() == ValidationStatus::WAITING) { ?> |  | ||||||
|     <hr/> |  | ||||||
|     <form method="POST"> |  | ||||||
|         <div class="form-group row"> |  | ||||||
|             <label for="message">Message à adresser à l'équipe :</label> |  | ||||||
|             <textarea class="form-control" id="message" name="message"></textarea> |  | ||||||
|         </div> |  | ||||||
|  |  | ||||||
|         <div class="form-group"> |  | ||||||
|             <div class="form-group row col-mod-6"> |  | ||||||
|                 <input type="submit" class="btn btn-secondary btn-lg btn-block" name="unvalidate" |  | ||||||
|                        value="Refuser l'équipe"/> |  | ||||||
|                 <input type="submit" class="btn btn-primary btn-lg btn-block" name="validate" value="Valider l'équipe"/> |  | ||||||
|             </div> |  | ||||||
|         </div> |  | ||||||
|     </form> |  | ||||||
|     <?php |  | ||||||
| } elseif ($team->getValidationStatus() == ValidationStatus::NOT_READY) { ?> |  | ||||||
|     <hr/> |  | ||||||
|     <form method="POST"> |  | ||||||
|         <input type="submit" class="btn btn-primary btn-lg btn-block" name="delete_team" value="Supprimer l'équipe" |  | ||||||
|                style="background-color: #ff2e34"/> |  | ||||||
|     </form> |  | ||||||
| <?php } |  | ||||||
|  |  | ||||||
| require_once "footer.php" ?> |  | ||||||
| @@ -1,33 +0,0 @@ | |||||||
| <?php |  | ||||||
| require_once "header.php"; |  | ||||||
| ?> |  | ||||||
|  |  | ||||||
|     <div class="mt-4 mb-4"> |  | ||||||
|         <h1 class="display-4">Exporter les données</h1> |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
|     <form method="POST"> |  | ||||||
|         <input class="btn btn-primary btn-lg btn-block" type="submit" name="export_user_data" |  | ||||||
|                value="Exporter les données utilisateurs"/> |  | ||||||
|     </form> |  | ||||||
|  |  | ||||||
|     <hr/> |  | ||||||
|  |  | ||||||
|     <form method="POST"> |  | ||||||
|         <input class="btn btn-primary btn-lg btn-block" type="submit" name="export_team_data" |  | ||||||
|                value="Exporter les données équipes"/> |  | ||||||
|     </form> |  | ||||||
|  |  | ||||||
|     <hr/> |  | ||||||
|  |  | ||||||
|     <form method="POST"> |  | ||||||
|         <input class="btn btn-primary btn-lg btn-block" type="submit" name="export_problems_data" |  | ||||||
|                value="Exporter les données problèmes"/> |  | ||||||
|     </form> |  | ||||||
|  |  | ||||||
|     <hr /> |  | ||||||
|  |  | ||||||
|     <h4><em>Ce site a enregistré <?= $CONFIG->getViews() ?> visites.</em></h4> |  | ||||||
|  |  | ||||||
| <?php |  | ||||||
| require_once "footer.php"; |  | ||||||
| @@ -1,18 +0,0 @@ | |||||||
| <div class="mt-4 mb-4"> |  | ||||||
| </div> |  | ||||||
| </div> |  | ||||||
|  |  | ||||||
| <footer> |  | ||||||
|     <hr/> |  | ||||||
|     <div class="container.fluid"> |  | ||||||
|         <div class="alert alert-light inner"> |  | ||||||
|             <em>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 <a href="mailto:contact@correspondances-maths.fr">contact@correspondances-maths.fr</a>.</em><br/> |  | ||||||
|             © <?= date("Y") ?> Correspondances de Jeunes Mathématicien·ne·s |  | ||||||
|         </div> |  | ||||||
|     </div> |  | ||||||
| </footer> |  | ||||||
| </body> |  | ||||||
| </html> |  | ||||||
| <?php exit() ?> |  | ||||||
| @@ -1,177 +0,0 @@ | |||||||
| <?php $CONFIG->incrViews() ?> |  | ||||||
|  |  | ||||||
| <!DOCTYPE html> |  | ||||||
| <html lang="fr"> |  | ||||||
| <head> |  | ||||||
|     <meta charset="UTF-8"> |  | ||||||
|     <meta name="description" content="Inscrivez-vous pour les Correspondances des Jeunes Mathématicien·ne·s <?= $YEAR . " - " . ($YEAR + 1) ?> !"> |  | ||||||
|     <meta name="keywords" content="Correspondances,Jeunes,Mathématicien·ne·s,Mathématiciens,Mathématiciennes,Corres2Math,Inscription,TFJM²,TFJM"> |  | ||||||
|     <meta name="author" content="Yohann D'ANELLO (yohann.danello[at]animath.fr)"> |  | ||||||
|     <meta name="viewport" content="width=device-width, initial-scale=1.0"> |  | ||||||
|     <meta name="google-site-verification" content="nTgyZnU1Uw0OYaAX-TMg-5hVIKkeKAYtj2sNQRDz_sQ"> |  | ||||||
|     <title>Site d'inscription pour les Correspondances des Jeunes Mathématicien·ne·s <?= $YEAR . " - " . ($YEAR + 1) ?></title> |  | ||||||
|     <link rel="stylesheet" type="text/css" href="/style.css"> |  | ||||||
|     <link REL="shortcut icon" href="/favicon.ico"> |  | ||||||
|  |  | ||||||
|     <!--  Bootstrap  --> |  | ||||||
|     <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" |  | ||||||
|           integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> |  | ||||||
| </head> |  | ||||||
|  |  | ||||||
| <body> |  | ||||||
| <div class="container.fluid bg-light"> |  | ||||||
|     <nav class="navbar navbar-expand-lg navbar-light"> |  | ||||||
|         <div class="container"> |  | ||||||
|             <a class="navbar-brand" href="https://correspondances-maths.fr/" target="_blank"> |  | ||||||
|                 <img src="/logo.png" alt="Logo Corres2Mat" id="navbar-logo"> |  | ||||||
|             </a> |  | ||||||
|             <ul class="navbar-nav mr-auto"> |  | ||||||
|                 <li class="nav-item active"> |  | ||||||
|                     <a class="nav-link" href="/">Accueil</a> |  | ||||||
|                 </li> |  | ||||||
|                 <li class="nav-item active"> |  | ||||||
|                     <a class="nav-link" href="/calendrier">Calendrier</a> |  | ||||||
|                 </li> |  | ||||||
| 				<?php if (isset($_SESSION["user_id"])) { ?> |  | ||||||
|                     <li class="nav-item active"> |  | ||||||
|                         <a class="nav-link" href="/mon-compte">Mon compte</a> |  | ||||||
|                     </li> |  | ||||||
| 					<?php if ($_SESSION["role"] == Role::ENCADRANT || $_SESSION["role"] == Role::PARTICIPANT) { ?> |  | ||||||
| 						<?php if ($_SESSION["team"] == NULL || $_SESSION["role"] == Role::ENCADRANT) { |  | ||||||
| 							if (date("Y-m-d H:i:s") < $CONFIG->getInscriptionDate()) { ?> |  | ||||||
|                                 <li class="nav-item active"><a class="nav-link" href="/ajouter-equipe"> |  | ||||||
|                                         Ajouter une équipe</a> |  | ||||||
|                                 </li> |  | ||||||
|                                 <li class="nav-item active"><a class="nav-link" href="/rejoindre-equipe"> |  | ||||||
|                                         Rejoindre une équipe</a> |  | ||||||
|                                 </li> |  | ||||||
| 							<?php } |  | ||||||
| 						} |  | ||||||
| 						{ |  | ||||||
| 						    /** |  | ||||||
|                             * @var Team $_team |  | ||||||
|                             */ |  | ||||||
| 						    foreach ($_SESSION["teams"] as $_team) { |  | ||||||
| 						        $appendice = $_SESSION["role"] == Role::ENCADRANT ? "/" . $_team->getTrigram() : ""; |  | ||||||
| 						        ?> |  | ||||||
| 						        <li class="nav-item active"> |  | ||||||
|                             <a class="nav-link">Équipe <?= $_team->getTrigram() ?></a> |  | ||||||
|                             <ul class="deroule"> |  | ||||||
|                                 <li class="nav-item active"> |  | ||||||
|                                     <a class="nav-link" href="/mon-equipe<?= $appendice ?>">Informations sur l'équipe</a> |  | ||||||
|                                 </li> |  | ||||||
|                                 <?php if ($_team->getValidationStatus() == ValidationStatus::VALIDATED) { ?> |  | ||||||
|                                 <li class="nav-item active"><a class="nav-link" href="/ma-participation<?= $appendice ?>">Ma participation</a></li> |  | ||||||
|                                 <?php |  | ||||||
| 								switch (Phase::getCurrentPhase()) { |  | ||||||
| 									case Phase::PHASE1: |  | ||||||
| 									case Phase::PHASE12: |  | ||||||
| 									    if (Phase::getCurrentPhase() == Phase::PHASE12) { |  | ||||||
| 									        if (Video::getVideo(Reason::SOLUTION, $_team) == NULL) |  | ||||||
| 									            break; |  | ||||||
| 									        else if (Video::getVideo(Reason::SOLUTION, $_team, ValidationStatus::WAITING) != NULL) |  | ||||||
| 									            break; |  | ||||||
| 									    } |  | ||||||
| 									    ?> |  | ||||||
|                                         <li class="nav-item active"><a class="nav-link" href="/envoyer-video-1<?= $appendice ?>"> |  | ||||||
|                                                 Envoyer ma vidéo (phase 1)</a> |  | ||||||
|                                         </li> |  | ||||||
| 										<?php break; |  | ||||||
| 									case Phase::PHASE2: ?> |  | ||||||
|                                         <li class="nav-item active"><a class="nav-link" href="/poser-questions-2<?= $appendice ?>"> |  | ||||||
|                                                 Poser des questions (phase 2)</a> |  | ||||||
|                                         </li> |  | ||||||
| 										<?php break; |  | ||||||
| 									case Phase::PHASE3: ?> |  | ||||||
|                                         <li class="nav-item active"><a class="nav-link" href="/repondre-questions-3<?= $appendice ?>"> |  | ||||||
|                                                 Répondre aux questions (phase 3)</a> |  | ||||||
|                                         </li> |  | ||||||
| 										<?php break; |  | ||||||
| 									case Phase::PHASE4: ?> |  | ||||||
|                                         <li class="nav-item active"><a class="nav-link" href="/commenter-echange-4<?= $appendice ?>"> |  | ||||||
|                                                 Commenter l'échange (phase 4)</a></li> |  | ||||||
| 										<?php break; |  | ||||||
| 								} |  | ||||||
| 							} ?> |  | ||||||
|                             </ul> |  | ||||||
|                         </li> |  | ||||||
| 						<?php } ?> |  | ||||||
| 						<?php } ?> |  | ||||||
| 					<?php } ?> |  | ||||||
| 					<?php if ($_SESSION["role"] == Role::ADMIN) { ?> |  | ||||||
|                         <li class="nav-item active"> |  | ||||||
|                             <a class="nav-link">Liste des équipes</a> |  | ||||||
|                             <ul class="deroule"> |  | ||||||
|                                 <li class="nav-item active"><a class="nav-link" href="/probleme/1">Problème 1</a></li> |  | ||||||
|                                 <li class="nav-item active"><a class="nav-link" href="/probleme/2">Problème 2</a></li> |  | ||||||
|                                 <li class="nav-item active"><a class="nav-link" href="/probleme/3">Problème 3</a></li> |  | ||||||
|                                 <li class="nav-item active"><a class="nav-link" href="/probleme/4">Problème 4</a></li> |  | ||||||
|                                 <li class="nav-item active"><a class="nav-link" href="/probleme/0">Équipes sans problème</a></li> |  | ||||||
|                                 <li class="nav-item active"><a class="nav-link" href="/profils-orphelins">Profils orphelins</a></li> |  | ||||||
|                                 <li class="nav-item active"><a class="nav-link" href="/profils">Tous les profils</a></li> |  | ||||||
|                                 <li class="nav-item active"><a class="nav-link" href="/admins">Administrateurs</a></li> |  | ||||||
|                             </ul> |  | ||||||
|                         </li> |  | ||||||
|                         <li class="nav-item active"> |  | ||||||
|                             <a class="nav-link" href="/ajouter-admin">Ajouter un admin</a> |  | ||||||
|                         </li> |  | ||||||
|                         <li class="nav-item active"> |  | ||||||
|                             <a class="nav-link">Suivi des Correspondances</a> |  | ||||||
|                             <ul class="deroule"> |  | ||||||
|                                 <li class="nav-item active"><a class="nav-link" href="/suivi-correspondances/1">Problème 1</a></li> |  | ||||||
|                                 <li class="nav-item active"><a class="nav-link" href="/suivi-correspondances/2">Problème 2</a></li> |  | ||||||
|                                 <li class="nav-item active"><a class="nav-link" href="/suivi-correspondances/3">Problème 3</a></li> |  | ||||||
|                                 <li class="nav-item active"><a class="nav-link" href="/suivi-correspondances/4">Problème 4</a></li> |  | ||||||
|                                 <li class="nav-item active"><a class="nav-link" href="/suivi-correspondances">Tous les problèmes</a></li> |  | ||||||
|                             </ul> |  | ||||||
|                         </li> |  | ||||||
|                         <li class="nav-item active"> |  | ||||||
|                             <a class="nav-link" href="/exporter-donnees">Exporter les données</a> |  | ||||||
|                         </li> |  | ||||||
| 					<?php } ?> |  | ||||||
| 				<?php } ?> |  | ||||||
|             </ul> |  | ||||||
|  |  | ||||||
|             <ul class="navbar-nav"> |  | ||||||
|                 <?php if (isset($_SESSION["admin"])) { ?> |  | ||||||
|                     <li class="nav-item active"> |  | ||||||
|                         <a class="nav-link" href="/?view-as-admin">Retourner en vue administrateur</a> |  | ||||||
|                     </li> |  | ||||||
|                 <?php } ?> |  | ||||||
| 				<?php if (isset($_SESSION["user_id"])) { ?> |  | ||||||
|                     <li class="nav-item active"> |  | ||||||
|                         <a class="nav-link" href="/deconnexion">Déconnexion</a> |  | ||||||
|                     </li> |  | ||||||
| 				<?php } else { ?> |  | ||||||
| 					<?php if (date("Y-m-d H:i:s") < $CONFIG->getInscriptionDate()) { ?> |  | ||||||
|                         <li class="nav-item active"> |  | ||||||
|                             <a class="nav-link" href="/inscription">Inscription</a> |  | ||||||
|                         </li> |  | ||||||
| 					<?php } ?> |  | ||||||
|                     <li class="nav-item active"> |  | ||||||
|                         <a class="nav-link" href="/connexion">Connexion</a> |  | ||||||
|                     </li> |  | ||||||
| 				<?php } ?> |  | ||||||
|             </ul> |  | ||||||
|         </div> |  | ||||||
|     </nav> |  | ||||||
| </div> |  | ||||||
|  |  | ||||||
| <div class="container"> |  | ||||||
|     <div class="mt-4 mb-4"> |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
| <?php |  | ||||||
| if (isset($has_error) && $has_error) { ?> |  | ||||||
|     <div class="alert alert-danger"> |  | ||||||
|         <strong>Erreur :</strong> <?= $error_message ?> |  | ||||||
|     </div> |  | ||||||
| <?php } |  | ||||||
|  |  | ||||||
| /* if (!isset($_SESSION["role"]) || $_SESSION["role"] != Role::ADMIN && !isset($_SESSION["admin"])) { ?> |  | ||||||
|     <div class="alert alert-warning"> |  | ||||||
|         Le site est actuellement en maintenance. Veuillez réessayer ultérieurement. |  | ||||||
|     </div> |  | ||||||
|     <?php |  | ||||||
|     exit(-1); |  | ||||||
| }*/ |  | ||||||
| @@ -1,54 +0,0 @@ | |||||||
| <div> |  | ||||||
|  |  | ||||||
|     <div class="jumbotron bg-white"> |  | ||||||
|         <div class="row"> |  | ||||||
|             <h1 class="display-3"> |  | ||||||
|                 Bienvenue sur le site d'inscription aux <a href="https://correspondances-maths.fr/" target="_blank"> |  | ||||||
|                     Correspondances des Jeunes Mathématicien·ne·s</a> ! |  | ||||||
|             </h1> |  | ||||||
|         </div> |  | ||||||
|     </div> |  | ||||||
|     <div class="row jumbotron bg-white"> |  | ||||||
|         <div class="col-sm"> |  | ||||||
|             <h3> |  | ||||||
|                 Tu souhaites participer aux Correspondances ? |  | ||||||
|                 <br/> |  | ||||||
|                 Ton équipe est déjà formée ? |  | ||||||
|             </h3> |  | ||||||
|         </div> |  | ||||||
|         <div class="col-sm text-right"> |  | ||||||
|             <div class="btn-group-vertical"> |  | ||||||
|                 <a class="btn btn-primary btn-lg" href="/inscription" role="button">Inscris-toi maintenant !</a> |  | ||||||
|                 <a class="btn btn-light btn-lg" href="/connexion" role="button">J'ai déjà un compte</a> |  | ||||||
|             </div> |  | ||||||
|         </div> |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
|     <div class="jumbotron"> |  | ||||||
|         <h5 class="display-4">Comment ça marche ?</h5> |  | ||||||
|         <p> |  | ||||||
|             Pour participer aux Correspondances, il suffit de créer un compte sur la rubrique <strong>Inscription</strong>. |  | ||||||
|             Vous devrez ensuite confirmer votre adresse e-mail. |  | ||||||
|         </p> |  | ||||||
|  |  | ||||||
|         <p> |  | ||||||
|             Vous pouvez accéder à votre compte via la rubrique <b>Connexion</b>. 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. |  | ||||||
|         </p> |  | ||||||
|  |  | ||||||
|         <div class="alert alert-warning"> |  | ||||||
|             <strong>Attention aux dates !</strong> Si vous ne finalisez pas votre inscription dans le délai indiqué, vous |  | ||||||
|             ne pourrez malheureusement pas participer aux Correspondances. |  | ||||||
|         </div> |  | ||||||
|  |  | ||||||
|         <div class="alert alert-info"> |  | ||||||
|             Si votre équipe est déjà formée mais que vous peinez à trouver un encadrant, n'hésitez pas à nous contacter à l'adresse |  | ||||||
|             <a href="mailto:contact@correspondances-maths.fr">contact@correspondances-maths.fr</a> pour que nous vous aidions à |  | ||||||
|             vous mettre éventuellement en contact avec un encadrant de votre région. |  | ||||||
|         </div> |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
| </div> |  | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user