Commit 8a8e8cf6 authored by Florent Chehab's avatar Florent Chehab
Browse files

Merge branch 'frontend' into 'master'

New Frontend initialize

Closes #11

See merge request chehabfl/outgoing_rex!15
parents f7b3fc08 a157cc69
from backend.models.university import University
from backend.models.university.campus import CampusSerializer
from backend.models.university import UniversityDriSerializer
from backend.models.my_model import MyModelSerializer, MyModelViewSet
class UniversityModulesSerializer(MyModelSerializer):
univ_campus = CampusSerializer(many=True, read_only=True)
university_dri = UniversityDriSerializer(many=True, read_only=True)
class Meta:
model = University
fields = '__all__'
class UniversityModulesViewSet(MyModelViewSet):
serializer_class = UniversityModulesSerializer
def get_queryset(self):
univ_id = self.kwargs['univ_id']
return University.objects.filter(id=univ_id).prefetch_related('univ_campus', 'university_dri') # pylint: disable=E1101
# queryset = get_queryset()
from django.db import models
from backend.models.university import University
from backend.models.module import VersionnedModuleSerializer
from backend.models.module import Photo
from rest_framework import viewsets, permissions
from backend.models.module import Photo, PhotoSerializer, PhotoViewSet
class UniversityPhoto(Photo):
......@@ -16,14 +14,13 @@ class UniversityPhoto(Photo):
unique_together = ('university', 'photo')
class UniversityPhotoSerializer(VersionnedModuleSerializer):
class UniversityPhotoSerializer(PhotoSerializer):
class Meta:
model = UniversityPhoto
fields = '__all__'
class UniversityPhotoViewSet(viewsets.ModelViewSet): # TODO switch to dict
permission_classes = (permissions.DjangoModelPermissions,)
class UniversityPhotoViewSet(PhotoViewSet):
queryset = UniversityPhoto.objects.all() # pylint: disable=E1101
serializer_class = UniversityPhotoSerializer
from django.db import models
from backend.models.university import University
from backend.models.module import Scholarship, BasicModuleSerializer
from rest_framework import viewsets, permissions
from backend.models.module import Scholarship, ScholarshipSerializer, ScholarshipViewSet
class UniversityScholarship(Scholarship):
......@@ -9,14 +8,13 @@ class UniversityScholarship(Scholarship):
University, on_delete=models.PROTECT, null=False, related_name="univScholarship")
class UniversityScholarshipSerializer(BasicModuleSerializer):
class UniversityScholarshipSerializer(ScholarshipSerializer):
class Meta:
model = UniversityScholarship
fields = '__all__'
class UniversityScholarshipViewSet(viewsets.ModelViewSet):
permission_classes = (permissions.DjangoModelPermissions,)
class UniversityScholarshipViewSet(ScholarshipViewSet):
queryset = UniversityScholarship.objects.all() # pylint: disable=E1101
serializer_class = UniversityScholarshipSerializer
from django.db import models
from backend.models.module import BasicModule, BasicModuleSerializer
from backend.models.module import BasicModule, BasicModuleSerializer, BasicModuleViewSet
from backend.models.university import University
from rest_framework import serializers, viewsets, permissions
from rest_framework import serializers
def check_nones(val1, val2):
......@@ -55,7 +55,6 @@ class UniversitySemestersDatesSerializer(BasicModuleSerializer):
fields = '__all__'
class UniversitySemestersDatesViewSet(viewsets.ModelViewSet): # TODO switch to dict
permission_classes = (permissions.DjangoModelPermissions,)
class UniversitySemestersDatesViewSet(BasicModuleViewSet):
queryset = UniversitySemestersDates.objects.all() # pylint: disable=E1101
serializer_class = UniversitySemestersDatesSerializer
from .userRestrictedModule import UserRestrictedModule, UserRestrictedModuleSerializer # noqa: F401
from .userRestrictedModule import UserRestrictedModule, UserRestrictedModuleSerializer, UserRestrictedModuleViewSet # noqa: F401
from .previousDeparture import PreviousDeparture, PreviousDepartureViewSet # noqa: F401
from .previousDepartureFeedback import PreviousDepartureFeedback, PreviousDepartureFeedbackViewSet # noqa: F401
from .recommendationList import RecommendationList, RecommendationListSerializer, RecommendationListViewSet # noqa: F401
......
from django.db import models
from rest_framework import viewsets, permissions, serializers
from rest_framework import permissions
from backend.models.otherCore.specialty import Specialty
from backend.models.otherCore.semester import Semester
from backend.models.university import University
from django.contrib.auth.models import User
from django.contrib.postgres.fields import JSONField
from backend.models.my_model import MyModel, MyModelSerializer, MyModelViewSet
class PreviousDeparture(models.Model):
class PreviousDeparture(MyModel):
# This model should be filled with data from the ENT
semester = models.ForeignKey(Semester, on_delete=models.PROTECT)
university = models.ForeignKey(University, on_delete=models.PROTECT)
......@@ -23,14 +23,14 @@ class PreviousDeparture(models.Model):
# when someone delete the link and relink we can rematch the data
class PreviousDepartureSerializer(serializers.ModelSerializer):
class PreviousDepartureSerializer(MyModelSerializer):
class Meta:
model = PreviousDeparture
fields = '__all__'
class PreviousDepartureViewSet(viewsets.ModelViewSet):
class PreviousDepartureViewSet(MyModelViewSet):
permission_classes = (permissions.IsAdminUser,)
queryset = PreviousDeparture.objects.all() # pylint: disable=E1101
serializer_class = PreviousDepartureSerializer
......
from django.db import models
from rest_framework import viewsets, permissions
from django.core.validators import MaxValueValidator
from backend.models.user import UserRestrictedModule, UserRestrictedModuleSerializer
from backend.models.user import UserRestrictedModule, UserRestrictedModuleSerializer, UserRestrictedModuleViewSet
from backend.models.user import PreviousDeparture
from django.contrib.postgres.fields import JSONField
......@@ -28,7 +27,6 @@ class PreviousDepartureFeedbackSerializer(UserRestrictedModuleSerializer):
fields = '__all__'
class PreviousDepartureFeedbackViewSet(viewsets.ModelViewSet):
permission_classes = (permissions.DjangoModelPermissions,)
class PreviousDepartureFeedbackViewSet(UserRestrictedModuleViewSet):
queryset = PreviousDepartureFeedback.objects.all() # pylint: disable=E1101
serializer_class = PreviousDepartureFeedbackSerializer
from django.db import models
from rest_framework import viewsets, permissions
from rest_framework import permissions
from django.core.validators import MaxValueValidator
from backend.models.university import University
from backend.models.user import UserRestrictedModule, UserRestrictedModuleSerializer
from backend.models.user import UserRestrictedModule, UserRestrictedModuleSerializer, UserRestrictedModuleViewSet
from backend.models.otherCore import Specialty
from backend.models.user import RecommendationList
......@@ -30,7 +30,7 @@ class RecommendationSerializer(UserRestrictedModuleSerializer):
fields = '__all__'
class RecommendationViewSet(viewsets.ModelViewSet):
class RecommendationViewSet(UserRestrictedModuleViewSet):
permission_classes = (permissions.DjangoObjectPermissions,)
queryset = Recommendation.objects.all() # pylint: disable=E1101
serializer_class = RecommendationSerializer
......
from django.db import models
from rest_framework import viewsets, permissions
from backend.models.user import UserRestrictedModule, UserRestrictedModuleSerializer
from backend.models.user import UserRestrictedModule, UserRestrictedModuleSerializer, UserRestrictedModuleViewSet
class RecommendationList(UserRestrictedModule):
......@@ -8,7 +7,7 @@ class RecommendationList(UserRestrictedModule):
title = models.CharField(max_length=200)
class Meta:
unique_together = ('title', 'user')
unique_together = ('title', 'owner')
class RecommendationListSerializer(UserRestrictedModuleSerializer):
......@@ -18,8 +17,7 @@ class RecommendationListSerializer(UserRestrictedModuleSerializer):
fields = '__all__'
class RecommendationListViewSet(viewsets.ModelViewSet):
permission_classes = (permissions.DjangoModelPermissions,)
class RecommendationListViewSet(UserRestrictedModuleViewSet):
queryset = RecommendationList.objects.all() # pylint: disable=E1101
serializer_class = RecommendationListSerializer
# TODO add public support to check access rights
from django.db import models
from rest_framework import viewsets, permissions
from backend.models.tools import UsefullLinksField
from rest_framework import permissions, serializers
from backend.models.university import University
from django.contrib.postgres.fields import JSONField
from backend.models.user import UserRestrictedModule, UserRestrictedModuleSerializer
from backend.models.my_model import MyModel, MyModelSerializer, MyModelViewSet
from django.contrib.auth.models import User
from backend.models.tools import NoDelete, IsOwner
class UserData(UserRestrictedModule):
contact_info = UsefullLinksField(null=True)
class UserData(MyModel):
owner = models.OneToOneField(User, on_delete=models.CASCADE)
contact_info = JSONField(null=True, default={})
contact_info_is_public = models.BooleanField(default=False)
config = JSONField(null=True, default={})
black_list = models.ManyToManyField(
University, related_name='+', blank=True)
other_data = JSONField(null=True, default={})
class UserDataSerializer(UserRestrictedModuleSerializer):
class UserDataSerializer(MyModelSerializer):
owner = serializers.CharField(read_only=True)
def my_pre_save(self):
user = self.get_user_in_request()
self.override_validated_data({'owner': user})
# we try to recover the correct instance
query = UserData.objects.filter(owner=user)
if len(query) == 1:
self.instance = query[0]
class Meta:
model = UserData
fields = '__all__'
NEVER_MODERATE = True
class UserDataViewSet(viewsets.ModelViewSet):
permission_classes = (permissions.IsAdminUser,) # TODO change
queryset = UserData.objects.all() # pylint: disable=E1101
class UserDataViewSet(MyModelViewSet):
permission_classes = (
permissions.IsAuthenticated,
NoDelete,
IsOwner
)
serializer_class = UserDataSerializer
# TODO change to require a login not display all
def get_queryset(self):
return UserData.objects.filter(owner=self.request.user) # pylint: disable=E1101
from django.db import models
from rest_framework import serializers
from django.contrib.auth.models import User
from backend.models.my_model import MyModel, MyModelSerializer, MyModelViewSet
class UserRestrictedModule(models.Model):
class UserRestrictedModule(MyModel):
# RGPD made easy with CASCADE
user = models.ForeignKey(User, on_delete=models.CASCADE)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
# User is anonymised
is_anonymous = models.BooleanField(default=True)
......@@ -17,11 +18,15 @@ class UserRestrictedModule(models.Model):
abstract = True
class UserRestrictedModuleSerializer(serializers.ModelSerializer):
user = serializers.HiddenField(
class UserRestrictedModuleSerializer(MyModelSerializer):
owner = serializers.HiddenField(
default=serializers.CurrentUserDefault(),
) # TODO check that this works
class Meta:
model = UserRestrictedModule
fields = '__all__'
class UserRestrictedModuleViewSet(MyModelViewSet):
serializer_class = UserRestrictedModuleSerializer
from reversion.models import Version
import django.dispatch
new_revision_saved = django.dispatch.Signal(providing_args=["obj"])
def squashRevisionByUser(sender, obj, **kwargs):
"""
TODO add comment and unit test
It should also work with moderation as obj will be a versionned object
"""
versions = Version.objects\
.get_for_object(obj)\
.select_related('revision')\
.order_by('-revision__date_created')
last_edit = versions[0]
user_made_last_edit = last_edit.revision.user
if user_made_last_edit is not None:
for v in versions[1:]:
if v.revision.user == user_made_last_edit:
v.delete()
else:
break
new_revision_saved.connect(
squashRevisionByUser,
dispatch_uid="receiver_concat_revisions"
)
../../../node_modules/leaflet/dist/leaflet.css
\ No newline at end of file
{% extends 'main_website/base.html' %}
{% load staticfiles %}
{% block content %}
<div id="mapid" style="height:400px"></div>
<link rel="stylesheet" href="{% static 'css/leaflet.css' %}"/>
<script type="text/javascript" src="{% static 'js/leaflet.js' %}"></script>
<link rel="stylesheet" href="{% static 'css/MarkerCluster.css' %}"/>
<link rel="stylesheet" href="{% static 'css/MarkerCluster.Default.css' %}"/>
<script type="text/javascript" src="{% static 'js/leaflet.markercluster.js' %}"></script>
<script>
var Stamen_Watercolor = L.tileLayer('https://stamen-tiles-{s}.a.ssl.fastly.net/watercolor/{z}/{x}/{y}.{ext}', {
attribution: 'Map tiles by <a href="http://stamen.com">Stamen Design</a>, <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a> &mdash; Map data &copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
subdomains: 'abcd',
minZoom: 1,
maxZoom: 18,
ext: 'png'
});
var Stamen_Label = L.tileLayer('https://stamen-tiles-{s}.a.ssl.fastly.net/toner-labels/{z}/{x}/{y}.{ext}', {
attribution: 'Map tiles by <a href="http://stamen.com">Stamen Design</a>, <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a> &mdash; Map data &copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
subdomains: 'abcd',
minZoom: 1,
maxZoom: 18,
ext: 'png'
});
var OpenStreetMap_France = L.tileLayer('https://{s}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png', {
maxZoom: 20,
attribution: '&copy; Openstreetmap France | &copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
});
var Esri_WorldImagery = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
attribution: 'Tiles &copy; Esri &mdash; Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community'
});
var Stamen = L.layerGroup();
Stamen_Watercolor.addTo(Stamen);
Stamen_Label.addTo(Stamen);
var baseLayers = {
"Stamen Watercolor": Stamen,
"OpenStreetMap": OpenStreetMap_France,
"Satellite": Esri_WorldImagery
};
// End of handling of layers, now let's handle markers.
var universities_markers = L.markerClusterGroup();
{% for camp in campus %}
L.marker([{{ camp.lat }}, {{ camp.lon }}]).addTo(universities_markers)
.bindPopup("<b>{{ camp.university.name }}</b>");
{% endfor %}
// Creation of map
var mymap = L.map('mapid', {'layers':[Stamen, universities_markers]}).setView([45, 1.2], 4);
L.control.layers(baseLayers).addTo(mymap);
// Extra feature
var popup = L.popup();
function onMapClick(e) {
popup
.setLatLng(e.latlng)
.setContent("You clicked the map at " + e.latlng.toString())
.openOn(mymap);
}
mymap.on('click', onMapClick);
</script>
<!-- {% for univ in universities %}
<p>{{ univ.country.name }}</p>
{% endfor %} -->
{% endblock %}
\ No newline at end of file
# from django.test import TestCase
# Create your tests here.
from .withUserTestCase import WithUserTestCase # noqa: F401
from django.test import TestCase
from backend.load_data import load_all
class ModerationTestCase(TestCase):
def test_everything_loads(self):
try:
load_all()
except Exception:
self.fail("load_all() raised an Exception unexpectedly!")
from django.test import override_settings
from .withUserTestCase import WithUserTestCase
from backend.models.my_model import ForTestingModeration
from backend.models.my_model import PendingModeration
from django.contrib.contenttypes.models import ContentType
from django.conf import settings
class ModerationTestCase(WithUserTestCase):
@classmethod
def setUpMoreTestData(cls):
cls.api_moderation = '/api/test/moderation/'
def test_setting_ok(self):
self.assertTrue(settings.TESTING)
#####
def _submit_post_test(self, client, data):
response = client.post(
self.api_moderation,
data,
format='json'
)
self.assertEqual(response.status_code, 201)
return response
def _submit_put_test(self, client, data, pk):
response = client.put(
self.api_moderation + str(pk) + '/',
data,
format='json'
)
self.assertEqual(response.status_code, 200)
return response
def _test_retreive_instance(self, data):
matching = ForTestingModeration.objects.filter(
aaa=data['aaa']
)
self.assertTrue(matching.exists())
return matching[0]
def _test_retreive_instance_in_moderation(self, instance, expected_fail=False):
ct = ContentType.objects.get_for_model(ForTestingModeration)
pending = PendingModeration.objects.filter(
content_type=ct, object_id=instance.pk)
if expected_fail:
self.assertFalse(pending.exists())
return None
else:
self.assertTrue(pending.exists())
self.assertEqual(len(pending), 1)
return pending[0]
def _test_val_null(self, val1, null):
if null:
self.assertIsNone(val1)
else:
self.assertIsNotNone(val1)
def _test_moderated_val(self, instance, null=True):
self._test_val_null(instance.moderated_by, null)
self._test_val_null(instance.moderated_on, null)
def _test_updated_val(self, instance, null=True):
self._test_val_null(instance.updated_on, null)
self._test_val_null(instance.updated_by, null)
def _test_new_obj_val(self, instance, data):
self.assertEqual(
instance.new_object['aaa'],
data['aaa']
)
####
@override_settings(MODERATION_ACTIVATED=True)
def test_moderation_activated(self):
"""
Test to check that when moderation IS activated,
the app behaves as expected regarding creation
and moderation of models.
"""
# phase 1
# Need moderation
data_1 = {'aaa': "Test"}
self._submit_post_test(self.authenticated_client, data_1)
instance = self._test_retreive_instance(data_1)
self._test_updated_val(instance, null=True)
self._test_moderated_val(instance, null=True)
instance_in_moderation = self._test_retreive_instance_in_moderation(
instance)
self._test_updated_val(instance_in_moderation, null=False)
self._test_new_obj_val(instance_in_moderation, data_1)
# Phase 2
# More moderation
data_2 = {'aaa': "Test 2"}
self._submit_put_test(self.authenticated_client, data_2, instance.pk)
instance = self._test_retreive_instance(data_1) # not data_2 !
self._test_updated_val(instance, null=True)
self._test_moderated_val(instance, null=True)
instance_in_moderation = self._test_retreive_instance_in_moderation(
instance)
self._test_updated_val(instance_in_moderation, null=False)
# here we espect data_2
self._test_new_obj_val(instance_in_moderation, data_2)
# Phase 3
# Moderation with modification
data_3 = {'aaa': "Test 3"}
self._submit_put_test(self.moderator_client, data_3, instance.pk)
instance = self._test_retreive_instance(data_3) # not data_2 !
self._test_updated_val(instance, null=False)
self._test_moderated_val(instance, null=False)
self.assertEqual(instance.updated_by, self.moderator_user)
# (below) because the field aaa was updated by the moderator
self.assertEqual(instance.moderated_by, self.moderator_user)
instance_in_moderation = self._test_retreive_instance_in_moderation(
instance, True)
# Phase 4
# Put that require moderation
data_4 = {'aaa': "Test 4"}
self._submit_put_test(self.authenticated_client, data_4, instance.pk)
instance = self._test_retreive_instance(data_3) # not data_4 !
self._test_updated_val(instance, null=False) # Not True
self._test_moderated_val(instance, null=False) # Not True
instance_in_moderation = self._test_retreive_instance_in_moderation(
instance)
self._test_updated_val(instance_in_moderation, null=False)
# here we espect data_4
self. _test_new_obj_val(instance_in_moderation, data_4)
# Phase 5
# Moderation with no modification
self._submit_put_test(self.moderator_client, data_4, instance.pk)
instance = self._test_retreive_instance(data_4) # not data_2 !