diff --git a/Makefile b/Makefile index 4d55269ae245dea92e6b503608c5524161a414dd..b9a7445a401bb01201916d156db5828182651f3a 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/backend/backend_app/load_data/load_all.py b/backend/backend_app/load_data/load_all.py index 69b211ab9dfdf883bb716f74eee12e601c9309ae..16a1e026550f066a6318054b99369ef7440ffe05 100644 --- a/backend/backend_app/load_data/load_all.py +++ b/backend/backend_app/load_data/load_all.py @@ -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() diff --git a/backend/backend_app/load_data/loading_scripts/loadLanguages.py b/backend/backend_app/load_data/loading_scripts/loadLanguages.py index 6937a1be92cfcd0f48d874531ee772d8208469bd..8318c6c8314f0934e2e3cc3f189285265af457f7 100644 --- a/backend/backend_app/load_data/loading_scripts/loadLanguages.py +++ b/backend/backend_app/load_data/loading_scripts/loadLanguages.py @@ -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]) + ) diff --git a/backend/backend_app/migrations/0001_initial.py b/backend/backend_app/migrations/0001_initial.py index 9beffe89f28ccb4a866ad9bfea6aef624b968458..4749bd0100fd32210e84f14e5205ef99245c7329 100644 --- a/backend/backend_app/migrations/0001_initial.py +++ b/backend/backend_app/migrations/0001_initial.py @@ -1,17 +1,24 @@ -# Generated by Django 2.1.7 on 2019-06-26 21:10 +# Generated by Django 2.1.7 on 2019-06-30 20:48 import backend_app.fields import backend_app.models.abstract.essentialModule +import backend_app.utils import backend_app.validation.validators +from django.conf import settings import django.core.validators from django.db import migrations, models +import django.db.models.deletion class Migration(migrations.Migration): initial = True - dependencies = [] + dependencies = [ + ("base_app", "0001_initial"), + ("contenttypes", "0002_remove_content_type_name"), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] operations = [ migrations.CreateModel( @@ -26,43 +33,6 @@ class Migration(migrations.Migration): 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)), - ("title", models.CharField(blank=True, default="", max_length=150)), - ("comment", models.CharField(blank=True, default="", max_length=5000)), - ( - "useful_links", - backend_app.fields.JSONField( - default=list, - validators=[ - backend_app.validation.validators.UsefulLinksValidator() - ], - ), - ), - ( - "importance_level", - models.CharField( - choices=[ - ("-", "normal"), - ("+", "important"), - ("++", "IMPORTANT"), - ], - default="-", - max_length=2, - ), - ), ("is_main_campus", models.BooleanField()), ("name", models.CharField(blank=True, default="", max_length=200)), ( @@ -192,6 +162,12 @@ class Migration(migrations.Migration): max_length=2, ), ), + ( + "countries", + models.ManyToManyField( + related_name="country_dri", to="backend_app.Country" + ), + ), ], options={"abstract": False}, ), @@ -283,6 +259,12 @@ class Migration(migrations.Migration): validators=[django.core.validators.MinValueValidator(0)], ), ), + ( + "countries", + models.ManyToManyField( + related_name="country_scholarships", to="backend_app.Country" + ), + ), ], options={"abstract": False}, ), @@ -336,6 +318,14 @@ class Migration(migrations.Migration): ], ), ), + ( + "country", + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + related_name="country_tagged_items", + to="backend_app.Country", + ), + ), ], ), migrations.CreateModel( @@ -350,15 +340,17 @@ class Migration(migrations.Migration): verbose_name="ID", ), ), + ("utc_id", models.IntegerField(unique=True)), ("utc_exchange_id", models.IntegerField()), - ("course_id", models.IntegerField()), - ("code", models.CharField(max_length=10)), + ("code", models.CharField(blank=True, max_length=10, null=True)), + ("title", models.CharField(blank=True, default="", max_length=200)), + ("link", models.URLField(blank=True, max_length=500, null=True)), ( - "title", - models.CharField(blank=True, default="", max_length=200, null=True), + "ects", + models.DecimalField( + decimal_places=2, default=0, max_digits=7, null=True + ), ), - ("link", models.URLField(blank=True, max_length=500, null=True)), - ("nb_credit", models.PositiveIntegerField(default=0)), ("category", models.CharField(blank=True, max_length=5, null=True)), ("profile", models.CharField(blank=True, max_length=10, null=True)), ("tsh_profile", models.CharField(blank=True, max_length=21, null=True)), @@ -366,6 +358,7 @@ class Migration(migrations.Migration): "student_login", models.CharField(blank=True, max_length=8, null=True), ), + ("unlinked", models.BooleanField(default=False)), ], options={"abstract": False}, ), @@ -435,6 +428,16 @@ class Migration(migrations.Migration): ], ), ), + ("untouched", models.BooleanField(default=True)), + ( + "course", + models.OneToOneField( + default=0, + on_delete=django.db.models.deletion.CASCADE, + related_name="course_feedback", + to="backend_app.Course", + ), + ), ], options={"abstract": False}, ), @@ -458,18 +461,6 @@ class Migration(migrations.Migration): ], options={"abstract": False}, ), - migrations.CreateModel( - name="Department", - fields=[ - ( - "code", - models.CharField(max_length=6, primary_key=True, serialize=False), - ), - ("name", models.CharField(max_length=100)), - ("active", models.BooleanField()), - ], - options={"abstract": False}, - ), migrations.CreateModel( name="Exchange", fields=[ @@ -482,24 +473,41 @@ class Migration(migrations.Migration): verbose_name="ID", ), ), - ("utc_departure_id", models.IntegerField()), - ("year", models.PositiveIntegerField(default=2018)), + ("utc_id", models.IntegerField(unique=True)), + ("utc_partner_id", models.IntegerField(null=True)), + ("year", models.PositiveIntegerField(default=2018, null=True)), ( "semester", models.CharField( - choices=[("a", "autumn"), ("p", "spring")], - default="a", - max_length=5, + choices=[("A", "autumn"), ("P", "spring")], + default="A", + max_length=1, + null=True, ), ), ("duration", models.PositiveIntegerField()), - ("dual_degree", models.BooleanField()), + ("double_degree", models.BooleanField()), ("master_obtained", models.BooleanField()), - ("student_major", models.CharField(max_length=20)), - ("student_minor", models.CharField(max_length=7)), - ("student_option", models.CharField(max_length=7)), + ( + "student_major_and_semester", + models.CharField(blank=True, max_length=20), + ), + ( + "student_minor", + models.CharField(blank=True, max_length=47, null=True), + ), + ( + "student_option", + models.CharField(blank=True, max_length=7, null=True), + ), ("utc_allow_courses", models.BooleanField()), ("utc_allow_login", models.BooleanField()), + ( + "student_major", + models.CharField(blank=True, max_length=20, null=True), + ), + ("student_semester", models.IntegerField(null=True)), + ("unlinked", models.BooleanField(default=False)), ], options={"abstract": False}, ), @@ -534,7 +542,6 @@ class Migration(migrations.Migration): models.CharField(blank=True, default="", max_length=500, null=True), ), ], - options={"abstract": False}, ), migrations.CreateModel( name="ForTestingModeration", @@ -618,21 +625,35 @@ class Migration(migrations.Migration): verbose_name="ID", ), ), - ("year", models.PositiveIntegerField(default=2018)), + ("utc_partner_id", models.IntegerField()), + ("year", models.PositiveIntegerField(default=2018, null=True)), ( "semester", models.CharField( - choices=[("a", "autumn"), ("p", "spring")], - default="a", + choices=[("A", "autumn"), ("P", "spring")], + default="A", max_length=2, + null=True, ), ), - ("nb_seats_offered", models.PositiveIntegerField()), - ("nb_seats_offered_exchange", models.PositiveIntegerField(null=True)), - ( - "nb_seats_offered_double_degree", - models.PositiveIntegerField(null=True), - ), + ("comment", models.TextField(max_length=500, null=True)), + ("double_degree", models.BooleanField(default=False)), + ("is_master_offered", models.BooleanField(default=False, null=True)), + ("nb_seats_offered", models.PositiveIntegerField(null=True)), + ("majors", models.CharField(max_length=4000, null=True)), + ], + ), + migrations.CreateModel( + name="Partner", + fields=[ + ("utc_id", models.IntegerField(primary_key=True, serialize=False)), + ("univ_name", models.CharField(max_length=80)), + ("address1", models.CharField(blank=True, max_length=100, null=True)), + ("address2", models.CharField(blank=True, 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}, ), @@ -651,6 +672,13 @@ class Migration(migrations.Migration): ("object_id", models.CharField(max_length=100)), ("updated_on", models.DateTimeField(null=True)), ("new_object", backend_app.fields.JSONField(default=dict)), + ( + "content_type", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="contenttypes.ContentType", + ), + ), ], ), migrations.CreateModel( @@ -719,7 +747,7 @@ class Migration(migrations.Migration): options={"abstract": False}, ), migrations.CreateModel( - name="Specialty", + name="SharedUnivFeedback", fields=[ ( "id", @@ -730,10 +758,23 @@ class Migration(migrations.Migration): verbose_name="ID", ), ), - ("code", models.CharField(max_length=6)), - ("name", models.CharField(max_length=100)), - ("active", models.BooleanField()), + ("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)), ], + options={"abstract": False}, ), migrations.CreateModel( name="University", @@ -762,20 +803,8 @@ class Migration(migrations.Migration): ("has_pending_moderation", models.BooleanField(default=False)), ("name", models.CharField(max_length=200)), ("acronym", models.CharField(blank=True, default="", max_length=20)), - ( - "logo", - models.URLField( - blank=True, - default="", - validators=[ - backend_app.validation.validators.PathExtensionValidator( - ["jpg", "jpeg", "png", "svg"] - ) - ], - ), - ), ("website", models.URLField(blank=True, default="", max_length=300)), - ("utc_id", models.IntegerField(unique=True)), + ("denormalized_infos", backend_app.fields.JSONField(default=dict)), ], options={"abstract": False}, ), @@ -919,6 +948,14 @@ class Migration(migrations.Migration): validators=[django.core.validators.MinValueValidator(0)], ), ), + ( + "currency", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="backend_app.Currency", + ), + ), ], options={"abstract": False}, ), @@ -973,4 +1010,751 @@ class Migration(migrations.Migration): ), ], ), + 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)), + ], + ), + migrations.CreateModel( + name="UserData", + fields=[ + ( + "owner", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + primary_key=True, + serialize=False, + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "theme", + backend_app.fields.JSONField( + default=backend_app.utils.get_default_theme_settings, + validators=[backend_app.validation.validators.ThemeValidator()], + ), + ), + ], + options={"abstract": False}, + ), + migrations.CreateModel( + name="ExchangeFeedback", + fields=[ + ("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)), + ( + "exchange", + models.OneToOneField( + default=0, + on_delete=django.db.models.deletion.CASCADE, + primary_key=True, + related_name="feedbacks", + serialize=False, + to="backend_app.Exchange", + ), + ), + ("general_comment", models.TextField(max_length=1500, null=True)), + ( + "academical_level_appreciation", + models.IntegerField( + default=0, + validators=[ + django.core.validators.MinValueValidator(-5), + django.core.validators.MaxValueValidator(5), + ], + ), + ), + ( + "foreign_student_welcome", + models.IntegerField( + default=0, + validators=[ + django.core.validators.MinValueValidator(-5), + django.core.validators.MaxValueValidator(5), + ], + ), + ), + ( + "cultural_interest", + models.IntegerField( + default=0, + validators=[ + django.core.validators.MinValueValidator(-5), + django.core.validators.MaxValueValidator(5), + ], + ), + ), + ("untouched", models.BooleanField(default=True)), + ( + "moderated_by", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to=settings.AUTH_USER_MODEL, + ), + ), + ], + options={"abstract": False}, + ), + migrations.CreateModel( + name="UniversityInfo", + fields=[ + ("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)), + ("title", models.CharField(blank=True, default="", max_length=150)), + ("comment", models.CharField(blank=True, default="", max_length=5000)), + ( + "useful_links", + backend_app.fields.JSONField( + default=list, + validators=[ + backend_app.validation.validators.UsefulLinksValidator() + ], + ), + ), + ( + "importance_level", + models.CharField( + choices=[ + ("-", "normal"), + ("+", "important"), + ("++", "IMPORTANT"), + ], + default="-", + max_length=2, + ), + ), + ( + "university", + models.OneToOneField( + on_delete=django.db.models.deletion.PROTECT, + primary_key=True, + related_name="university_info", + serialize=False, + to="backend_app.University", + ), + ), + ( + "cost_exchange", + models.DecimalField( + decimal_places=2, + max_digits=20, + null=True, + validators=[django.core.validators.MinValueValidator(0)], + ), + ), + ( + "cost_double_degree", + models.DecimalField( + decimal_places=2, + max_digits=20, + null=True, + validators=[django.core.validators.MinValueValidator(0)], + ), + ), + ( + "costs_currency", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="backend_app.Currency", + ), + ), + ], + options={"abstract": False}, + ), + migrations.CreateModel( + name="UniversitySemestersDates", + fields=[ + ("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)), + ("title", models.CharField(blank=True, default="", max_length=150)), + ("comment", models.CharField(blank=True, default="", max_length=5000)), + ( + "useful_links", + backend_app.fields.JSONField( + default=list, + validators=[ + backend_app.validation.validators.UsefulLinksValidator() + ], + ), + ), + ( + "importance_level", + models.CharField( + choices=[ + ("-", "normal"), + ("+", "important"), + ("++", "IMPORTANT"), + ], + default="-", + max_length=2, + ), + ), + ( + "university", + models.OneToOneField( + on_delete=django.db.models.deletion.PROTECT, + primary_key=True, + related_name="university_semesters_dates", + serialize=False, + to="backend_app.University", + ), + ), + ("spring_begin", models.DateField(blank=True, null=True)), + ("spring_end", models.DateField(blank=True, null=True)), + ("autumn_begin", models.DateField(blank=True, null=True)), + ("autumn_end", models.DateField(blank=True, null=True)), + ( + "moderated_by", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "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.AddField( + model_name="univmajorminors", + name="university", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="backend_app.University" + ), + ), + migrations.AddField( + model_name="universitytaggeditem", + name="moderated_by", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="universitytaggeditem", + name="university", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + related_name="university_tagged_items", + to="backend_app.University", + ), + ), + migrations.AddField( + model_name="universitytaggeditem", + name="updated_by", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="universityscholarship", + name="moderated_by", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="universityscholarship", + name="universities", + field=models.ManyToManyField( + related_name="university_scholarships", to="backend_app.University" + ), + ), + migrations.AddField( + model_name="universityscholarship", + name="updated_by", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="universitydri", + name="moderated_by", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="universitydri", + name="universities", + field=models.ManyToManyField( + related_name="university_dri", to="backend_app.University" + ), + ), + migrations.AddField( + model_name="universitydri", + name="updated_by", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="university", + name="logo", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="backend_app.Picture", + ), + ), + migrations.AddField( + model_name="university", + name="moderated_by", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="university", + name="updated_by", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="sharedunivfeedback", + name="moderated_by", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="sharedunivfeedback", + name="university", + field=models.OneToOneField( + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="backend_app.University", + ), + ), + migrations.AddField( + model_name="sharedunivfeedback", + name="updated_by", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="recommendationlist", + name="followers", + field=models.ManyToManyField( + related_name="followed_recommendation_list", to=settings.AUTH_USER_MODEL + ), + ), + migrations.AddField( + model_name="recommendationlist", + name="owner", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="user_recommendation_list", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="recommendationlist", + name="universities", + field=models.ManyToManyField(to="backend_app.University"), + ), + migrations.AddField( + model_name="picture", + name="owner", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="pendingmoderation", + name="updated_by", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL + ), + ), + 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="offer", + name="partner", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, to="backend_app.Partner" + ), + ), + migrations.AddField( + model_name="offer", + name="university", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="offers", + to="backend_app.University", + ), + ), + migrations.AddField( + model_name="fortestingversioning", + name="moderated_by", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="fortestingversioning", + name="updated_by", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="fortestingmoderation", + name="moderated_by", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="fortestingmoderation", + name="updated_by", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="file", + name="owner", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, + ), + ), + 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="exchange", + name="student", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="exchanges", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + 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.AddField( + model_name="coursefeedback", + name="language", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="courses", + to="backend_app.Language", + ), + ), + migrations.AddField( + model_name="coursefeedback", + name="moderated_by", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="coursefeedback", + name="updated_by", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="course", + name="exchange", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="exchange_courses", + to="backend_app.Exchange", + ), + ), + migrations.AddField( + model_name="countrytaggeditem", + name="moderated_by", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="countrytaggeditem", + name="updated_by", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="countryscholarship", + name="currency", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="backend_app.Currency", + ), + ), + migrations.AddField( + model_name="countryscholarship", + name="moderated_by", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="countryscholarship", + name="updated_by", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="countrydri", + name="moderated_by", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="countrydri", + name="updated_by", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="city", + name="country", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, to="backend_app.Country" + ), + ), + migrations.AddField( + model_name="campus", + name="city", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, to="backend_app.City" + ), + ), + migrations.AddField( + model_name="campus", + name="university", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + related_name="university_campuses", + to="backend_app.University", + ), + ), + migrations.AlterUniqueTogether( + name="univmajorminors", unique_together={("university", "major")} + ), + migrations.AlterUniqueTogether( + name="universitytaggeditem", unique_together={("university", "tag")} + ), + migrations.AddField( + model_name="universityinfo", + name="cover_photos", + field=models.ManyToManyField(to="backend_app.Picture"), + ), + migrations.AddField( + model_name="universityinfo", + name="moderated_by", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AddField( + model_name="universityinfo", + name="updated_by", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AlterUniqueTogether( + name="pendingmoderation", unique_together={("content_type", "object_id")} + ), + migrations.AlterUniqueTogether( + name="offer", unique_together={("utc_partner_id", "year", "semester")} + ), + migrations.AddField( + model_name="exchangefeedback", + name="university", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="backend_app.University", + ), + ), + migrations.AddField( + model_name="exchangefeedback", + name="updated_by", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AlterUniqueTogether( + name="countrytaggeditem", unique_together={("country", "tag")} + ), + migrations.AlterUniqueTogether( + name="campus", unique_together={("is_main_campus", "university")} + ), ] diff --git a/backend/backend_app/migrations/0002_auto_20190626_2310.py b/backend/backend_app/migrations/0002_auto_20190626_2310.py deleted file mode 100644 index b7cfc7dda9cbab707abd1faab0a5aa7601e3f138..0000000000000000000000000000000000000000 --- a/backend/backend_app/migrations/0002_auto_20190626_2310.py +++ /dev/null @@ -1,748 +0,0 @@ -# Generated by Django 2.1.7 on 2019-06-26 21:10 - -import backend_app.fields -import backend_app.models.abstract.essentialModule -import backend_app.utils -import backend_app.validation.validators -from django.conf import settings -import django.core.validators -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ("backend_app", "0001_initial"), - ("contenttypes", "0002_remove_content_type_name"), - ("base_app", "0001_initial"), - ] - - operations = [ - migrations.CreateModel( - name="UserData", - fields=[ - ( - "owner", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - primary_key=True, - serialize=False, - to=settings.AUTH_USER_MODEL, - ), - ), - ( - "theme", - backend_app.fields.JSONField( - default=backend_app.utils.get_default_theme_settings, - validators=[backend_app.validation.validators.ThemeValidator()], - ), - ), - ], - options={"abstract": False}, - ), - migrations.CreateModel( - name="ExchangeFeedback", - fields=[ - ("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)), - ( - "exchange", - models.OneToOneField( - default=0, - on_delete=django.db.models.deletion.CASCADE, - primary_key=True, - related_name="feedbacks", - serialize=False, - to="backend_app.Exchange", - ), - ), - ("general_comment", models.TextField(max_length=1500, null=True)), - ( - "academical_level_appreciation", - models.IntegerField( - validators=[ - django.core.validators.MinValueValidator(-5), - django.core.validators.MaxValueValidator(5), - ] - ), - ), - ( - "foreign_student_welcome", - models.IntegerField( - validators=[ - django.core.validators.MinValueValidator(-5), - django.core.validators.MaxValueValidator(5), - ] - ), - ), - ( - "cultural_interest", - models.IntegerField( - validators=[ - django.core.validators.MinValueValidator(-5), - django.core.validators.MaxValueValidator(5), - ] - ), - ), - ( - "moderated_by", - models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to=settings.AUTH_USER_MODEL, - ), - ), - ], - options={"abstract": False}, - ), - migrations.CreateModel( - name="UniversityInfo", - fields=[ - ("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)), - ("title", models.CharField(blank=True, default="", max_length=150)), - ("comment", models.CharField(blank=True, default="", max_length=5000)), - ( - "useful_links", - backend_app.fields.JSONField( - default=list, - validators=[ - backend_app.validation.validators.UsefulLinksValidator() - ], - ), - ), - ( - "importance_level", - models.CharField( - choices=[ - ("-", "normal"), - ("+", "important"), - ("++", "IMPORTANT"), - ], - default="-", - max_length=2, - ), - ), - ( - "university", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - primary_key=True, - related_name="university_info", - serialize=False, - to="backend_app.University", - ), - ), - ( - "cost_exchange", - models.DecimalField( - decimal_places=2, - max_digits=20, - null=True, - validators=[django.core.validators.MinValueValidator(0)], - ), - ), - ( - "cost_double_degree", - models.DecimalField( - decimal_places=2, - max_digits=20, - null=True, - validators=[django.core.validators.MinValueValidator(0)], - ), - ), - ( - "costs_currency", - models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.PROTECT, - to="backend_app.Currency", - ), - ), - ( - "moderated_by", - models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to=settings.AUTH_USER_MODEL, - ), - ), - ( - "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.CreateModel( - name="UniversitySemestersDates", - fields=[ - ("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)), - ("title", models.CharField(blank=True, default="", max_length=150)), - ("comment", models.CharField(blank=True, default="", max_length=5000)), - ( - "useful_links", - backend_app.fields.JSONField( - default=list, - validators=[ - backend_app.validation.validators.UsefulLinksValidator() - ], - ), - ), - ( - "importance_level", - models.CharField( - choices=[ - ("-", "normal"), - ("+", "important"), - ("++", "IMPORTANT"), - ], - default="-", - max_length=2, - ), - ), - ( - "university", - models.OneToOneField( - on_delete=django.db.models.deletion.CASCADE, - primary_key=True, - related_name="university_semesters_dates", - serialize=False, - to="backend_app.University", - ), - ), - ("spring_begin", models.DateField(blank=True, null=True)), - ("spring_end", models.DateField(blank=True, null=True)), - ("autumn_begin", models.DateField(blank=True, null=True)), - ("autumn_end", models.DateField(blank=True, null=True)), - ( - "moderated_by", - models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to=settings.AUTH_USER_MODEL, - ), - ), - ( - "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.AddField( - model_name="universitytaggeditem", - name="moderated_by", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AddField( - model_name="universitytaggeditem", - name="university", - field=models.ForeignKey( - on_delete=django.db.models.deletion.PROTECT, - related_name="university_tagged_items", - to="backend_app.University", - ), - ), - migrations.AddField( - model_name="universitytaggeditem", - name="updated_by", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AddField( - model_name="universityscholarship", - name="currency", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.PROTECT, - to="backend_app.Currency", - ), - ), - migrations.AddField( - model_name="universityscholarship", - name="moderated_by", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AddField( - model_name="universityscholarship", - name="universities", - field=models.ManyToManyField( - related_name="university_scholarships", to="backend_app.University" - ), - ), - migrations.AddField( - model_name="universityscholarship", - name="updated_by", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AddField( - model_name="universitydri", - name="moderated_by", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AddField( - model_name="universitydri", - name="universities", - field=models.ManyToManyField( - related_name="university_dri", to="backend_app.University" - ), - ), - migrations.AddField( - model_name="universitydri", - name="updated_by", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AddField( - model_name="university", - name="moderated_by", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AddField( - model_name="university", - name="updated_by", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AddField( - model_name="specialty", - name="department", - field=models.ForeignKey( - on_delete=django.db.models.deletion.PROTECT, to="backend_app.Department" - ), - ), - migrations.AddField( - model_name="recommendationlist", - name="followers", - field=models.ManyToManyField( - related_name="followed_recommendation_list", to=settings.AUTH_USER_MODEL - ), - ), - migrations.AddField( - model_name="recommendationlist", - name="owner", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="user_recommendation_list", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AddField( - model_name="recommendationlist", - name="universities", - field=models.ManyToManyField(to="backend_app.University"), - ), - migrations.AddField( - model_name="picture", - name="owner", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AddField( - model_name="pendingmoderation", - name="content_type", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="contenttypes.ContentType", - ), - ), - migrations.AddField( - model_name="pendingmoderation", - name="updated_by", - field=models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL - ), - ), - migrations.AddField( - model_name="offer", - name="specialties", - field=models.ManyToManyField( - related_name="has_seats_at_univ", to="backend_app.Specialty" - ), - ), - migrations.AddField( - model_name="offer", - name="university", - field=models.ForeignKey( - on_delete=django.db.models.deletion.PROTECT, to="backend_app.University" - ), - ), - migrations.AddField( - model_name="fortestingversioning", - name="moderated_by", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AddField( - model_name="fortestingversioning", - name="updated_by", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AddField( - model_name="fortestingmoderation", - name="moderated_by", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AddField( - model_name="fortestingmoderation", - name="updated_by", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AddField( - model_name="file", - name="owner", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AddField( - model_name="exchange", - name="student", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AddField( - model_name="exchange", - name="university", - field=models.ForeignKey( - on_delete=django.db.models.deletion.PROTECT, to="backend_app.University" - ), - ), - migrations.AddField( - model_name="coursefeedback", - name="course", - field=models.OneToOneField( - default=0, - on_delete=django.db.models.deletion.CASCADE, - related_name="course_feedback", - to="backend_app.Course", - ), - ), - migrations.AddField( - model_name="coursefeedback", - name="language", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="courses", - to="backend_app.Language", - ), - ), - migrations.AddField( - model_name="coursefeedback", - name="moderated_by", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AddField( - model_name="coursefeedback", - name="updated_by", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AddField( - model_name="course", - name="exchange", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.CASCADE, - related_name="exchange_courses", - to="backend_app.Exchange", - ), - ), - migrations.AddField( - model_name="countrytaggeditem", - name="country", - field=models.ForeignKey( - on_delete=django.db.models.deletion.PROTECT, - related_name="country_tagged_items", - to="backend_app.Country", - ), - ), - migrations.AddField( - model_name="countrytaggeditem", - name="moderated_by", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AddField( - model_name="countrytaggeditem", - name="updated_by", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AddField( - model_name="countryscholarship", - name="countries", - field=models.ManyToManyField( - related_name="country_scholarships", to="backend_app.Country" - ), - ), - migrations.AddField( - model_name="countryscholarship", - name="currency", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.PROTECT, - to="backend_app.Currency", - ), - ), - migrations.AddField( - model_name="countryscholarship", - name="moderated_by", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AddField( - model_name="countryscholarship", - name="updated_by", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AddField( - model_name="countrydri", - name="countries", - field=models.ManyToManyField( - related_name="country_dri", to="backend_app.Country" - ), - ), - migrations.AddField( - model_name="countrydri", - name="moderated_by", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AddField( - model_name="countrydri", - name="updated_by", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AddField( - model_name="city", - name="country", - field=models.ForeignKey( - on_delete=django.db.models.deletion.PROTECT, to="backend_app.Country" - ), - ), - migrations.AddField( - model_name="campus", - name="city", - field=models.ForeignKey( - on_delete=django.db.models.deletion.PROTECT, to="backend_app.City" - ), - ), - migrations.AddField( - model_name="campus", - name="moderated_by", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AddField( - model_name="campus", - name="university", - field=models.ForeignKey( - on_delete=django.db.models.deletion.PROTECT, - related_name="university_campuses", - to="backend_app.University", - ), - ), - migrations.AddField( - model_name="campus", - name="updated_by", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AlterUniqueTogether( - name="universitytaggeditem", unique_together={("university", "tag")} - ), - migrations.AlterUniqueTogether( - name="specialty", unique_together={("code", "department")} - ), - migrations.AlterUniqueTogether( - name="pendingmoderation", unique_together={("content_type", "object_id")} - ), - migrations.AddField( - model_name="exchangefeedback", - name="university", - field=models.ForeignKey( - default=0, - on_delete=django.db.models.deletion.PROTECT, - to="backend_app.University", - ), - ), - migrations.AddField( - model_name="exchangefeedback", - name="updated_by", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AlterUniqueTogether( - name="countrytaggeditem", unique_together={("country", "tag")} - ), - migrations.AlterUniqueTogether( - name="campus", unique_together={("is_main_campus", "university")} - ), - ] diff --git a/backend/backend_app/migrations/0003_auto_20190629_1122.py b/backend/backend_app/migrations/0003_auto_20190629_1122.py deleted file mode 100644 index 46a0feabf7d197b950f88acd89a4d2090abf4134..0000000000000000000000000000000000000000 --- a/backend/backend_app/migrations/0003_auto_20190629_1122.py +++ /dev/null @@ -1,213 +0,0 @@ -# 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, - ), - ] diff --git a/backend/backend_app/migrations/0004_auto_20190629_1941.py b/backend/backend_app/migrations/0004_auto_20190629_1941.py deleted file mode 100644 index d49d6498dda8330c16f19c9bec5234278c4e1be8..0000000000000000000000000000000000000000 --- a/backend/backend_app/migrations/0004_auto_20190629_1941.py +++ /dev/null @@ -1,118 +0,0 @@ -# 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")} - ), - ] diff --git a/backend/backend_app/migrations/0005_auto_20190630_0937.py b/backend/backend_app/migrations/0005_auto_20190630_0937.py deleted file mode 100644 index d0bf879fdd4261561d6d0e6929aaace80796dc50..0000000000000000000000000000000000000000 --- a/backend/backend_app/migrations/0005_auto_20190630_0937.py +++ /dev/null @@ -1,54 +0,0 @@ -# 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")} - ), - ] diff --git a/backend/backend_app/migrations/0006_auto_20190630_1119.py b/backend/backend_app/migrations/0006_auto_20190630_1119.py deleted file mode 100644 index 483cbe7cec29cd4a94ac20562c78b65b0f25e264..0000000000000000000000000000000000000000 --- a/backend/backend_app/migrations/0006_auto_20190630_1119.py +++ /dev/null @@ -1,84 +0,0 @@ -# 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, - ), - ), - ] diff --git a/backend/backend_app/migrations/0007_auto_20190630_1753.py b/backend/backend_app/migrations/0007_auto_20190630_1753.py deleted file mode 100644 index c49d504088499c7c12fe37d4b42173114baed3af..0000000000000000000000000000000000000000 --- a/backend/backend_app/migrations/0007_auto_20190630_1753.py +++ /dev/null @@ -1,41 +0,0 @@ -# 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", - ), - ), - ] diff --git a/backend/backend_app/migrations/0008_auto_20190630_1830.py b/backend/backend_app/migrations/0008_auto_20190630_1830.py deleted file mode 100644 index d807bbbf431c4d556140fd0bd7129c277c467420..0000000000000000000000000000000000000000 --- a/backend/backend_app/migrations/0008_auto_20190630_1830.py +++ /dev/null @@ -1,26 +0,0 @@ -# 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", - ), - ), - ] diff --git a/backend/backend_app/models/abstract/base.py b/backend/backend_app/models/abstract/base.py index ed20009f27ef27c789d42d70d5585c6053183555..e7525a126e858133cb3ca23066ef64f4cb1bc130 100644 --- a/backend/backend_app/models/abstract/base.py +++ b/backend/backend_app/models/abstract/base.py @@ -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() diff --git a/backend/backend_app/models/abstract/essentialModule.py b/backend/backend_app/models/abstract/essentialModule.py index 1fc26783efedd50284880d482938ba1460c1709d..48f02f4dfabc4d3e1081484fae01d6126eeefcc6 100644 --- a/backend/backend_app/models/abstract/essentialModule.py +++ b/backend/backend_app/models/abstract/essentialModule.py @@ -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): diff --git a/backend/backend_app/models/abstract/module.py b/backend/backend_app/models/abstract/module.py index 1c6b3cfde512fff7376de3a3831a7a9c1ced2cdd..ec19c854e2aebde7b49b8799bba86c578336052e 100644 --- a/backend/backend_app/models/abstract/module.py +++ b/backend/backend_app/models/abstract/module.py @@ -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 diff --git a/backend/backend_app/models/abstract/scholarship.py b/backend/backend_app/models/abstract/scholarship.py index abc55e6be8fcf06bac5c236f2dc289621c67bd5e..0c2f3c9f37abdfd4be90e466fcbb6759b7afb6a2 100644 --- a/backend/backend_app/models/abstract/scholarship.py +++ b/backend/backend_app/models/abstract/scholarship.py @@ -73,7 +73,14 @@ class ScholarshipSerializer(ModuleSerializer): class Meta: model = Scholarship - fields = "__all__" + fields = ModuleSerializer.Meta.fields + ( + "short_description", + "currency", + "other_advantages", + "frequency", + "amount_min", + "amount_max", + ) class ScholarshipViewSet(ModuleViewSet): diff --git a/backend/backend_app/models/campus.py b/backend/backend_app/models/campus.py index 23ab2cc489cef2d274f5d48d3331c28ab137c67d..76305bbd7e6bcf2c080739a7274735914eba6078 100644 --- a/backend/backend_app/models/campus.py +++ b/backend/backend_app/models/campus.py @@ -1,13 +1,17 @@ from django.core.validators import MinValueValidator, MaxValueValidator from django.db import models -from backend_app.models.abstract.module import Module, ModuleSerializer, ModuleViewSet +from backend_app.models.abstract.base import ( + BaseModel, + BaseModelSerializer, + BaseModelViewSet, +) from backend_app.models.city import City from backend_app.models.university import University from backend_app.permissions.app_permissions import ReadOnly -class Campus(Module): +class Campus(BaseModel): is_main_campus = models.BooleanField(null=False) name = models.CharField(max_length=200, default="", blank=True) city = models.ForeignKey(City, on_delete=models.PROTECT, null=False) @@ -37,19 +41,27 @@ class Campus(Module): unique_together = ("is_main_campus", "university") -class CampusSerializer(ModuleSerializer): +class CampusSerializer(BaseModelSerializer): class Meta: model = Campus - fields = "__all__" + fields = BaseModelSerializer.Meta.fields + ( + "is_main_campus", + "name", + "city", + "university", + "lat", + "lon", + ) -class CampusViewSet(ModuleViewSet): +class CampusViewSet(BaseModelViewSet): + permission_classes = (ReadOnly,) queryset = Campus.objects.all() # pylint: disable=E1101 serializer_class = CampusSerializer end_point_route = "campuses" -class MainCampusViewSet(ModuleViewSet): +class MainCampusViewSet(BaseModelViewSet): queryset = Campus.objects.filter(is_main_campus=True) serializer_class = CampusSerializer permission_classes = (ReadOnly,) diff --git a/backend/backend_app/models/city.py b/backend/backend_app/models/city.py index a54a161e537ac07542c8eb7d7456d70dc621e37b..486ecf1839de9715fed77d0f32fce25c5f7cdd90 100644 --- a/backend/backend_app/models/city.py +++ b/backend/backend_app/models/city.py @@ -6,7 +6,7 @@ from backend_app.models.abstract.base import ( BaseModelViewSet, ) from backend_app.models.country import Country -from backend_app.permissions.app_permissions import ReadOnly, IsStaff +from backend_app.permissions.app_permissions import ReadOnly class City(BaseModel): @@ -21,11 +21,16 @@ class City(BaseModel): class CitySerializer(BaseModelSerializer): class Meta: model = City - fields = "__all__" + fields = BaseModelSerializer.Meta.fields + ( + "name", + "local_name", + "area", + "country", + ) class CityViewSet(BaseModelViewSet): queryset = City.objects.all() # pylint: disable=E1101 serializer_class = CitySerializer - permission_classes = (IsStaff | ReadOnly,) + permission_classes = (ReadOnly,) end_point_route = "cities" diff --git a/backend/backend_app/models/country.py b/backend/backend_app/models/country.py index 8cee227edba9ab4b9368e2d1c29cffb2ca055875..baea12d8036dd230a132ffa91ba63095d2433d63 100644 --- a/backend/backend_app/models/country.py +++ b/backend/backend_app/models/country.py @@ -28,7 +28,16 @@ class Country(BaseModel): class CountrySerializer(BaseModelSerializer): class Meta: model = Country - fields = "__all__" + fields = BaseModelSerializer.Meta.fields + ( + "name", + "iso_alpha2_code", + "iso_alpha3_code", + "region_name", + "region_un_code", + "sub_region_name", + "intermediate_region_name", + "intermediate_region_un_code", + ) class CountryViewSet(BaseModelViewSet): diff --git a/backend/backend_app/models/countryDri.py b/backend/backend_app/models/countryDri.py index d5c9a3de609bb151b9116a945b8f4126b9d5d662..c1145b7f7885a01014b47393f7e1f84d2e68601a 100644 --- a/backend/backend_app/models/countryDri.py +++ b/backend/backend_app/models/countryDri.py @@ -2,22 +2,24 @@ from django.db import models from backend_app.models.abstract.module import Module, ModuleSerializer, ModuleViewSet from backend_app.models.country import Country -from backend_app.permissions.app_permissions import IsStaff, IsDri, NoPost +from backend_app.permissions.app_permissions import IsStaff, IsDri, ReadOnly +from backend_app.permissions.moderation import ModerationLevels class CountryDri(Module): + moderation_level = ModerationLevels.DEPENDING_ON_SITE_SETTINGS countries = models.ManyToManyField(Country, related_name="country_dri") class CountryDriSerializer(ModuleSerializer): class Meta: model = CountryDri - fields = "__all__" + fields = ModuleSerializer.Meta.fields + ("countries",) class CountryDriViewSet(ModuleViewSet): queryset = CountryDri.objects.all() # pylint: disable=E1101 serializer_class = CountryDriSerializer - permission_classes = (IsStaff | IsDri | NoPost,) + permission_classes = (IsStaff | IsDri | ReadOnly,) end_point_route = "countryDri" filterset_fields = ("countries",) diff --git a/backend/backend_app/models/countryScholarship.py b/backend/backend_app/models/countryScholarship.py index fd761cfd504da99782e886dea8db1b4f6c5f5de4..551fa225df4b6f64f6664fa5a3622e2e9a66aebf 100644 --- a/backend/backend_app/models/countryScholarship.py +++ b/backend/backend_app/models/countryScholarship.py @@ -6,19 +6,23 @@ from backend_app.models.abstract.scholarship import ( ScholarshipViewSet, ) from backend_app.models.country import Country +from backend_app.permissions.moderation import ModerationLevels class CountryScholarship(Scholarship): + moderation_level = ModerationLevels.DEPENDING_ON_SITE_SETTINGS + countries = models.ManyToManyField(Country, related_name="country_scholarships") class CountryScholarshipSerializer(ScholarshipSerializer): class Meta: model = CountryScholarship - fields = "__all__" + fields = ScholarshipSerializer.Meta.fields + ("countries",) class CountryScholarshipViewSet(ScholarshipViewSet): + permission_classes = ScholarshipViewSet.permission_classes queryset = CountryScholarship.objects.all() # pylint: disable=E1101 serializer_class = CountryScholarshipSerializer end_point_route = "countryScholarships" diff --git a/backend/backend_app/models/courseFeedback.py b/backend/backend_app/models/courseFeedback.py index 77365419b1470b32ca942e01c54eec7a20e948c4..69a579319b556df40bb6d16c3af7f4a757117562 100644 --- a/backend/backend_app/models/courseFeedback.py +++ b/backend/backend_app/models/courseFeedback.py @@ -14,7 +14,7 @@ class CourseFeedback(EssentialModule): Course, on_delete=models.CASCADE, default=0, related_name="course_feedback" ) language = models.ForeignKey( - Language, on_delete=models.SET_NULL, related_name="courses", null=True + Language, on_delete=models.PROTECT, related_name="courses", null=True ) comment = models.TextField(null=True, max_length=1500) adequation = models.IntegerField( diff --git a/backend/backend_app/models/currency.py b/backend/backend_app/models/currency.py index 269286950d7cb7cdb215e8061bd77ab0551150ee..d4477e500cb534c55c221a6e536579fbc7266378 100644 --- a/backend/backend_app/models/currency.py +++ b/backend/backend_app/models/currency.py @@ -21,7 +21,12 @@ class Currency(BaseModel): class CurrencySerializer(BaseModelSerializer): class Meta: model = Currency - fields = "__all__" + fields = BaseModelSerializer.Meta.fields + ( + "code", + "name", + "symbol", + "one_EUR_in_this_currency", + ) class CurrencyViewSet(BaseModelViewSet): diff --git a/backend/backend_app/models/file_picture.py b/backend/backend_app/models/file_picture.py index a3ed99b1491764bee3f014c050701d69912937d1..f80d0e8434e5f5af881e0b06e7f00ebb9cbe9ff8 100644 --- a/backend/backend_app/models/file_picture.py +++ b/backend/backend_app/models/file_picture.py @@ -7,6 +7,7 @@ from backend_app.models.abstract.base import ( BaseModelViewSet, ) from backend_app.permissions.app_permissions import NoDelete, IsStaff, IsOwner, ReadOnly +from backend_app.permissions.moderation import ModerationLevels from backend_app.validation.validators import ImageValidator from base_app.models import User @@ -17,6 +18,7 @@ from base_app.models import User class AbstractFile(BaseModel): + moderation_level = ModerationLevels.NO_MODERATION owner = models.ForeignKey(User, on_delete=models.SET_NULL, null=True) file = models.FileField(upload_to="files/%Y/%m/%d/", blank=True, null=True) title = models.CharField(max_length=200, default="", blank=True, null=True) @@ -98,10 +100,12 @@ class BaseFileViewSet(BaseModelViewSet): else: return self._serializer_not_read_only - permission_classes = (NoDelete | IsStaff | IsOwner, IsOwner | IsStaff | ReadOnly) + permission_classes = ( + (NoDelete | IsStaff | IsOwner) & (ReadOnly | IsOwner | IsStaff), + ) -class FileViewSet(BaseModelViewSet): +class FileViewSet(BaseFileViewSet): _serializer_not_read_only = FileSerializer _serializer_read_only = FileSerializerFileReadOnly queryset = File.objects.all() diff --git a/backend/backend_app/models/for_testing/moderation.py b/backend/backend_app/models/for_testing/moderation.py index 4f08d4adaeedff4a5fa8a9cdbad5854980d3a51f..5e2d4fe1e3d4f6661df146f377f8600575251a9b 100644 --- a/backend/backend_app/models/for_testing/moderation.py +++ b/backend/backend_app/models/for_testing/moderation.py @@ -25,7 +25,7 @@ class ForTestingModerationSerializer(EssentialModuleSerializer): class Meta: model = ForTestingModeration - fields = "__all__" + fields = EssentialModuleSerializer.Meta.fields + ("aaa",) class ForTestingModerationViewSet(EssentialModuleViewSet): @@ -33,6 +33,7 @@ class ForTestingModerationViewSet(EssentialModuleViewSet): Simple Viewset for testing purpose """ + permission_classes = tuple() serializer_class = ForTestingModerationSerializer queryset = ForTestingModeration.objects.all() end_point_route = "test/moderation" diff --git a/backend/backend_app/models/for_testing/versioning.py b/backend/backend_app/models/for_testing/versioning.py index 598e62563002ce81dc4655e89520020a6af1013c..13d3c4b405a83a60ef253fb9d611bf03c9a32314 100644 --- a/backend/backend_app/models/for_testing/versioning.py +++ b/backend/backend_app/models/for_testing/versioning.py @@ -27,7 +27,7 @@ class ForTestingVersioningSerializer(VersionedEssentialModuleSerializer): class Meta: model = ForTestingVersioning - fields = "__all__" + fields = VersionedEssentialModuleSerializer.Meta.fields + ("bbb",) class ForTestingVersioningViewSet(VersionedEssentialModuleViewSet): @@ -35,6 +35,7 @@ class ForTestingVersioningViewSet(VersionedEssentialModuleViewSet): Simple Viewset for testing purposes (versioning) """ + permission_classes = tuple() serializer_class = ForTestingVersioningSerializer queryset = ForTestingVersioning.objects.all() end_point_route = "test/versioning" diff --git a/backend/backend_app/models/language.py b/backend/backend_app/models/language.py index add0e0f3f156ca650cdc4558f7f00bbd8d12ce2a..a2fbad0cc38248ba390b02ba4920d860b33d1488 100644 --- a/backend/backend_app/models/language.py +++ b/backend/backend_app/models/language.py @@ -5,7 +5,7 @@ from backend_app.models.abstract.base import ( BaseModelSerializer, BaseModelViewSet, ) -from backend_app.permissions.app_permissions import IsStaff, ReadOnly +from backend_app.permissions.app_permissions import ReadOnly class Language(BaseModel): @@ -23,4 +23,4 @@ class LanguageViewSet(BaseModelViewSet): serializer_class = LanguageSerializer queryset = Language.objects.all() # pylint: disable=E1101 end_point_route = "languages" - permission_classes = (IsStaff | ReadOnly,) + permission_classes = (ReadOnly,) diff --git a/backend/backend_app/models/pendingModeration.py b/backend/backend_app/models/pendingModeration.py index 41a88dae3c9a7965dc52ac2f796b515c5984e1c7..217b9cbea2d33cfde29c78480af7b8a4a1cb7222 100644 --- a/backend/backend_app/models/pendingModeration.py +++ b/backend/backend_app/models/pendingModeration.py @@ -49,7 +49,13 @@ class PendingModerationSerializer(BaseModelSerializer): class Meta: model = PendingModeration - fields = "__all__" + fields = BaseModelSerializer.Meta.fields + ( + "content_type", + "object_id", + "updated_by", + "updated_on", + "new_object", + ) class PendingModerationViewSet(BaseModelViewSet): diff --git a/backend/backend_app/models/taggedItems.py b/backend/backend_app/models/taggedItems.py index f1c36663731556dcf29ad6d742210b45ac9387a9..9ee9438e2794507370343cbbb2258f83d80b0ac0 100644 --- a/backend/backend_app/models/taggedItems.py +++ b/backend/backend_app/models/taggedItems.py @@ -61,7 +61,7 @@ class UniversityTaggedItemViewSet(VersionedEssentialModuleViewSet): end_point_route = "universityTaggedItems" filterset_fields = ("university",) required_filterset_fields = ("university",) - permission_classes = (NoPost, NoDelete) + permission_classes = VersionedEssentialModuleViewSet.permission_classes ######################### @@ -113,7 +113,7 @@ class CountryTaggedItemViewSet(VersionedEssentialModuleViewSet): end_point_route = "countryTaggedItems" filterset_fields = ("country",) required_filterset_fields = ("country",) - permission_classes = (NoPost, NoDelete) + permission_classes = (NoPost & NoDelete,) ######################### diff --git a/backend/backend_app/models/university.py b/backend/backend_app/models/university.py index 53c87ad5abde2a6001d615fd6dcc587e0443994c..7ddc41780b356297544462403c76af88ca0addd1 100644 --- a/backend/backend_app/models/university.py +++ b/backend/backend_app/models/university.py @@ -9,6 +9,7 @@ from backend_app.models.abstract.essentialModule import ( EssentialModuleViewSet, ) from backend_app.models.file_picture import Picture +from backend_app.permissions.moderation import ModerationLevels logger = logging.getLogger("django") @@ -18,6 +19,8 @@ class University(EssentialModule): Model storing information about universities """ + moderation_level = ModerationLevels.ENFORCED + name = models.CharField(max_length=200) acronym = models.CharField(max_length=20, default="", blank=True) logo = models.ForeignKey(Picture, null=True, on_delete=models.PROTECT) @@ -40,6 +43,7 @@ class UniversitySerializer(EssentialModuleSerializer): class UniversityViewSet(EssentialModuleViewSet): + permission_classes = EssentialModuleViewSet.permission_classes serializer_class = UniversitySerializer queryset = University.objects.all() # pylint: disable=E1101 end_point_route = "universities" diff --git a/backend/backend_app/models/universityDri.py b/backend/backend_app/models/universityDri.py index 2cb3bbf1471f9c7e6f1f9f95008c2029c6a9bed8..7812c78feaf58245b6b6f377541628d90d2557ee 100644 --- a/backend/backend_app/models/universityDri.py +++ b/backend/backend_app/models/universityDri.py @@ -3,16 +3,19 @@ from django.db import models from backend_app.models.abstract.module import Module, ModuleSerializer, ModuleViewSet from backend_app.models.university import University from backend_app.permissions.app_permissions import IsStaff, IsDri, ReadOnly +from backend_app.permissions.moderation import ModerationLevels class UniversityDri(Module): + moderation_level = ModerationLevels.ENFORCED + universities = models.ManyToManyField(University, related_name="university_dri") class UniversityDriSerializer(ModuleSerializer): class Meta: model = UniversityDri - fields = "__all__" + fields = ModuleSerializer.Meta.fields + ("universities",) class UniversityDriViewSet(ModuleViewSet): diff --git a/backend/backend_app/models/universityInfo.py b/backend/backend_app/models/universityInfo.py index 9db8d3dd3c51ff128f76833b2bcb5e105f6beccd..c9755e8f0ec8fce999add0a2f7d04b0415a0c23b 100644 --- a/backend/backend_app/models/universityInfo.py +++ b/backend/backend_app/models/universityInfo.py @@ -5,12 +5,15 @@ from backend_app.models.abstract.module import Module, ModuleSerializer, ModuleV from backend_app.models.currency import Currency from backend_app.models.file_picture import Picture from backend_app.models.university import University +from backend_app.permissions.moderation import ModerationLevels class UniversityInfo(Module): + moderation_level = ModerationLevels.DEPENDING_ON_SITE_SETTINGS + university = models.OneToOneField( University, - on_delete=models.CASCADE, + on_delete=models.PROTECT, related_name="university_info", primary_key=True, null=False, @@ -42,5 +45,5 @@ class UniversityInfoSerializer(ModuleSerializer): class UniversityInfoViewSet(ModuleViewSet): queryset = UniversityInfo.objects.all() # pylint: disable=E1101 serializer_class = UniversityInfoSerializer - # permission_classes = (ReadOnly,) + permission_classes = ModuleViewSet.permission_classes end_point_route = "universityInfo" diff --git a/backend/backend_app/models/universityScholarship.py b/backend/backend_app/models/universityScholarship.py index 94aa91c35ca8d5b110d0feafb2597e41be63726f..e283505bc4733abbac3ab6222572f515dff25a6e 100644 --- a/backend/backend_app/models/universityScholarship.py +++ b/backend/backend_app/models/universityScholarship.py @@ -6,9 +6,12 @@ from backend_app.models.abstract.scholarship import ( ScholarshipViewSet, ) from backend_app.models.university import University +from backend_app.permissions.moderation import ModerationLevels class UniversityScholarship(Scholarship): + moderation_level = ModerationLevels.DEPENDING_ON_SITE_SETTINGS + universities = models.ManyToManyField( University, related_name="university_scholarships" ) @@ -17,10 +20,11 @@ class UniversityScholarship(Scholarship): class UniversityScholarshipSerializer(ScholarshipSerializer): class Meta: model = UniversityScholarship - fields = "__all__" + fields = ScholarshipSerializer.Meta.fields + ("universities",) class UniversityScholarshipViewSet(ScholarshipViewSet): + permission_classes = ScholarshipViewSet.permission_classes queryset = UniversityScholarship.objects.all() # pylint: disable=E1101 serializer_class = UniversityScholarshipSerializer end_point_route = "universityScholarships" diff --git a/backend/backend_app/models/universitySemestersDates.py b/backend/backend_app/models/universitySemestersDates.py index 24ae91ee2dcb04b3aaf6107846ecaf8b1a2fadf3..1ba216bcf56318c74d5b6522f1cf10392a8a125c 100644 --- a/backend/backend_app/models/universitySemestersDates.py +++ b/backend/backend_app/models/universitySemestersDates.py @@ -3,6 +3,7 @@ from rest_framework import serializers from backend_app.models.abstract.module import Module, ModuleSerializer, ModuleViewSet from backend_app.models.university import University +from backend_app.permissions.moderation import ModerationLevels def semester_error(semester_name): @@ -12,9 +13,11 @@ def semester_error(semester_name): class UniversitySemestersDates(Module): + moderation_level = ModerationLevels.DEPENDING_ON_SITE_SETTINGS + university = models.OneToOneField( University, - on_delete=models.CASCADE, + on_delete=models.PROTECT, related_name="university_semesters_dates", primary_key=True, null=False, @@ -49,10 +52,17 @@ class UniversitySemestersDatesSerializer(ModuleSerializer): class Meta: model = UniversitySemestersDates - fields = "__all__" + fields = ModuleSerializer.Meta.fields + ( + "university", + "spring_begin", + "spring_end", + "autumn_begin", + "autumn_end", + ) class UniversitySemestersDatesViewSet(ModuleViewSet): + permission_classes = ModuleViewSet.permission_classes queryset = UniversitySemestersDates.objects.all() # pylint: disable=E1101 serializer_class = UniversitySemestersDatesSerializer end_point_route = "universitiesSemestersDates" diff --git a/backend/backend_app/models/userData.py b/backend/backend_app/models/userData.py index df8e697e07d4d4affa920c4e93616f771247f834..a94dfd87b516dba16cd1610d8c2490d4d959b3db 100644 --- a/backend/backend_app/models/userData.py +++ b/backend/backend_app/models/userData.py @@ -54,7 +54,13 @@ class UserDataSerializer(BaseModelSerializer): class Meta: model = UserData - fields = "__all__" + fields = BaseModelSerializer.Meta.fields + ( + "owner", + "owner_level", + "owner_can_post_to", + "owner", + "theme", + ) class UserDataViewSet(BaseModelViewSet): diff --git a/backend/backend_app/viewsets.py b/backend/backend_app/viewsets.py index 3e2b0c8228e87e24e469e5f5dcfa77012b1f6eff..f4b1309e71d3b67987a45c5542e4b97c3c84b7cf 100644 --- a/backend/backend_app/viewsets.py +++ b/backend/backend_app/viewsets.py @@ -44,7 +44,13 @@ from backend_app.models.universityScholarship import UniversityScholarshipViewSe from backend_app.models.universitySemestersDates import UniversitySemestersDatesViewSet from backend_app.models.userData import UserDataViewSet from backend_app.models.version import VersionViewSet -from backend_app.permissions.app_permissions import ReadOnly, IsStaff, NoDelete, NoPost +from backend_app.permissions.app_permissions import ( + ReadOnly, + IsStaff, + NoDelete, + NoPost, + IsAuthenticated, +) from backend_app.serializers import ( CourseFeedbackSerializer, ExchangeSerializerSimple, @@ -79,7 +85,10 @@ class CourseFeedbackPermission(BasePermission): """ def has_object_permission(self, request, view, obj): - return request.user.pk == obj.course.exchange.student.pk + student = obj.course.exchange.student + if student is None: + return False + return request.user.pk == student.pk class CourseFeedbackViewSet(EssentialModuleViewSet): @@ -284,7 +293,7 @@ class DeleteUserViewSet(ViewSet): """ end_point_route = "emptyUserAccount" - permission_classes = tuple() + permission_classes = (IsAuthenticated,) def create(self, request): """ @@ -318,7 +327,7 @@ class RecommendationListChangeFollowerViewSet(ViewSet): # Since RecommendationListChangeFollowerViewSet doesn't inherit from BaseModelViewSet # We need to link here the correct permissions end_point_route = "recommendationListChangeFollower" - permission_classes = tuple() + permission_classes = (IsAuthenticated,) def update(self, request, pk=None): if pk is None: diff --git a/backend/cron_tasks.py b/backend/cron_tasks.py index 99199622405586ab88d7f07fdb390fa28f93bf2a..a72893856cd7dd963176789da4a5f87e670ff68d 100644 --- a/backend/cron_tasks.py +++ b/backend/cron_tasks.py @@ -26,7 +26,7 @@ logger = logging.getLogger("django") # @timer(60, target="spooler") # use this for tests -@cron(0, 0, -1, -1, -1, target="spooler") # everyday at midnight +@timer(3 * 60 * 60, target="spooler") # run it three hours @harakiri(40) def update_currencies(num): FixerData().update() diff --git a/backend/init_prod_data.py b/backend/init_prod_data.py new file mode 100644 index 0000000000000000000000000000000000000000..2dc8fda1928f0aa34f4525ae2a9751b4ed961c8c --- /dev/null +++ b/backend/init_prod_data.py @@ -0,0 +1,5 @@ +# To be used with the Makefile + +from backend_app.load_data.load_all import load_prod + +load_prod() diff --git a/docker-compose.yml b/docker-compose.yml index d7c28be77d81384a7068561a0e5cebcd7e04e9ce..ea0fe942567a37a363bcae61d75105e0e68697a6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,6 +10,7 @@ version: '3.7' volumes: # Create some local volume (should be stored in some directory on your computer) postgres_data: + media_files: networks: backend-nginx: @@ -25,7 +26,7 @@ services: # To use a locally built one, comment above, uncomment bellow. # build: ./backend restart: on-failure - volumes: [".:/usr/src/app/"] # "Copy" the repo to the workdir. + volumes: [".:/usr/src/app/", "media_files:/usr/src/app/backend/media"] # "Copy" the repo to the workdir and store media files on volume. networks: [backend-nginx, backend-db] environment: WAIT_HOSTS: database:5432 # For the 'wait' script, so that we are sure the db is up and running @@ -43,7 +44,7 @@ services: restart: always volumes: - ./backend/static/:/usr/src/static:ro - - ./backend/media/:/usr/src/media:ro + - media_files:/usr/src/media:ro networks: [backend-nginx, map-nginx] ports: # The port 8000 of the host is redirected to the port 80 of the container diff --git a/documentation/Other/cgu.md b/documentation/Other/cgu.md index e47b3604ef5a7210e4c9aef492627d69ab247b67..115aa17db1bc2002f8cbd9a4560292dc735a317b 100644 --- a/documentation/Other/cgu.md +++ b/documentation/Other/cgu.md @@ -35,14 +35,14 @@ En raison du format de la plateforme, le degré de fiabilité des informations m ### Définitions des licences -La licence « **REX-DRI-BY** » se définit comme étant une licence CC-BY ([https://creativecommons.org/licenses/by/2.0/fr/](https://creativecommons.org/licenses/by/2.0/fr/)) restreinte dont : +La licence « **REX-DRI—BY** » se définit comme étant une licence CC-BY ([https://creativecommons.org/licenses/by/2.0/fr/](https://creativecommons.org/licenses/by/2.0/fr/)) restreinte dont : - Le droit à « l'adaptation » est restreint à toute personne physique pouvant accéder à la plateforme REX-DRI ([https://rex.dri.utc.fr](https://rex.dri.utc.fr)) - Le droit au « partage » est restreint au fait que le contenu partagé (adapté ou non) n'est accessible qu'aux utilisateurs de la plateforme REX-DRI ou derrière le système d'authentification central de l'UTC ([https://cas.utc.fr/cas/login](https://cas.utc.fr/cas/login)) -La licence « **REX-DRI-PRIVATE** » se définit comme suit : +La licence « **REX-DRI—PRIVATE** » se définit comme suit : Sauf mention contraire de votre part, vous détenez tous les droits sur le contenu concerné par cette licence. @@ -78,7 +78,7 @@ Tout manquement aux présentes CGU pourra donner lieu à des sanctions proportio ## Mentions légales -Le **SIMDE** (Service informatique de la Maison Des Étudiants -- commission du Bureau Des Étudiants de l'Université de Technologie de Compiègne) met à disposition la plateforme REX-DRI ([https://rex.dri.utc.fr](https://rex.dri.utc.fr)) pour une durée indéterminée. +Le **SIMDE** (Service informatique de la Maison Des Étudiants — commission du Bureau Des Étudiants de l'Université de Technologie de Compiègne) met à disposition la plateforme REX-DRI ([https://rex.dri.utc.fr](https://rex.dri.utc.fr)) pour une durée indéterminée. contact : [simde@assos.utc.fr](mailto:simde@assos.utc.fr) diff --git a/frontend/src/components/app/ExternalDataUpdateInfo.js b/frontend/src/components/app/ExternalDataUpdateInfo.js index b70c029be7f984d8631ed8bad23495c970427afa..1a30766444e6392b05e00ffceb49d31922536165 100644 --- a/frontend/src/components/app/ExternalDataUpdateInfo.js +++ b/frontend/src/components/app/ExternalDataUpdateInfo.js @@ -12,7 +12,7 @@ import {toDateFr} from "../../utils/dateToFr"; import Typography from "@material-ui/core/Typography"; function getLabel(source) { - if (source === "fixer") return "Données concernant les taux de change (Fixer)"; + if (source === "fixer") return "Données concernant les taux de change"; if (source === "utc") return "Données issues de l'ENT"; return "Donnée externe non connue"; } diff --git a/frontend/src/components/app/Logo.js b/frontend/src/components/app/Logo.js index 38d461a7b40dda437ec00cc5f8e0205232a77c41..1bb3e864dc1c4948571b4c92212f329c492cfb35 100644 --- a/frontend/src/components/app/Logo.js +++ b/frontend/src/components/app/Logo.js @@ -45,6 +45,16 @@ const useStyle = makeStyles(theme => ({ backgroundColor: "transparent", right: -4 }, + logoBeta: { + position: "absolute", + right: -19, + bottom: 15, + height: 9, + zIndex: 0, + fontWeight: 900, + fontSize: 25, + color: theme.palette.getContrastText(theme.palette.primary.main), + } })); function Core() { @@ -59,6 +69,7 @@ function Core() { className={classes.iconChip} color="primary"/>
+
β
); } diff --git a/frontend/src/components/app/MainAppFrame.js b/frontend/src/components/app/MainAppFrame.js index f12149bc84298ae1d07ab566f42b4633f1112133..a41c8a5f8ed1af63fc09455f77f113e5b2a69a69 100644 --- a/frontend/src/components/app/MainAppFrame.js +++ b/frontend/src/components/app/MainAppFrame.js @@ -51,7 +51,9 @@ const styles = theme => ({ contrastTextSecondary: { color: theme.palette.getContrastText(theme.palette.secondary.main), }, - mobileIcon: {}, + mobileIcon: { + color: theme.palette.getContrastText(theme.palette.primary.main), + }, mobileIconContainer: { marginLeft: theme.spacing(1), marginRight: theme.spacing(1), @@ -187,7 +189,7 @@ class MainAppFrame extends React.Component { return (

Une erreur est survenue lors du téléchargement des données. Merci de recharger la page et si l'erreur - persiste, merci de contacter les administrateurs du site.

+ persiste, merci de contacter le SIMDE.

); } diff --git a/frontend/src/components/common/LicenseNotice.js b/frontend/src/components/common/LicenseNotice.js new file mode 100644 index 0000000000000000000000000000000000000000..a6a627ad44af1aad2704acb0cfef26e8884bf09c --- /dev/null +++ b/frontend/src/components/common/LicenseNotice.js @@ -0,0 +1,28 @@ +import React from "react"; +import PropTypes from "prop-types"; +import Typography from "@material-ui/core/Typography"; +import TextLink from "./TextLink"; +import {APP_ROUTES} from "../../config/appRoutes"; +import getWindowBase from "../../utils/getWindowBase"; + +/** + * Component to render the links in custom manner + * + */ +function LicenseNotice(props) { + return ( + <> + + Ce contenu est sous license {props.variant}. + Plus d'informations à ce propos sont disponibles  + ici. + + + ); +} + +LicenseNotice.propTypes = { + variant: PropTypes.oneOf(["REX-DRI—PRIVATE", "REX-DRI—BY"]).isRequired, +}; + +export default LicenseNotice; diff --git a/frontend/src/components/common/markdown/Markdown.js b/frontend/src/components/common/markdown/Markdown.js index 6b34cc332cead86cb183c952230b3dbfad89c99b..78f1acf5a3cc48768e1735fd9b7123e1165a461c 100644 --- a/frontend/src/components/common/markdown/Markdown.js +++ b/frontend/src/components/common/markdown/Markdown.js @@ -17,14 +17,14 @@ function compileSource(source) { const {amount, currency} = el; if (currency === "EUR") { - compiled += `${amount.toFixed(2)}€`; + compiled += `${amount}€`; } else { const converted = convertAmountToEur(amount, currency); - compiled += `${amount.toFixed(2)} ${currency} `; + compiled += `${amount} ${currency} `; if (converted === null) { compiled += `*(\`${currency}\` n'a pas été reconnue comme le code d'une monnaie ; nous n'avons pas pu procéder à une conversion automatique)*`; } else { - compiled += `[*(≈ ${converted.toFixed(2)}€)*](https://www.xe.com/currencyconverter/convert/?Amount=${amount}&From=${currency}&To=EUR)`; // add money converted information in markdown format + compiled += `[*(≈ ${converted}€)*](https://www.xe.com/currencyconverter/convert/?Amount=${amount}&From=${currency}&To=EUR)`; // add money converted information in markdown format } } } diff --git a/frontend/src/components/form/Form.js b/frontend/src/components/form/Form.js index cfb92b6c0f434757f669326252b8ba26d2f5b1a7..3eea5f0879096a5b045c0bb917a67c63c74cc982 100644 --- a/frontend/src/components/form/Form.js +++ b/frontend/src/components/form/Form.js @@ -1,9 +1,11 @@ -import {Component} from "react"; +import React, {Component} from "react"; import PropTypes from "prop-types"; import isEqual from "lodash/isEqual"; import renderFieldsMixIn from "./renderFieldsMixIn"; import CustomError from "../common/CustomError"; +import LicenseNotice from "../common/LicenseNotice"; +import Divider from "@material-ui/core/Divider"; /** * Function to build a chached version of the fields mapping to cascade update. @@ -42,6 +44,12 @@ function buildFieldUpdateCache(formLevelErrors) { */ class Form extends Component { + /** + * Default license applied when in the form. + * @type {string} + */ + license = "REX-DRI—BY"; + /** * * @@ -269,6 +277,21 @@ class Form extends Component { return new CustomError(errors); } + renderCore() { + throw new Error("Dev you forgot to override a method"); + } + + render() { + return ( + <> +
+ + +
+ {this.renderCore()} + + ); + } } // Copy all the custom already ready render fields mix in diff --git a/frontend/src/components/form/fields/NumberField.js b/frontend/src/components/form/fields/NumberField.js index e1aebef15e80254d0a00510602d507204cdd9d3f..94b4a80b5991f54eb777e6923b499932344d18b7 100644 --- a/frontend/src/components/form/fields/NumberField.js +++ b/frontend/src/components/form/fields/NumberField.js @@ -38,6 +38,11 @@ class NumberField extends Field { return new CustomError(messages); } + serializeFromField() { + const value = super.serializeFromField(); + return parseFloat(value); + } + handleChangeValue(val) { const regex = /[^\d.-]*/gi, value = val.replace(regex, ""); diff --git a/frontend/src/components/pages/PageAboutProject.js b/frontend/src/components/pages/PageAboutProject.js index 279a5acf64cbf706d2671d58a5173385cf2e0ae1..1659661e027364fe5fad8c84ad897e3e331665f2 100644 --- a/frontend/src/components/pages/PageAboutProject.js +++ b/frontend/src/components/pages/PageAboutProject.js @@ -7,11 +7,35 @@ import {withPaddedPaper} from "./shared"; const source = ` -# TODO +# Genèse + +La plateforme REX-DRI est née de la volonté d'un ex-représentant étudiant +au CÉVU et d'une large concertation. Elle a ouvert ses portes à l'été 2019 🎉. + +À ce jour, c'est le fruit d'un paquet d'heures de travail bénévole, d'une PR, et du soutien +technique de la DSI. + +L'objectif est, et a toujours été, de faciliter les mobilités sortantes en proposant +une plateforme d'information faisant la part belle à la contribution et la mise à disposition +de données issues de l'ENT. Le tout dans le respect du RGPD. + + +Aujourd'hui, la plateforme est sous la responsabilité du SIMDE ❤ + # Contribuer -Rendez vous sur [le GitLab de l'UTC](https://gitlab.utc.fr/rex-dri/rex-dri) ! +REX-DRI n'a pas vocation à être immobilisée pour de longues années. +Au contraire même ! Si vous avez envie de mettre la main à la pâte pour l'améliorer et proposer une +expérience toujours plus stable, performante ou complète, il y a moult possibilités autour de cette pépite Open Source. + +* [Ouvrir une issue](https://gitlab.utc.fr/rex-dri/rex-dri/issues) pour remonter un problème +ou faire une demande de fonctionnalité. +* Résoudre des issues, bénévolement ou au travers d'une PR. + +**Toute aide est la bienvenue, c'est un projet très riche !** + +Dans tous les cas, tout se passe sur [le GitLab de l'UTC](https://gitlab.utc.fr/rex-dri/rex-dri) 😄 `; diff --git a/frontend/src/components/pages/PageHome.js b/frontend/src/components/pages/PageHome.js index 3bf595e5bc98742f89622fdbf35ab3e7a84e0423..752396cff6d64e27dd6b29cde2c04f17d45ff776 100644 --- a/frontend/src/components/pages/PageHome.js +++ b/frontend/src/components/pages/PageHome.js @@ -18,22 +18,26 @@ Vous y retrouvez: * Les précédents départs effectués, * Une carte des universités partenaires, * Toutes les bonnes informations contribuées par les uns et les autres, -* Des listes mélant universités et commentaires à votre guise, +* Des listes mêlant universités et commentaires à votre guise, * etc. Les valeurs de la plateforme sont : **bienveillance**, **partage**, **contribution** et **collaboration**. Aidez-nous à les diffuser ! 😉 + +**Le bon réflexe** : penser à [donner les autorisations de partage d'informations (**cours et login**) avec +la plateforme REX-DRI depuis l'ENT](https://webapplis.utc.fr/etudiant/suiviOutgoing/autorisationsREX.faces) +pour enrichir automatiquement la plateforme. `; const sourceFocusMarkdown = ` De nombreux éléments de saisie supportent la syntaxe [markdown](https://www.markdownguide.org/basic-syntax/) -pour un rendu plus nuancé, faîtes-en bon usage 😌 (vive le **gras**, l'*italique*, etc.). +pour un rendu plus nuancé, faites-en bon usage 😌 (vive le **gras**, l'*italique*, etc.). -**Dès que vous parler d'💰, nous vous invitons à utiliser la syntaxe dédiée** \`:100.10USD:\` (\`:\` suivi du montant et - du code ISO de la monnaie, puis de nouveau \`:\`) dans votre markdown. -Cette dernière sera automatiquement reconnu et la valeur après application du taux de change du jour -sera automatiquement affichée en euro : :100.10USD: 🎉 +**Dès que vous parlez d'💰, nous vous invitons à utiliser la syntaxe dédiée** \`:100.10USD:\` +(deux-points, suivi du montant et du code ISO de la monnaie, puis de nouveau deux-points) dans votre markdown. +Cette dernière sera automatiquement reconnue et la valeur après application du taux de change du jour +sera affichée en euro : :1100.10USD: 🎉 `; @@ -44,7 +48,7 @@ function PageHome() { return ( <> - Bienvenue sur REX-DRI ! + Bienvenue sur REX-DRI @@ -55,9 +59,10 @@ function PageHome() { Amélioration continue - Un bug 🐇 ? Une fonctionnalité qui vous manque ? Envie de contribuer (bénévolement/PR) 😍 ? Plus + Un bug 🐇 ? Une typo ? Une fonctionnalité qui vous manque ? Envie de contribuer (bénévolement/PR) 😍 ? Plus d'informations ici. + Informations dynamiques diff --git a/frontend/src/components/pages/PageMyExchanges.js b/frontend/src/components/pages/PageMyExchanges.js index e7ea3e12a03f6942a469a1411e473bcad82418e9..0cc2acace38be715e42522bd9d8cb5dfb11ee6d9 100644 --- a/frontend/src/components/pages/PageMyExchanges.js +++ b/frontend/src/components/pages/PageMyExchanges.js @@ -84,7 +84,7 @@ class PageMyExchanges extends CustomComponentForAPI { if (isReloadingFromEnt) { return ( <> - Rechargement en cours + Rechargement en cours ); @@ -92,14 +92,14 @@ class PageMyExchanges extends CustomComponentForAPI { return ( <> {this.renderReloadInformation()} - Aucun échange n'est associé à votre compte. + Aucun échange n'est associé à votre compte. ); } else { return ( <> {this.renderReloadInformation()} - Les échanges que j'ai effectué + Les échanges que j'ai effectué (cliquer sur un départ pour éditer votre feedback sur ce dernier) diff --git a/frontend/src/components/pages/PageUniversity.js b/frontend/src/components/pages/PageUniversity.js index 7b6c0be5da333fd104d3e78d47da18ae2fa846c2..401641a41585a0be03b6864ec8494fd1d9236571 100644 --- a/frontend/src/components/pages/PageUniversity.js +++ b/frontend/src/components/pages/PageUniversity.js @@ -81,9 +81,8 @@ class PageUniversity extends CustomComponentForAPI { return ( - C'est la première fois que vous consulter cet onglet. Nous vous invitons à parcourir - les universités dans un - premier temps. 😁 + C'est la première fois que vous consultez cet onglet. Nous vous invitons à parcourir + les universités dans un premier temps. 😁 ); diff --git a/frontend/src/components/recommendation/view/View.js b/frontend/src/components/recommendation/view/View.js index 6cd107557f4ccaf4e1dceb9f457a90b1e62411a5..b9996c006741012938032a78a9e691b491194119 100644 --- a/frontend/src/components/recommendation/view/View.js +++ b/frontend/src/components/recommendation/view/View.js @@ -37,6 +37,7 @@ import {Prompt} from "react-router-dom"; import CopyToClipboard from "../../common/CopyToClipboard"; import Divider from "@material-ui/core/Divider"; import LinkToUser from "../../common/LinkToUser"; +import LicenseNotice from "../../common/LicenseNotice"; const FORGET_SAVE_MESSAGE = "Des changements n'ont pas été enregistré !"; @@ -334,6 +335,7 @@ class View extends React.Component { return (
+ /#?([0-9a-f]{6})/i.test(string); @@ -215,7 +216,7 @@ class ColorTool extends CustomComponentForAPI { Réglages avancés des couleurs - + Ci-dessous, vous pouvez choisir les couleurs dominantes du site. Celles-ci dépendent de l'état d'activation du « mode nuit ». @@ -263,6 +264,7 @@ class ColorTool extends CustomComponentForAPI { Réglages + editorStyle(theme); class CountryDriForm extends Form { - render() { + renderCore() { return ( <> {this.renderTitleField()} diff --git a/frontend/src/components/university/editors/SharedUnivFeedbackEditor.js b/frontend/src/components/university/editors/SharedUnivFeedbackEditor.js index 184db30d5232a853e5de3a5360bbc38beaca973e..d3ee3ce4ee559ae68e15a61dbb5a25981512a5f7 100644 --- a/frontend/src/components/university/editors/SharedUnivFeedbackEditor.js +++ b/frontend/src/components/university/editors/SharedUnivFeedbackEditor.js @@ -25,7 +25,7 @@ plutôt aux étudiantes et étudiants qui ont été sélectionnés pour partir e class SharedUnivFeedbackForm extends Form { - render() { + renderCore() { return ( <> diff --git a/frontend/src/components/university/editors/TaggedItemEditor.js b/frontend/src/components/university/editors/TaggedItemEditor.js index 4718690c9c6a4f7ee967fe22ece487425f04af03..36278629da7fab5d57a56026942965d8f4691696 100644 --- a/frontend/src/components/university/editors/TaggedItemEditor.js +++ b/frontend/src/components/university/editors/TaggedItemEditor.js @@ -16,7 +16,7 @@ const styles = theme => editorStyle(theme); class TaggedItemForm extends Form { - render() { + renderCore() { const {modelData} = this.props; return ( <> diff --git a/frontend/src/components/university/editors/UniversityDriEditor.js b/frontend/src/components/university/editors/UniversityDriEditor.js index 2a531bdff43acd4f5336232be8a1cb261e624c70..c88707ad2276dacf80c198b314cdd90fae962b64 100644 --- a/frontend/src/components/university/editors/UniversityDriEditor.js +++ b/frontend/src/components/university/editors/UniversityDriEditor.js @@ -15,7 +15,7 @@ import { withSnackbar } from "notistack"; const styles = theme => editorStyle(theme); class UniversityDriForm extends Form { - render() { + renderCore() { return ( <> {this.renderTitleField()} diff --git a/frontend/src/components/university/editors/UniversityGeneralEditor.js b/frontend/src/components/university/editors/UniversityGeneralEditor.js index 41a62248c33644ac64eef8086a0ab5009b3b85b5..47a0c95263de00174eb20dc13de5d2e8c421e718 100644 --- a/frontend/src/components/university/editors/UniversityGeneralEditor.js +++ b/frontend/src/components/university/editors/UniversityGeneralEditor.js @@ -16,7 +16,7 @@ const styles = theme => editorStyle(theme); class UniversityGeneralForm extends Form { - render() { + renderCore() { return ( <> {this.renderObjModerationLevelField()} diff --git a/frontend/src/components/university/editors/common/ScholarshipForm.js b/frontend/src/components/university/editors/common/ScholarshipForm.js index c728c5e3fcc2f6cf8e6b767510913ea7e2dcc27f..ab54dffce693bac00b8486272fb1b2202188ba0e 100644 --- a/frontend/src/components/university/editors/common/ScholarshipForm.js +++ b/frontend/src/components/university/editors/common/ScholarshipForm.js @@ -23,9 +23,13 @@ class ScholarshipForm extends Form { ["amount_min", "amount_max"], (amountMin, amountMax) => amountMin !== null && amountMax !== null && amountMax < amountMin, "La logique voudrait que la borne supérieure de la bourse soit... supérieure à la borne inférieure."), + new FormLevelError( + ["currency", "amount_min", "amount_max"], + (currency, amountMin, amountMax) => (amountMin || amountMax || amountMin === 0 || amountMax === 0) && !currency, + "Veuillez saisir la devise associée."), ]; - render() { + renderCore() { return ( <> {this.renderObjModerationLevelField()} diff --git a/frontend/src/components/university/modules/CountryScholarships.js b/frontend/src/components/university/modules/CountryScholarships.js index eb5eadf57cbaf990ee75c3f6338131862079c6e9..d2f12371a79390a9ec2f2619b88c8a037fc73a94 100644 --- a/frontend/src/components/university/modules/CountryScholarships.js +++ b/frontend/src/components/university/modules/CountryScholarships.js @@ -19,8 +19,12 @@ import {withUnivInfo} from "../common/withUnivInfo"; import {RequestParams} from "../../../redux/api/RequestParams"; -// eslint-disable-next-line no-unused-vars -const styles = theme => ({}); +const styles = theme => ({ + item: { + marginBottom: theme.spacing(2), + marginTop: theme.spacing(2), + } +}); function renderCore(rawModelData, classes, outsideData) { const {comment, frequency, currency, short_description} = rawModelData; @@ -59,7 +63,7 @@ class CountryScholarships extends Module { return ( { - countryScholarshipsItems.map((rawModelData, idx) => ( - modelData.title} - rawModelData={rawModelData} - editor={CountryScholarshipEditor} - renderCore={renderCore} - coreClasses={classes} - outsideData={outsideData} - moduleInGroupInfos={{isInGroup: true, invalidateGroup: () => this.props.invalidateData()}} - /> + countryScholarshipsItems.map(rawModelData => ( +
+ modelData.title} + rawModelData={rawModelData} + editor={CountryScholarshipEditor} + renderCore={renderCore} + coreClasses={classes} + outsideData={outsideData} + moduleInGroupInfos={{isInGroup: true, invalidateGroup: () => this.props.invalidateData()}} + /> +
)) }
diff --git a/frontend/src/components/university/modules/TaggedItem.js b/frontend/src/components/university/modules/TaggedItem.js index 467117b71b60ea59e3369c252afcd15dfe537afd..8a42bc82cf0b688f1df251ba9a33dfb998e5862a 100644 --- a/frontend/src/components/university/modules/TaggedItem.js +++ b/frontend/src/components/university/modules/TaggedItem.js @@ -15,7 +15,7 @@ function renderCore(rawModelData, classes, outsideData) { <> { comment.length === 0 ? - Aucune information n'est disponible... contribuer ! 😉 + Aucune information n'est disponible... contribuez ! 😉 : } diff --git a/frontend/src/components/university/modules/UniversityScholarships.js b/frontend/src/components/university/modules/UniversityScholarships.js index 4c40c95d6596ec9b3b698a04a663f359d775a693..e6a0881a50e888e501a7437a6a4f8ecd8c8f1ee8 100644 --- a/frontend/src/components/university/modules/UniversityScholarships.js +++ b/frontend/src/components/university/modules/UniversityScholarships.js @@ -15,12 +15,16 @@ import getActions from "../../../redux/api/getActions"; import {withUnivInfo} from "../common/withUnivInfo"; import {RequestParams} from "../../../redux/api/RequestParams"; -// eslint-disable-next-line no-unused-vars + const styles = theme => ({ + item: { + marginBottom: theme.spacing(2), + marginTop: theme.spacing(2), + } }); function renderCore(rawModelData, classes, outsideData) { - const { comment, frequency, currency, short_description } = rawModelData, + const {comment, frequency, currency, short_description} = rawModelData, amountMin = rawModelData.amount_min, amountMax = rawModelData.amount_max, otherAdvantages = rawModelData.other_advantages; @@ -47,7 +51,7 @@ class UniversityScholarships extends Module { customRender() { const univScholarshipsItems = this.getOnlyReadData("universityScholarships"), - { universities, currencies, classes } = this.props, + {universities, currencies, classes} = this.props, outsideData = { universities, currencies @@ -56,29 +60,35 @@ class UniversityScholarships extends Module { return ( { - univScholarshipsItems.map((rawModelData, idx) => ( - modelData.title} - rawModelData={rawModelData} - editor={UniversityScholarshipEditor} - renderCore={renderCore} - coreClasses={classes} - outsideData={outsideData} - moduleInGroupInfos={{ isInGroup: true, invalidateGroup: () => this.props.invalidateData() }} - /> + univScholarshipsItems.map(rawModelData => ( +
+ modelData.title} + rawModelData={rawModelData} + editor={UniversityScholarshipEditor} + renderCore={renderCore} + coreClasses={classes} + outsideData={outsideData} + moduleInGroupInfos={{isInGroup: true, invalidateGroup: () => this.props.invalidateData()}} + /> +
)) } -
+ ); } @@ -110,6 +120,6 @@ const mapDispatchToProps = (dispatch) => { export default compose( withUnivInfo(["universities", "currencies"]), - withStyles(styles, { withTheme: true }), + withStyles(styles, {withTheme: true}), connect(mapStateToProps, mapDispatchToProps) )(UniversityScholarships); diff --git a/frontend/src/components/university/modules/common/ModuleGroupWrapper.js b/frontend/src/components/university/modules/common/ModuleGroupWrapper.js index 915c26a9e282c44dd9ce719565f2509e7740025e..74c7a63885e1d0611214b51e35407e311689bbac 100644 --- a/frontend/src/components/university/modules/common/ModuleGroupWrapper.js +++ b/frontend/src/components/university/modules/common/ModuleGroupWrapper.js @@ -1,8 +1,8 @@ -import React, { Component } from "react"; +import React, {Component} from "react"; import PropTypes from "prop-types"; import withStyles from "@material-ui/core/styles/withStyles"; import compose from "recompose/compose"; -import { getLatestReadDataFromStore } from "../../../../redux/api/utils"; +import {getLatestReadDataFromStore} from "../../../../redux/api/utils"; import Typography from "@material-ui/core/Typography"; import Paper from "@material-ui/core/Paper"; @@ -37,7 +37,7 @@ class ModuleGroupWrapper extends Component { * @memberof ModuleGroupWrapper */ openEditorPanel() { - this.setState({ editorOpen: true }); + this.setState({editorOpen: true}); } /** @@ -47,14 +47,14 @@ class ModuleGroupWrapper extends Component { * @memberof ModuleGroupWrapper */ closeEditorPanel(somethingWasSaved = false) { - this.setState({ editorOpen: false }); + this.setState({editorOpen: false}); if (somethingWasSaved) { this.props.invalidateGroup(); } } render() { - const { classes, groupTitle, endPoint, defaultModelData } = this.props, + const {classes, groupTitle, endPoint, defaultModelData} = this.props, userCanPostTo = getLatestReadDataFromStore("userDataOne").owner_can_post_to, disabled = userCanPostTo.indexOf(endPoint) < 0; @@ -65,7 +65,8 @@ class ModuleGroupWrapper extends Component { rawModelData={defaultModelData} open={this.state.editorOpen} closeEditorPanel={(somethingWasSaved) => this.closeEditorPanel(somethingWasSaved)} - subscribeToModuleWrapper={() => { }} + subscribeToModuleWrapper={() => { + }} /> @@ -73,25 +74,26 @@ class ModuleGroupWrapper extends Component { {groupTitle} - + -
{/* Needed to fire events for the tooltip when below is disabled! */} +
{/* Needed to fire events for the tooltip when below is disabled! */} this.openEditorPanel()} > - +
- + {this.props.children} ); @@ -132,5 +134,5 @@ const styles = theme => ({ }); export default compose( - withStyles(styles, { withTheme: true }), + withStyles(styles, {withTheme: true}), )(ModuleGroupWrapper); diff --git a/frontend/src/components/university/modules/common/Scholarship.js b/frontend/src/components/university/modules/common/Scholarship.js index 88be0648c12133a3e1d18f94a9a128c6934db1df..a69b45c716e1271e94f6a7b0773c8d31d3732970 100644 --- a/frontend/src/components/university/modules/common/Scholarship.js +++ b/frontend/src/components/university/modules/common/Scholarship.js @@ -47,7 +47,7 @@ class Scholarship extends React.Component { y: "/année", o: "(une seule fois)" }; - const { frequency } = this.props; + const {frequency} = this.props; return table[frequency]; } @@ -56,12 +56,12 @@ class Scholarship extends React.Component { } convertAmountToEur(amount) { - const { currency } = this.props; + const {currency} = this.props; return moneyConversion(amount, currency); } getAmounts() { - const { amountMin, amountMax } = this.props; + const {amountMin, amountMax} = this.props; if (amountMax != null && amountMax != amountMin) { return `${amountMin}${this.getSymbol()} – ${amountMax}${this.getSymbol()}`; } else { @@ -70,7 +70,7 @@ class Scholarship extends React.Component { } getConvertedAmounts() { - const { amountMin, amountMax, currency } = this.props, + const {amountMin, amountMax, currency} = this.props, convertedMin = this.convertAmountToEur(amountMin); // we only need for errors in conversion on min. @@ -87,18 +87,19 @@ class Scholarship extends React.Component { } renderFinancialAdvantage() { - const { amountMin, currency, classes } = this.props; + const {amountMin, currency, classes} = this.props; return ( <> - Avantage financier : { amountMin !== null ? ( <> + Avantage financier : {this.getAmounts()}{" "}{this.getFrequency()} { currency != "EUR" ? - (≈ {this.getConvertedAmounts()}{" "}{this.getFrequency()}) + (≈ {this.getConvertedAmounts()}{" "}{this.getFrequency()}) : <> } @@ -112,32 +113,37 @@ class Scholarship extends React.Component { } renderOtherAdvantages() { - const { classes, otherAdvantages } = this.props; + const {classes, otherAdvantages} = this.props; + + if (otherAdvantages !== "" && otherAdvantages !== null) { + return ( + <> + Autre(s) avantage(s) : + + + ); + } - return ( - <> - Autre(s) avantage(s) : - { - otherAdvantages != "" && otherAdvantages !== null ? - - : - Aucun autre avantage a été notifié. - } - - ); + return <>; } render() { - const { shortDescription, comment, classes, theme } = this.props; + const {shortDescription, comment, classes, theme} = this.props; return ( <> {shortDescription} {this.renderFinancialAdvantage()} -
+
{this.renderOtherAdvantages()} - Informations complémentaires : - + { + comment ? + <> + Informations complémentaires : + + + : <> + } ); } @@ -146,7 +152,7 @@ class Scholarship extends React.Component { Scholarship.propTypes = { classes: PropTypes.object.isRequired, theme: PropTypes.object.isRequired, - currency: PropTypes.string.isRequired, + currency: PropTypes.string, frequency: PropTypes.string, shortDescription: PropTypes.string.isRequired, comment: PropTypes.string.isRequired, @@ -156,4 +162,4 @@ Scholarship.propTypes = { currencies: PropTypes.array.isRequired, }; -export default withStyles(styles, { withTheme: true })(Scholarship); +export default withStyles(styles, {withTheme: true})(Scholarship); diff --git a/frontend/src/components/university/modules/previousExchangeFeedback/PreviousExchange.js b/frontend/src/components/university/modules/previousExchangeFeedback/PreviousExchange.js index a2d6289666dc558df4ee05a312a36bd97d58a9ab..90628fc6784a1cfaa17151befafbd64cb52a1148 100644 --- a/frontend/src/components/university/modules/previousExchangeFeedback/PreviousExchange.js +++ b/frontend/src/components/university/modules/previousExchangeFeedback/PreviousExchange.js @@ -168,7 +168,7 @@ function PreviousExchange(props) { } { courses.length === 0 ? - Aucun cours n'est rataché à cet échange. + <> : }> diff --git a/frontend/src/components/university/modules/previousExchangeFeedback/edit/CourseFeedbackEditor.js b/frontend/src/components/university/modules/previousExchangeFeedback/edit/CourseFeedbackEditor.js index 960a4d2f0d6bd95d5916610db00deba32f84b479..ad697b1708fdd6d85d4e3af33a10d0f48c71dd08 100644 --- a/frontend/src/components/university/modules/previousExchangeFeedback/edit/CourseFeedbackEditor.js +++ b/frontend/src/components/university/modules/previousExchangeFeedback/edit/CourseFeedbackEditor.js @@ -21,7 +21,7 @@ const defaultNumberProps = { }; class CourseFeedbackForm extends Form { - render() { + renderCore() { return ( <> {this.renderLanguageField({ diff --git a/frontend/src/components/university/modules/previousExchangeFeedback/edit/GeneralFeedbackEditor.js b/frontend/src/components/university/modules/previousExchangeFeedback/edit/GeneralFeedbackEditor.js index 1a590a6b13ab02c0c34690c7c95f19fec7a61aa2..6883c17def5dd6a05209cd30b167342965ff20d0 100644 --- a/frontend/src/components/university/modules/previousExchangeFeedback/edit/GeneralFeedbackEditor.js +++ b/frontend/src/components/university/modules/previousExchangeFeedback/edit/GeneralFeedbackEditor.js @@ -22,7 +22,7 @@ const defaultNumberProps = { }; class GeneralFeedbackForm extends Form { - render() { + renderCore() { return ( <> ({ }, wideLeftCol: { flexGrow: 8, - flexShrink: 1, + flexShrink: 4, marginRight: theme.spacing(2), - minWidth: "40vh", }, wideRightCol: { flexGrow: 6, flexShrink: 6, - minWidth: "40vh", }, wideColItem: { marginBottom: theme.spacing(2), diff --git a/frontend/src/components/university/tabs/PreviousExchangesTab.js b/frontend/src/components/university/tabs/PreviousExchangesTab.js index d3e4848761c9ce2eaa6c7389430c66374443ddea..1ae8e6e89351ebc0f9a6809070e8c7a60606e227 100644 --- a/frontend/src/components/university/tabs/PreviousExchangesTab.js +++ b/frontend/src/components/university/tabs/PreviousExchangesTab.js @@ -15,6 +15,8 @@ import FormControl from "@material-ui/core/FormControl"; import withStyles from "@material-ui/core/styles/withStyles"; import uuid from "uuid/v4"; import Typography from "@material-ui/core/Typography"; +import CustomLink from "../../common/CustomLink"; +import {APP_ROUTES} from "../../../config/appRoutes"; const undefinedVal = uuid(); @@ -68,6 +70,12 @@ class PreviousExchangesTab extends CustomComponentForAPI { if (displayMinorSelect) minors = univMajorMinors.find(el => el.major === this.state.major).minors; return ( <> +
+ + Afin d'éditer vos avis sur vos échanges, rendez-vous directement sur cette page. + +
Branche diff --git a/frontend/src/components/user/PictureEditor.js b/frontend/src/components/user/PictureEditor.js index 5d605f4fc103427713dd9ffa2c091f7638faf169..1f547dac7d840e0f175a2356dcc5bcf1ec7a70cb 100644 --- a/frontend/src/components/user/PictureEditor.js +++ b/frontend/src/components/user/PictureEditor.js @@ -21,7 +21,7 @@ const styles = theme => ({ class PictureForm extends Form { - render() { + renderCore() { return ( <> { diff --git a/frontend/src/components/user/UserInfoEditor.js b/frontend/src/components/user/UserInfoEditor.js index 4df64c50b6575d06bdddb8a975340c1c3dcb7ee4..de3779bf5fbedd53627030616044b3fceb1368f4 100644 --- a/frontend/src/components/user/UserInfoEditor.js +++ b/frontend/src/components/user/UserInfoEditor.js @@ -18,7 +18,7 @@ import FormLevelError from "../form/FormLevelError"; const styles = theme => editorStyle(theme); class UserInfoForm extends Form { - + license = "REX-DRI—PRIVATE"; /** * @override */ @@ -33,7 +33,7 @@ class UserInfoForm extends Form { "Les modérateurs, membres de la DRI ainsi que les administrateurs du site sont forcés d'avoir un profil publique.") ]; - render() { + renderCore() { return ( <>