Restart the project in Django

This commit is contained in:
Yohann D'ANELLO 2020-09-20 22:31:37 +02:00
parent f341764d0b
commit c882d1ac7a
135 changed files with 1694 additions and 6995 deletions

45
.gitignore vendored
View File

@ -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/

View File

@ -1,4 +0,0 @@
Options +FollowSymlinks
Options -Indexes
RewriteEngine On
RewriteRule ^(.*)$ dispatcher.php?path=$1 [QSA,L]

View File

@ -1,39 +1,31 @@
FROM php:7.3-apache as plateforme-builder
FROM python:3-alpine
# Enabling apache rewrite mod
RUN a2enmod rewrite
ENV PYTHONUNBUFFERED 1
RUN apt clean && apt update && apt upgrade -y
# Install LaTeX requirements
RUN apk add --no-cache gettext texlive nginx gcc libc-dev libffi-dev postgresql-dev mariadb-connector-c-dev
# Install MySQL drivers
RUN docker-php-ext-install pdo_mysql \
&& docker-php-ext-enable pdo_mysql
RUN apk add --no-cache bash
# Install zip utilities
RUN apt install -y libzip-dev zip \
&& docker-php-ext-configure zip --with-libzip \
&& docker-php-ext-install zip \
&& docker-php-ext-enable zip
RUN mkdir /code
WORKDIR /code
COPY requirements.txt /code/requirements.txt
RUN pip install -r requirements.txt --no-cache-dir
# Setup locales
RUN apt install locales locales-all -y && locale-gen fr_FR.UTF-8
ENV LANG fr_FR.UTF-8
ENV LANGUAGE fr_FR:fr
ENV LC_ALL fr_FR.UTF-8
COPY . /code/
# Setup timezone
RUN echo Europe/Paris > /etc/timezone \
&& ln -sf /usr/share/zoneinfo/Europe/Paris /etc/localtime \
&& dpkg-reconfigure -f noninteractive tzdata
# Configure nginx
RUN mkdir /run/nginx
RUN ln -sf /dev/stdout /var/log/nginx/access.log && ln -sf /dev/stderr /var/log/nginx/error.log
RUN ln -sf /code/nginx_corres2math.conf /etc/nginx/conf.d/corres2math.conf
RUN rm /etc/nginx/conf.d/default.conf
# Setup mailing
RUN apt install -yq msmtp ca-certificates
COPY setup/msmtprc /etc/msmtprc
RUN echo "sendmail_path=msmtp -t" >> /usr/local/etc/php/conf.d/php-sendmail.ini
RUN cp /code/corres2math.cron /etc/crontabs/corres2math
# Setting environment
ENV CORRES2MATH_LOCAL_PATH /var/www/html
ENV CORRES2MATH_MAIL_DOMAIN correspondances-maths.fr
ENV CORRES2MATH_URL_BASE https://inscription.correspondances-maths.fr
# With a bashrc, the shell is better
RUN ln -s /code/.bashrc /root/.bashrc
RUN chmod 0777 /var/www/html
ENTRYPOINT ["/code/entrypoint.sh"]
EXPOSE 80
CMD ["./manage.py", "shell_plus", "--ptpython"]

64
README.md Normal file
View 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
View File

@ -0,0 +1 @@
default_app_config = 'api.apps.APIConfig'

10
apps/api/apps.py Normal file
View 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
View 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
View 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
View 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.

Before

Width:  |  Height:  |  Size: 8.6 KiB

View File

@ -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
View 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
View File

16
corres2math/asgi.py Normal file
View 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
View 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

View 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
View 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 *

View 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'

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

35
corres2math/urls.py Normal file
View 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
View 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()

View File

@ -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
View 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

View 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
View 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
View 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
View 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

View File

@ -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";

View File

@ -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";

View File

@ -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;
}
}

View File

@ -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";
}
}
}

View File

@ -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]);
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}

View File

@ -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");

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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();

View File

@ -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>";
}
}

View File

@ -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);
}
}

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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 "";
}

View File

@ -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";

View File

@ -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" ?>

View File

@ -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" ?>

View File

@ -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";

View File

@ -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";

View File

@ -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" ?>

View File

@ -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";

View File

@ -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" ?>

View File

@ -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";

View File

@ -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() ?>

View File

@ -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);
}*/

View File

@ -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