Commit f4549210 authored by Florent Chehab's avatar Florent Chehab

馃帀 feat(beta) 馃帀 got ready, i.e. TWEAKS

Beta time has come ! 馃帀

WARNING: migrations have been reset one last time!

This MR concerns tones of little tweaks:

Reviewed:
* model moderation levels
* serializers.meta.fields value
* Viewset permissions
* on_delete values

Changed:
* Update dark theme color
* Added load prod base script
* beta logo on website
* Added missing about project markdown
* Added RGPD notice to all forms
* Put media files in a docker volume
* More frequent currency exhange rates update

Fixed:
* Front handling of scholarships
* Currencies conversion in the front
* Front theme icons color
* No default networks in prod docker compose to prevent nasty VM routing

Closes #135 #119 #96
parent abbba24b
Pipeline #42771 passed with stages
in 3 minutes and 54 seconds
......@@ -18,6 +18,9 @@ down_dev:
init_dev_data:
docker-compose exec backend sh -c "cd backend && ./manage.py shell < init_dev_data.py"
init_prod_data:
docker-compose $(prod_yml) exec backend sh -c "cd backend && ./manage.py shell < init_prod_data.py"
docker-pull:
docker-compose pull
......@@ -64,7 +67,8 @@ prod_yml = -f ./server/docker-compose.prod.yml
prod: setup
$(info In production, we need to reset the webpack-stats.json file to make sure the front is up-to-date)
sudo rm -f frontend/webpack-stats.json
docker-compose $(prod_yml) up --build -d
# Need higher compose timeout as the big map container can take a lot of time to wake up
COMPOSE_HTTP_TIMEOUT=600 docker-compose $(prod_yml) up --build -d
down_prod:
docker-compose $(prod_yml) down
......
......@@ -30,3 +30,21 @@ def load_all():
LoadUniversityEx(admin).load()
LoadRecommendationLists(admin).load()
LoadSiteInformation(admin).load()
def load_prod():
"""
for PRODUCTION ENV
Function to load all the initial data in the app
"""
with reversion.create_revision():
LoadGroups()
admin = LoadBaseUsers().get_admin()
LoadCurrencies(admin).load()
LoadCountries(admin).load()
LoadLanguages().load()
LoadSiteInformation(admin).load()
# LoadUniversities(admin).load()
# LoadUniversityEx(admin).load()
# LoadRecommendationLists(admin).load()
......@@ -19,4 +19,6 @@ class LoadLanguages(LoadGeneric):
reader = csv.reader(csvfile, quotechar='"')
next(reader)
for r in reader:
Language.objects.create(code_iso=r[0], name=r[1])
Language.objects.update_or_create(
code_iso=r[0], defaults=dict(name=r[1])
)
# Generated by Django 2.1.7 on 2019-06-29 09:22
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [("backend_app", "0002_auto_20190626_2310")]
operations = [
migrations.CreateModel(
name="Partner",
fields=[
("utc_id", models.IntegerField(primary_key=True, serialize=False)),
("univ_name", models.CharField(max_length=80)),
("address1", models.CharField(max_length=100, null=True)),
("address2", models.CharField(max_length=100, null=True)),
("zipcode", models.CharField(max_length=40, null=True)),
("city", models.CharField(max_length=40)),
("country", models.CharField(max_length=50)),
("iso_code", models.CharField(max_length=2)),
],
options={"abstract": False},
),
migrations.AlterUniqueTogether(name="specialty", unique_together=set()),
migrations.RemoveField(model_name="specialty", name="department"),
migrations.RenameField(
model_name="exchange", old_name="dual_degree", new_name="double_degree"
),
migrations.RemoveField(model_name="course", name="course_id"),
migrations.RemoveField(model_name="course", name="nb_credit"),
migrations.RemoveField(model_name="exchange", name="utc_departure_id"),
migrations.RemoveField(
model_name="offer", name="nb_seats_offered_double_degree"
),
migrations.RemoveField(model_name="offer", name="nb_seats_offered_exchange"),
migrations.RemoveField(model_name="university", name="utc_id"),
migrations.AddField(
model_name="course",
name="ects",
field=models.DecimalField(
decimal_places=2, default=0, max_digits=7, null=True
),
),
migrations.AddField(
model_name="course",
name="utc_id",
field=models.IntegerField(default=1, unique=True),
preserve_default=False,
),
migrations.AddField(
model_name="exchange",
name="utc_id",
field=models.IntegerField(default=1, unique=True),
preserve_default=False,
),
migrations.AddField(
model_name="exchange",
name="utc_partner_id",
field=models.IntegerField(null=True),
),
migrations.AddField(
model_name="offer",
name="comment",
field=models.TextField(max_length=500, null=True),
),
migrations.AddField(
model_name="offer",
name="double_degree",
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name="offer",
name="is_master_offered",
field=models.BooleanField(default=False, null=True),
),
migrations.AddField(
model_name="offer",
name="utc_partner_id",
field=models.IntegerField(default=1),
preserve_default=False,
),
migrations.AlterField(
model_name="course",
name="code",
field=models.CharField(max_length=10, null=True),
),
migrations.AlterField(
model_name="course",
name="title",
field=models.CharField(blank=True, default="", max_length=200),
),
migrations.AlterField(
model_name="exchange",
name="semester",
field=models.CharField(
choices=[("a", "autumn"), ("p", "spring")],
default="a",
max_length=5,
null=True,
),
),
migrations.AlterField(
model_name="exchange",
name="student",
field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
migrations.AlterField(
model_name="exchange",
name="student_minor",
field=models.CharField(max_length=47, null=True),
),
migrations.AlterField(
model_name="exchange",
name="student_option",
field=models.CharField(max_length=7, null=True),
),
migrations.AlterField(
model_name="exchange",
name="university",
field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.PROTECT,
to="backend_app.University",
),
),
migrations.AlterField(
model_name="exchange",
name="year",
field=models.PositiveIntegerField(default=2018, null=True),
),
migrations.AlterField(
model_name="exchangefeedback",
name="university",
field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.PROTECT,
to="backend_app.University",
),
),
migrations.AlterField(
model_name="offer",
name="nb_seats_offered",
field=models.PositiveIntegerField(null=True),
),
migrations.AlterField(
model_name="offer",
name="semester",
field=models.CharField(
choices=[("a", "autumn"), ("p", "spring")],
default="a",
max_length=2,
null=True,
),
),
migrations.RemoveField(model_name="offer", name="specialties"),
migrations.AddField(
model_name="offer",
name="specialties",
field=models.CharField(max_length=4000, null=True),
),
migrations.AlterField(
model_name="offer",
name="university",
field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.PROTECT,
to="backend_app.University",
),
),
migrations.AlterField(
model_name="offer",
name="year",
field=models.PositiveIntegerField(default=2018, null=True),
),
migrations.DeleteModel(name="Department"),
migrations.DeleteModel(name="Specialty"),
migrations.AddField(
model_name="partner",
name="university",
field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.PROTECT,
related_name="corresponding_utc_partners",
to="backend_app.University",
),
),
migrations.AddField(
model_name="exchange",
name="partner",
field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.PROTECT,
to="backend_app.Partner",
),
),
migrations.AddField(
model_name="offer",
name="partner",
field=models.ForeignKey(
default=1,
on_delete=django.db.models.deletion.PROTECT,
to="backend_app.Partner",
),
preserve_default=False,
),
]
# Generated by Django 2.1.7 on 2019-06-29 17:41
import django.core.validators
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [("backend_app", "0003_auto_20190629_1122")]
operations = [
migrations.AddField(
model_name="course",
name="unlinked",
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name="coursefeedback",
name="untouched",
field=models.BooleanField(default=True),
),
migrations.AddField(
model_name="exchange",
name="unlinked",
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name="exchangefeedback",
name="untouched",
field=models.BooleanField(default=True),
),
migrations.AlterField(
model_name="course",
name="code",
field=models.CharField(blank=True, max_length=10, null=True),
),
migrations.AlterField(
model_name="exchange",
name="semester",
field=models.CharField(
choices=[("A", "autumn"), ("P", "spring")],
default="A",
max_length=1,
null=True,
),
),
migrations.AlterField(
model_name="exchange",
name="student_major",
field=models.CharField(blank=True, max_length=20),
),
migrations.AlterField(
model_name="exchange",
name="student_minor",
field=models.CharField(blank=True, max_length=47, null=True),
),
migrations.AlterField(
model_name="exchange",
name="student_option",
field=models.CharField(blank=True, max_length=7, null=True),
),
migrations.AlterField(
model_name="exchangefeedback",
name="academical_level_appreciation",
field=models.IntegerField(
default=0,
validators=[
django.core.validators.MinValueValidator(-5),
django.core.validators.MaxValueValidator(5),
],
),
),
migrations.AlterField(
model_name="exchangefeedback",
name="cultural_interest",
field=models.IntegerField(
default=0,
validators=[
django.core.validators.MinValueValidator(-5),
django.core.validators.MaxValueValidator(5),
],
),
),
migrations.AlterField(
model_name="exchangefeedback",
name="foreign_student_welcome",
field=models.IntegerField(
default=0,
validators=[
django.core.validators.MinValueValidator(-5),
django.core.validators.MaxValueValidator(5),
],
),
),
migrations.AlterField(
model_name="offer",
name="semester",
field=models.CharField(
choices=[("A", "autumn"), ("P", "spring")],
default="A",
max_length=2,
null=True,
),
),
migrations.AlterField(
model_name="partner",
name="address1",
field=models.CharField(blank=True, max_length=100, null=True),
),
migrations.AlterField(
model_name="partner",
name="address2",
field=models.CharField(blank=True, max_length=100, null=True),
),
migrations.AlterUniqueTogether(
name="offer", unique_together={("utc_partner_id", "year", "semester")}
),
]
# Generated by Django 2.1.7 on 2019-06-30 07:37
import backend_app.fields
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [("backend_app", "0004_auto_20190629_1941")]
operations = [
migrations.CreateModel(
name="UnivMajorMinors",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("major", models.CharField(blank=True, max_length=20, null=True)),
("minors", backend_app.fields.JSONField(default=list)),
(
"university",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="backend_app.University",
),
),
],
),
migrations.AddField(
model_name="exchange",
name="student_major_and_semester",
field=models.CharField(blank=True, max_length=20),
),
migrations.AddField(
model_name="exchange",
name="student_semester",
field=models.IntegerField(null=True),
),
migrations.AlterField(
model_name="exchange",
name="student_major",
field=models.CharField(blank=True, max_length=20, null=True),
),
migrations.AlterUniqueTogether(
name="univmajorminors", unique_together={("university", "major")}
),
]
# Generated by Django 2.1.7 on 2019-06-30 09:19
import backend_app.models.abstract.essentialModule
from django.conf import settings
import django.core.validators
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("backend_app", "0005_auto_20190630_0937"),
]
operations = [
migrations.CreateModel(
name="SharedUnivFeedback",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("updated_on", models.DateTimeField(null=True)),
("moderated_on", models.DateTimeField(null=True)),
(
"obj_moderation_level",
models.SmallIntegerField(
default=0,
validators=[
django.core.validators.MinValueValidator(0),
backend_app.models.abstract.essentialModule.validate_obj_model_lv,
],
),
),
("has_pending_moderation", models.BooleanField(default=False)),
("nb_versions", models.PositiveIntegerField(default=0)),
("comment", models.CharField(blank=True, default="", max_length=5000)),
(
"moderated_by",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="+",
to=settings.AUTH_USER_MODEL,
),
),
(
"university",
models.OneToOneField(
null=True,
on_delete=django.db.models.deletion.PROTECT,
to="backend_app.University",
),
),
(
"updated_by",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="+",
to=settings.AUTH_USER_MODEL,
),
),
],
options={"abstract": False},
),
migrations.AlterField(
model_name="exchange",
name="student",
field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="exchanges",
to=settings.AUTH_USER_MODEL,
),
),
]
# Generated by Django 2.1.7 on 2019-06-30 15:53
import backend_app.fields
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [("backend_app", "0006_auto_20190630_1119")]
operations = [
migrations.RenameField(
model_name="offer", old_name="specialties", new_name="majors"
),
migrations.AddField(
model_name="university",
name="denormalized_infos",
field=backend_app.fields.JSONField(default=dict),
),
migrations.AlterField(
model_name="exchange",
name="university",
field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.PROTECT,
related_name="exchanges",
to="backend_app.University",
),
),
migrations.AlterField(
model_name="offer",
name="university",
field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.PROTECT,
related_name="offers",
to="backend_app.University",
),
),
]
# Generated by Django 2.1.7 on 2019-06-30 16:30
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [("backend_app", "0007_auto_20190630_1753")]
operations = [
migrations.AddField(
model_name="universityinfo",
name="cover_photos",
field=models.ManyToManyField(to="backend_app.Picture"),
),
migrations.AlterField(
model_name="university",
name="logo",
field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.PROTECT,
to="backend_app.Picture",
),
),
]
......@@ -4,6 +4,7 @@ from rest_framework import serializers, viewsets
from rest_framework.response import Response
from backend_app.custom.mySerializerWithJSON import MySerializerWithJSON
from backend_app.permissions.app_permissions import ReadOnly
from backend_app.permissions.default import DEFAULT_VIEWSET_PERMISSIONS
......@@ -92,7 +93,9 @@ class BaseModelViewSet(viewsets.ModelViewSet):
"""
serializer_class = BaseModelSerializer
permission_classes = None
permission_classes = (
DEFAULT_VIEWSET_PERMISSIONS & ReadOnly,
) # ReadOnly or Override
# We store the api endpoint route directly in the viewset classes
# so that we can easily access them
......@@ -103,12 +106,7 @@ class BaseModelViewSet(viewsets.ModelViewSet):
We override the permission getter to make sure we add the default
app viewsets permissions
"""
if self.permission_classes is None:
return [DEFAULT_VIEWSET_PERMISSIONS()]
else:
return [
(DEFAULT_VIEWSET_PERMISSIONS & p)() for p in self.permission_classes
]
return [p() for p in self.permission_classes] + [DEFAULT_VIEWSET_PERMISSIONS()]
# Attribute that lists the fields that are expected to be preset in request.GET
required_filterset_fields = tuple()
......
......@@ -7,6 +7,7 @@ from django.utils import timezone
from rest_framework import serializers
from backend_app.models.pendingModeration import PendingModeration
from backend_app.permissions.app_permissions import NoPost, NoDelete
from backend_app.permissions.moderation import is_moderation_required
from backend_app.permissions.utils import Request as FakeRequest
from backend_app.settings.defaults import (
......@@ -364,6 +365,7 @@ class EssentialModuleViewSet(BaseModelViewSet):
Custom default viewset
"""
permission_classes = (NoPost & NoDelete,)
serializer_class = EssentialModuleSerializer
def get_serializer_context(self):
......
......@@ -6,6 +6,7 @@ from backend_app.models.abstract.versionedEssentialModule import (
VersionedEssentialModuleSerializer,
VersionedEssentialModuleViewSet,
)
from backend_app.permissions.app_permissions import NoDelete
from backend_app.validation.validators import UsefulLinksValidator
IMPORTANCE_LEVEL = (("-", "normal"), ("+", "important"), ("++", "IMPORTANT"))
......@@ -54,4 +55,5 @@ class ModuleViewSet(VersionedEssentialModuleViewSet):
Viewset for the Basic Module
"""
permission_classes = (NoDelete,)
serializer_class = ModuleSerializer