Commit 3a615383 authored by Florent Chehab's avatar Florent Chehab
Browse files

feat(standard filtering, tweaks): REST Api and other

* Filtering on client request should now be performed with the standard `?attr=...` syntaxe
* Frontend updated for this new syntaxe
* Backend and frontend documentation updated with new changes
* Updated the location of the the api documentation to `/api-doc`
* Fixed bug preventing api-doc to render
* backend python requirements updated
* Updated dockerfile / docker-compose to make sure we wait for the db

Fixes #97 #80
parent 243f43bf
Pipeline #37640 passed with stages
in 4 minutes and 23 seconds
......@@ -21,3 +21,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
RUN pip install --upgrade pip
COPY requirements.txt /usr/src/app/requirements.txt
RUN pip install -r requirements.txt
## Add the wait script to the image to wait for the database to be up for sure
ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.5.0/wait /wait
RUN chmod +x /wait
......@@ -359,6 +359,12 @@ class EssentialModuleViewSet(BaseModelViewSet):
This allows to not do this query for all elements and improves
performances. You can look at the comment below for more information.
"""
# When generating the API documentation (url: /api-doc) the request would be None
# and we don't need to do anything special
if self.request is None:
return super().get_serializer_context()
fake_edit_request = FakeRequest(self.request.user, "PUT")
user_can_edit = True
......
......@@ -26,8 +26,5 @@ class CampusTaggedItemSerializer(TaggedItemSerializer):
class CampusTaggedItemViewSet(TaggedItemViewSet):
queryset = CampusTaggedItem.objects.all() # pylint: disable=E1101
serializer_class = CampusTaggedItemSerializer
end_point_route = r"campusTaggedItems/(?P<campus_id>[0-9]+)"
def get_queryset(self):
campus_id = self.kwargs["campus_id"]
return super().get_queryset().filter(campus=campus_id).distinct()
end_point_route = "campusTaggedItems"
filterset_fields = ("campus",)
......@@ -26,8 +26,5 @@ class CityTaggedItemSerializer(TaggedItemSerializer):
class CityTaggedItemViewSet(TaggedItemViewSet):
queryset = CityTaggedItem.objects.all() # pylint: disable=E1101
serializer_class = CityTaggedItemSerializer
end_point_route = r"cityTaggedItems/(?P<city_id>[0-9]+)"
def get_queryset(self):
city_id = self.kwargs["city_id"]
return super().get_queryset().filter(city=city_id).distinct()
end_point_route = "cityTaggedItems"
filterset_fields = ("city",)
......@@ -19,8 +19,5 @@ class CountryDriViewSet(ModuleViewSet):
queryset = CountryDri.objects.all() # pylint: disable=E1101
serializer_class = CountryDriSerializer
permission_classes = (IsStaff | IsDri | NoPost,)
end_point_route = r"countryDri/(?P<country_id>[a-zA-Z]+)"
def get_queryset(self):
country_id = self.kwargs["country_id"]
return super().get_queryset().filter(countries__pk=country_id).distinct()
end_point_route = "countryDri"
filterset_fields = ("countries",)
......@@ -21,8 +21,5 @@ class CountryScholarshipSerializer(ScholarshipSerializer):
class CountryScholarshipViewSet(ScholarshipViewSet):
queryset = CountryScholarship.objects.all() # pylint: disable=E1101
serializer_class = CountryScholarshipSerializer
end_point_route = r"countryScholarships/(?P<country_id>[a-zA-Z]+)"
def get_queryset(self):
country_id = self.kwargs["country_id"]
return super().get_queryset().filter(countries__pk=country_id).distinct()
end_point_route = "countryScholarships"
filterset_fields = ("countries",)
......@@ -26,8 +26,5 @@ class CountryTaggedItemSerializer(TaggedItemSerializer):
class CountryTaggedItemViewSet(TaggedItemViewSet):
queryset = CountryTaggedItem.objects.all() # pylint: disable=E1101
serializer_class = CountryTaggedItemSerializer
end_point_route = r"countryTaggedItems/(?P<country_id>[a-zA-Z]+)"
def get_queryset(self):
country_id = self.kwargs["country_id"]
return super().get_queryset().filter(country=country_id).distinct()
end_point_route = "countryTaggedItems"
filterset_fields = ("country",)
......@@ -8,7 +8,6 @@ from backend_app.models.abstract.essentialModule import (
EssentialModuleSerializer,
EssentialModuleViewSet,
)
from backend_app.permissions.app_permissions import ReadOnly
from backend_app.validators.tags import validate_extension
......@@ -42,5 +41,4 @@ class UniversitySerializer(EssentialModuleSerializer):
class UniversityViewSet(EssentialModuleViewSet):
serializer_class = UniversitySerializer
queryset = University.objects.all() # pylint: disable=E1101
permission_classes = (ReadOnly,)
end_point_route = "universities"
......@@ -19,8 +19,5 @@ class UniversityDriViewSet(ModuleViewSet):
queryset = UniversityDri.objects.all() # pylint: disable=E1101
serializer_class = UniversityDriSerializer
permission_classes = (IsStaff | IsDri | ReadOnly,)
end_point_route = r"universityDri/(?P<univ_id>[0-9]+)"
def get_queryset(self):
univ_id = self.kwargs["univ_id"]
return super().get_queryset().filter(universities__pk=univ_id).distinct()
end_point_route = "universityDri"
filterset_fields = ("universities",)
......@@ -23,8 +23,5 @@ class UniversityScholarshipSerializer(ScholarshipSerializer):
class UniversityScholarshipViewSet(ScholarshipViewSet):
queryset = UniversityScholarship.objects.all() # pylint: disable=E1101
serializer_class = UniversityScholarshipSerializer
end_point_route = r"universityScholarships/(?P<univ_id>[0-9]+)"
def get_queryset(self):
univ_id = self.kwargs["univ_id"]
return super().get_queryset().filter(universities__pk=univ_id).distinct()
end_point_route = "universityScholarships"
filterset_fields = ("universities",)
......@@ -28,8 +28,5 @@ class UniversityTaggedItemViewSet(TaggedItemViewSet):
queryset = UniversityTaggedItem.objects.all() # pylint: disable=E1101
serializer_class = UniversityTaggedItemSerializer
permission_classes = (IsOwner,)
end_point_route = r"universityTaggedItems/(?P<univ_id>[0-9]+)"
def get_queryset(self):
univ_id = self.kwargs["univ_id"]
return super().get_queryset().filter(university__pk=univ_id).distinct()
end_point_route = "universityTaggedItems"
filterset_fields = ("university",)
......@@ -56,7 +56,6 @@ class VersionSerializer(BaseModelSerializer):
djangoSerializers.deserialize(obj.format, data, ignorenonexistent=True)
)[0]
# Version is valid,
print(self.get_serializers_mapping())
obj_serializer = self.get_serializers_mapping()[type(tmp.object).__name__]
new_context = dict(self.context)
new_context["view"].action = "list"
......
......@@ -210,5 +210,5 @@ class ModerationTestCase(WithUserTestCase):
c.save()
data = {"comment": "", "useful_links": [], "universities": [c.pk]}
api_end_point = "/api/universityDri/{}/".format(c.pk)
api_end_point = "/api/universityDri/?universities={}/".format(c.pk)
self._submit_post_test(self.dri_client, data, api_end_point)
......@@ -10,7 +10,7 @@ class WriteAccessTestCase(WithUserTestCase):
@classmethod
def setUpMoreTestData(cls):
cls.univ = University.objects.create(name="Univ de test", utc_id=100)
cls.api_dri = "/api/universityDri/{}/".format(cls.univ.pk)
cls.api_dri = "/api/universityDri/?universities={}/".format(cls.univ.pk)
cls.post_data = dict(
universities=[cls.univ.pk], title="qsdlkjqsmlkdj", useful_links="[]"
)
......
......@@ -8,7 +8,7 @@ from backend_app.viewsets import ALL_API_VIEWSETS, ALL_API_VIEW_VIEWSETS
# Building the API routing
#######
urlpatterns = [url(r"^api-docs/", include_docs_urls(title="Outgoing API"))]
urlpatterns = [url(r"^api-doc/", include_docs_urls(title="REX-DRI API"))]
# router will hold all api related endpoints
router = routers.DefaultRouter()
......
......@@ -67,6 +67,7 @@ INSTALLED_APPS = [
"backend_app",
"base_app",
"webpack_loader",
"django_filters",
]
#
......@@ -87,6 +88,7 @@ REST_FRAMEWORK = {
"rest_framework.authentication.SessionAuthentication",
"rest_framework.authentication.TokenAuthentication",
),
"DEFAULT_FILTER_BACKENDS": ("django_filters.rest_framework.DjangoFilterBackend",),
}
#
......
......@@ -9,3 +9,5 @@ while [ ! -f `dirname $0`/../frontend/webpack-stats.json ]; do
done
echo "Frontend staticfiles are ready (NB: not necessarly up-to-date)."
./manage.py collectstatic --noinput && ./manage.py runserver 0.0.0.0:8000
......@@ -3,6 +3,7 @@ Django==2.1.7
psycopg2-binary==2.7.7
django-cas-ng==3.6.0
djangorestframework==3.9.1
django-filter==2.1.0 # easy filtering on API
coreapi==2.3.3 # Automatic API doc generation
django-reversion==3.0.3
django-reversion-compare==0.8.6
......
......@@ -16,6 +16,7 @@ services:
image: registry.gitlab.utc.fr/rex-dri/rex-dri/backend:latest
# To use a locally build one, comment above, uncomment bellow.
# build: ./backend
restart: on-failure
volumes:
# "Copy" the repo to the workdir.
- .:/usr/src/app/
......@@ -35,10 +36,12 @@ services:
- POSTGRES_DB=postgres
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
# Specify host to wait for; ie we want to wait for the db for sure
- WAIT_HOSTS=database:5432
# Run the django developpement server on image startup.
command: /bin/sh -c "cd backend && ./waitForFrontend.sh && ./manage.py collectstatic --noinput && ./manage.py runserver 0.0.0.0:8000"
command: /bin/sh -c "/wait && cd backend && ./entry.sh"
depends_on:
# Required that the `database` and `frontend` service is up and running.
# Required that the `database` and `frontend` service are up and running.
- database
- frontend
......
......@@ -5,7 +5,7 @@ API
The backend `Django` app, with `Django Rest Framework` acts as an API. It is available at the URI `/api`.
An automated documentation is generated and available at the URI `/api-docs`.
An automated documentation is generated and available at the URI `/api-doc`.
## Authentication
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment