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: ...@@ -18,6 +18,9 @@ down_dev:
init_dev_data: init_dev_data:
docker-compose exec backend sh -c "cd backend && ./manage.py shell < init_dev_data.py" 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-pull:
docker-compose pull docker-compose pull
...@@ -64,7 +67,8 @@ prod_yml = -f ./server/docker-compose.prod.yml ...@@ -64,7 +67,8 @@ prod_yml = -f ./server/docker-compose.prod.yml
prod: setup prod: setup
$(info In production, we need to reset the webpack-stats.json file to make sure the front is up-to-date) $(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 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: down_prod:
docker-compose $(prod_yml) down docker-compose $(prod_yml) down
......
...@@ -30,3 +30,21 @@ def load_all(): ...@@ -30,3 +30,21 @@ def load_all():
LoadUniversityEx(admin).load() LoadUniversityEx(admin).load()
LoadRecommendationLists(admin).load() LoadRecommendationLists(admin).load()
LoadSiteInformation(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): ...@@ -19,4 +19,6 @@ class LoadLanguages(LoadGeneric):
reader = csv.reader(csvfile, quotechar='"') reader = csv.reader(csvfile, quotechar='"')
next(reader) next(reader)
for r in 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 ...@@ -4,6 +4,7 @@ from rest_framework import serializers, viewsets
from rest_framework.response import Response from rest_framework.response import Response
from backend_app.custom.mySerializerWithJSON import MySerializerWithJSON from backend_app.custom.mySerializerWithJSON import MySerializerWithJSON
from backend_app.permissions.app_permissions import ReadOnly
from backend_app.permissions.default import DEFAULT_VIEWSET_PERMISSIONS from backend_app.permissions.default import DEFAULT_VIEWSET_PERMISSIONS
...@@ -92,7 +93,9 @@ class BaseModelViewSet(viewsets.ModelViewSet): ...@@ -92,7 +93,9 @@ class BaseModelViewSet(viewsets.ModelViewSet):
""" """
serializer_class = BaseModelSerializer 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 # We store the api endpoint route directly in the viewset classes
# so that we can easily access them # so that we can easily access them
...@@ -103,12 +106,7 @@ class BaseModelViewSet(viewsets.ModelViewSet): ...@@ -103,12 +106,7 @@ class BaseModelViewSet(viewsets.ModelViewSet):
We override the permission getter to make sure we add the default We override the permission getter to make sure we add the default
app viewsets permissions app viewsets permissions
""" """
if self.permission_classes is None: return [p() for p in self.permission_classes] + [DEFAULT_VIEWSET_PERMISSIONS()]
return [DEFAULT_VIEWSET_PERMISSIONS()]
else:
return [
(DEFAULT_VIEWSET_PERMISSIONS & p)() for p in self.permission_classes
]
# Attribute that lists the fields that are expected to be preset in request.GET # Attribute that lists the fields that are expected to be preset in request.GET
required_filterset_fields = tuple() required_filterset_fields = tuple()
......
...@@ -7,6 +7,7 @@ from django.utils import timezone ...@@ -7,6 +7,7 @@ from django.utils import timezone
from rest_framework import serializers from rest_framework import serializers
from backend_app.models.pendingModeration import PendingModeration 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.moderation import is_moderation_required
from backend_app.permissions.utils import Request as