From e534318dddcd4d819eeacceea20f1c84783afba2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Thu, 30 Apr 2020 16:23:56 +0200
Subject: [PATCH 3/3] okina: order endpoints and remove endpoints override in
 template (#17729)

---
 passerelle/apps/okina/models.py               | 198 +++++++++++++++---
 .../okina/templates/okina/okina_detail.html   |  80 -------
 2 files changed, 164 insertions(+), 114 deletions(-)

diff --git a/passerelle/apps/okina/models.py b/passerelle/apps/okina/models.py
index 4732cb00..ee296f89 100644
--- a/passerelle/apps/okina/models.py
+++ b/passerelle/apps/okina/models.py
@@ -35,6 +35,8 @@ class Okina(BaseResource):
 
     category = _('Business Process Connectors')
 
+    _category_ordering = [_('General'), _('Journeys'), _('Subscriptions'), _('Topology')]
+
     class Meta:
         verbose_name = _('Okina')
 
@@ -74,7 +76,10 @@ class Okina(BaseResource):
             raise APIError('HTTP request failed, error %s' % response.status_code, data=data)
         return data
 
-    @endpoint()
+    @endpoint(
+        display_category=_('General'),
+        display_order=1,
+        description=_('Cities'))
     def cities(self, request):
         okina_cities = self.request('cities')
         cities = []
@@ -90,7 +95,10 @@ class Okina(BaseResource):
         cities.sort(key=lambda x: x['text'])
         return {'data': cities}
 
-    @endpoint()
+    @endpoint(
+        display_category=_('General'),
+        display_order=2,
+        description=_('Classes'))
     def classes(self, request):
         return {'data': [{
             'id': '%s' % item['id'],
@@ -109,30 +117,52 @@ class Okina(BaseResource):
         institutions.sort(key=lambda x: x['text'])
         return institutions
 
-    @endpoint(parameters={
+    @endpoint(
+        display_category=_('General'),
+        display_order=3,
+        description=_('Institutions'))
+    def institutions(self, request):
+        return self.institutions(request)
+
+    @endpoint(
+        display_category=_('Journeys'),
+        display_order=2,
+        description=_('Institutions in a city (API 2020)'),
+        name='institutions',
+        parameters={
             'insee': {'description': _('INSEE City code'), 'example_value': '36005'},
         })
-    def institutions(self, request, insee=None):
+    def institutions_in_city(self, request, insee=None):
         if insee:
             query = '?' + urlencode({'inseeCode': insee})
         else:
             query = ''
         return {'data': self.get_institutions(query)}
 
-    @endpoint(name='institutions', pattern='^from-city/(?P<city_insee_code>\d+)/*$')
+    @endpoint(
+        display_category=_('Journeys'),
+        display_order=3,
+        description=_('Institutions accessible from a city'),
+        name='institutions',
+        pattern=r'^from-city/(?P<city_insee_code>\d+)/*$',
+        parameters={
+            'city_insee_code': {'description': _('INSEE City code'), 'example_value': '36005'},
+        })
     def institutions_from_city(self, request, city_insee_code):
         return {'data': self.get_institutions('/subscriberCity/%s' % city_insee_code)}
 
     @endpoint(
-            name='search', perm='can_access',
-            description=_('Get stop points based on a starting position and an arrival institution (API 2020)'),
-            parameters={
-                'lat': {'description': _('Latitude (departure)'), 'example_value': '46.828652'},
-                'lon': {'description': _('Longitude (departure)'), 'example_value': '1.701463'},
-                'address': {'description': _('Address (departure)')},
-                'institution': {'description': _('Institution ID (arrival)'), 'example_value': '277'},
-                'mode': {'description': _('Search mode: CLOSE_SCHOLAR (default) = 3km, FAR_ALL = 15km')},
-            })
+        display_category=_('Journeys'),
+        display_order=1,
+        name='search', perm='can_access',
+        description=_('Get stop points based on a starting position and an arrival institution (API 2020)'),
+        parameters={
+            'lat': {'description': _('Latitude (departure)'), 'example_value': '46.828652'},
+            'lon': {'description': _('Longitude (departure)'), 'example_value': '1.701463'},
+            'address': {'description': _('Address (departure)')},
+            'institution': {'description': _('Institution ID (arrival)'), 'example_value': '276'},
+            'mode': {'description': _('Search mode: CLOSE_SCHOLAR (default) = 3km, FAR_ALL = 15km')},
+        })
     def search(self, request, lat, lon, institution, address='', mode='CLOSE_SCHOLAR'):
         payload = {
                 'from-lat': lat,
@@ -147,8 +177,16 @@ class Okina(BaseResource):
             stop['text'] = stop['commercial_name']
         return {'data': stops}
 
-    @endpoint(name='stop-areas',
-              pattern='^from-city/(?P<city_insee_code>\d+)/to-institution/(?P<institution_id>\d+)/*$')
+    @endpoint(
+        display_category=_('Journeys'),
+        display_order=4,
+        description=_('Stop areas from a city to an institution'),
+        name='stop-areas',
+        pattern=r'^from-city/(?P<city_insee_code>\d+)/to-institution/(?P<institution_id>\d+)/*$',
+        parameters={
+            'city_insee_code': {'description': _('INSEE City code'), 'example_value': '36005'},
+            'institution_id': {'description': _('Institution ID (arrival)'), 'example_value': '276'},
+        })
     def stop_areas(self, request, city_insee_code, institution_id):
         stops = self.request('stop-areas/subscriberCity/%s/institution/%s' % (city_insee_code,
                                                                               institution_id))
@@ -179,17 +217,36 @@ class Okina(BaseResource):
                 })
         return {'data': ods}
 
-    @endpoint(name='origin-destinations')
+    @endpoint(
+        display_category=_('Journeys'),
+        display_order=5,
+        description=_('Origin/Destinations'),
+        name='origin-destinations')
     def origin_destinations(self, request):
         return self.get_ods()
 
-    @endpoint(name='origin-destinations',
-              pattern='^to-institution/(?P<institution_id>\d+)/*$')
+    @endpoint(
+        display_category=_('Journeys'),
+        display_order=6,
+        description=_('Origin/Destinations to an institution'),
+        name='origin-destinations',
+        pattern=r'^to-institution/(?P<institution_id>\d+)/*$',
+        parameters={
+            'institution_id': {'description': _('Institution ID (arrival)'), 'example_value': '276'},
+        })
     def origin_destinations_to_institution(self, request, institution_id):
         return self.get_ods('/institution/%s' % institution_id)
 
-    @endpoint(name='origin-destinations',
-              pattern='^from-stop-area/(?P<stop_area_id>\d+)/to-institution/(?P<institution_id>\d+)/*$')
+    @endpoint(
+        display_category=_('Journeys'),
+        display_order=7,
+        description=_('Origin/Destinations from a stop area to an institution'),
+        name='origin-destinations',
+        pattern=r'^from-stop-area/(?P<stop_area_id>\d+)/to-institution/(?P<institution_id>\d+)/*$',
+        parameters={
+            'stop_area_id': {'description': _('Stop area ID'), 'example_value': '3282'},
+            'institution_id': {'description': _('Institution ID (arrival)'), 'example_value': '276'},
+        })
     def origin_destinations_from_stop_to_institution(self, request, stop_area_id, institution_id):
         endpoint = 'ods/institution/%s/stop-area/%s' % (institution_id, stop_area_id)
         okina_journeys = self.request(endpoint)
@@ -206,24 +263,71 @@ class Okina(BaseResource):
             journeys.append(journey)
         return {'data': journeys}
 
-    @endpoint(name='origin-destinations',
-              pattern='^from-city/(?P<city_insee_code>\d+)/to-institution/(?P<institution_id>\d+)/*$')
+    @endpoint(
+        display_category=_('Journeys'),
+        display_order=8,
+        description=_('Origin/Destinations from a city to an institution'),
+        name='origin-destinations',
+        pattern=r'^from-city/(?P<city_insee_code>\d+)/to-institution/(?P<institution_id>\d+)/*$',
+        parameters={
+            'city_insee_code': {'description': _('INSEE City code'), 'example_value': '36005'},
+            'institution_id': {'description': _('Institution ID (arrival)'), 'example_value': '276'},
+        })
     def origin_destinations_from_city_to_institution(self, request, city_insee_code, institution_id):
         return self.get_ods('/institution/%s/subscriberCity/%s' % (institution_id, city_insee_code))
 
-    @endpoint(name='origin-destinations',
-              pattern='^from-city/(?P<city_insee_code>\d+)/*$')
+    @endpoint(
+        display_category=_('Journeys'),
+        display_order=9,
+        description=_('Origin/Destinations from a city'),
+        name='origin-destinations',
+        pattern=r'^from-city/(?P<city_insee_code>\d+)/*$',
+        parameters={
+            'city_insee_code': {'description': _('INSEE City code'), 'example_value': '36005'},
+        })
     def origin_destinations_from_city(self, request, city_insee_code):
         return self.get_ods('/subscriberCity/%s' % city_insee_code)
 
-    @endpoint(name='topology', pattern='^(?P<kind>(lines|networks|vehicle-journeys))/*$')
+    @endpoint(
+        display_category=_('Topology'),
+        show=False,
+        name='topology', pattern='^(?P<kind>(lines|networks|vehicle-journeys))/*$')
     def topology(self, request, kind):
         return {'data': [{
             'id': '%s' % item['id'],
             'text': item['name']
         } for item in self.request('topology/%s' % kind)]}
 
-    @endpoint(name='subscriber', methods=['post'], perm='can_access')
+    @endpoint(
+        display_category=_('Topology'),
+        display_order=1,
+        description=_('Lines'),
+        name='topology', pattern='^lines/*$', example_pattern='lines/')
+    def topology_lines(self, request):
+        return self.topology(request, kind='lines')
+
+    @endpoint(
+        display_category=_('Topology'),
+        display_order=2,
+        description=_('Networks'),
+        name='topology', pattern='^networks/*$', example_pattern='networks/')
+    def topology_networks(self, request):
+        return self.topology(request, kind='networks')
+
+    @endpoint(
+        display_category=_('Topology'),
+        display_order=3,
+        description=_('Vehicle journeys'),
+        name='topology', pattern='^vehicle-journeys/*$', example_pattern='vehicle-journeys/')
+    def topology_vehicle_journeys(self, request):
+        return self.topology(request, kind='vehicle-journeys')
+
+    @endpoint(
+        display_category=_('Subscriptions'),
+        display_order=1,
+        description=_('Create a subscriber'),
+        long_description=_('Same payload as for the Okina POST /b2b/subscribers endpoint'),
+        name='subscriber', methods=['post'], perm='can_access')
     def create_subscriber(self, request):
         try:
             payload = json_loads(request.body)
@@ -233,13 +337,27 @@ class Okina(BaseResource):
             raise APIError('payload must be a dict', http_status=400)
         return {'data': self.request('subscribers', payload, result_is_list=False)}
 
-    @endpoint(name='subscriber', pattern='^(?P<subscriber_id>\d+)/*$',
-              methods=['get'], perm='can_access')
+    @endpoint(
+        display_category=_('Subscriptions'),
+        display_order=2,
+        description=_('Informations about a subscriber'),
+        name='subscriber', pattern=r'^(?P<subscriber_id>\d+)/*$',
+        methods=['get'], perm='can_access',
+        parameters={
+            'subscriber_id': {'description': _('Subscriber ID'), 'example_value': '284'},
+        })
     def get_subscriber(self, request, subscriber_id):
         return {'data': self.request('subscribers/%s' % subscriber_id, result_is_list=False)}
 
-    @endpoint(name='subscriber', pattern='^(?P<subscriber_id>\d+)/qrcode/*$',
-              perm='can_access')
+    @endpoint(
+        display_category=_('Subscriptions'),
+        display_order=3,
+        description=_("Get subscriber's QR Code"),
+        name='subscriber', pattern=r'^(?P<subscriber_id>\d+)/qrcode/*$',
+        perm='can_access',
+        parameters={
+            'subscriber_id': {'description': _('Subscriber ID'), 'example_value': '284'},
+        })
     def get_subscriber_qrcode(self, request, subscriber_id):
         qrcode = self.request('subscribers/%s/qrcode' % subscriber_id, result_is_json=False)
         content_type = qrcode.headers.get('Content-Type')
@@ -250,7 +368,12 @@ class Okina(BaseResource):
                            err=response['code'])
         return HttpResponse(qrcode.content, content_type=content_type)
 
-    @endpoint(name='subscription', methods=['post'], perm='can_access')
+    @endpoint(
+        display_category=_('Subscriptions'),
+        display_order=4,
+        description=_("Create a subscription"),
+        long_description=_('Same payload as for the Okina POST /b2b/subscriptions endpoint'),
+        name='subscription', methods=['post'], perm='can_access')
     def create_subscription(self, request):
         try:
             payload = json_loads(request.body)
@@ -260,7 +383,14 @@ class Okina(BaseResource):
             raise APIError('payload must be a dict', http_status=400)
         return {'data': self.request('subscriptions', payload, result_is_list=False)}
 
-    @endpoint(name='subscription', pattern='^(?P<subscription_id>\d+)/*$',
-              methods=['get'], perm='can_access')
+    @endpoint(
+        display_category=_('Subscriptions'),
+        display_order=5,
+        description=_("Informations about a subscription"),
+        name='subscription', pattern=r'^(?P<subscription_id>\d+)/*$',
+        methods=['get'], perm='can_access',
+        parameters={
+            'subscription_id': {'description': _('Subscription ID'), 'example_value': '284'},
+        })
     def get_subscription(self, request, subscription_id):
         return {'data': self.request('subscriptions/%s' % subscription_id, result_is_list=False)}
diff --git a/passerelle/apps/okina/templates/okina/okina_detail.html b/passerelle/apps/okina/templates/okina/okina_detail.html
index 68a229eb..4f130f37 100644
--- a/passerelle/apps/okina/templates/okina/okina_detail.html
+++ b/passerelle/apps/okina/templates/okina/okina_detail.html
@@ -12,86 +12,6 @@ This API provides an access to <a href="https://www.okina.fr/">Okina</a> API.
 </p>
 {% endblock %}
 
-{% block endpoints %}
-<h4>{% trans 'General' %}</h4>
-<ul class="endpoints">
-<li class="get-method"><span class="description">{% trans 'Cities:' %}</span> <a class="example-url" href="cities/"
-  >{{ site_base_uri }}{{ object.get_absolute_url }}cities</a></li>
-<li class="get-method"><span class="description">{% trans 'Classes:' %}</span><a class="example-url" href="classes/"
-  >{{ site_base_uri }}{{ object.get_absolute_url }}classes</a></li>
-<li class="get-method"><span class="description">{% trans 'Institutions:' %}</span>
-  <a class="example-url" href="institutions/"
-  >{{ site_base_uri }}{{ object.get_absolute_url }}institutions</a></li>
-</ul>
-
-<h4><span class="description">{% trans 'Journeys' %}</h4>
-<ul class="endpoints">
-<li class="get-method"><span class="description">{% trans 'Get stop points based on a starting position and an arrival institution (API 2020)' %}</span>
-  <a class="example-url" href="search?lat=46.828652&lon=1.701463&institution=277"
-  >{{ site_base_uri }}{{ object.get_absolute_url }}search?lat=...&lon=...&institution=<i>institution_id</i></a></li>
-
-<li class="get-method"><span class="description">{% trans 'Institutions in a city (API 2020)' %}</span>
-  <a class="example-url" href="institutions?insee=36005"
-  >{{ site_base_uri }}{{ object.get_absolute_url }}institutions?insee=<i>city-insee-code</i></a></li>
-
-<li class="get-method"><span class="description">{% trans 'Institutions accessible from a city:' %}</span>
-  <a class="example-url" href="institutions/from-city/36005/"
-  >{{ site_base_uri }}{{ object.get_absolute_url }}institutions/from-city/<i>city-insee-code</i>/</a></li>
-
-<li class="get-method"><span class="description">{% trans 'Stop areas from a city to an institution:' %}</span>
-  <a class="example-url" href="stop-areas/from-city/36005/to-institution/276/"
-  >{{ site_base_uri }}{{ object.get_absolute_url }}stop-areas/from-city/<i>city-insee-code</i>/to-institution/<i>institution_id</i>/</a></li>
-
-<li class="get-method"><span class="description">{% trans 'Origin/Destinations:' %}</span><a class="example-url" href="origin-destinations/"
-  >{{ site_base_uri }}{{ object.get_absolute_url }}origin-destinations</a></li>
-<li class="get-method"><span class="description">{% trans 'Origin/Destinations to an institution:' %}</span>
-  <a class="example-url" href="origin-destinations/to-institution/276/"
-  >{{ site_base_uri }}{{ object.get_absolute_url }}origin-destinations/to-institution/<i>institution_id</i>/</a></li>
-<li class="get-method"><span class="description">{% trans 'Origin/Destinations from a stop area to an institution:' %}</span>
-  <a class="example-url" href="origin-destinations/from-stop-area/3282/to-institution/276/"
-  >{{ site_base_uri }}{{ object.get_absolute_url }}origin-destinations/from-stop-area/<i>stop_area_id</i>/to-institution/<i>institution_id</i>/</a></li>
-<li class="get-method"><span class="description">{% trans 'Origin/Destinations from a city to an institution:' %}</span>
-  <a class="example-url" href="origin-destinations/from-city/36005/to-institution/276/"
-  >{{ site_base_uri }}{{ object.get_absolute_url }}origin-destinations/from-city/<i>city_insee_code</i>/to-institution/<i>institution_id</i></a></li>
-<li class="get-method"><span class="description">{% trans 'Origin/Destinations from a city:' %}</span>
-  <a class="example-url" href="origin-destinations/from-city/36005/"
-  >{{ site_base_uri }}{{ object.get_absolute_url }}origin-destinations/from-city/<i>city_insee_code</i>/</a></li>
-</ul>
-
-<h4><span class="description">{% trans 'Subscriptions' %}</h4>
-<ul class="endpoints">
-<li class="post-method"><span class="description">{% trans 'Create a subscriber:' %}</span>
-  <a class="example-url" href="subscriber/"
-          >{{ site_base_uri }}{{ object.get_absolute_url }}subscriber/</a>
-  <div class="body-schemas">{% trans 'Same payload as for the Okina POST /b2b/subscribers endpoint' %}</div></li>
-<li class="get-method"><span class="description">{% trans 'Informations about a subscriber:' %}</span>
-  <a class="example-url" href="subscriber/284/"
-     >{{ site_base_uri }}{{ object.get_absolute_url }}subscriber/<i>id</i>/</a></li>
-<li class="get-method"><span class="description">{% trans "Get subscriber's QR Code:" %}</span>
-  <a class="example-url" href="subscriber/284/qrcode/"
-     >{{ site_base_uri }}{{ object.get_absolute_url }}subscriber/<i>id</i>/qrcode/</a></li>
-<li class="post-method"><span class="description">{% trans 'Create a subscription:' %}</span>
-  <a class="example-url" href="subscription/"
-          >{{ site_base_uri }}{{ object.get_absolute_url }}subscription/</a>
-  <div class="body-schemas">{% trans 'Same payload as for the Okina POST /b2b/subscriptions endpoint' %}</div></li>
-<li class="get-method"><span class="description">{% trans 'Informations about a subscription:' %}</span>
-  <a class="example-url" href="subscription/283/"
-     >{{ site_base_uri }}{{ object.get_absolute_url }}subscription/<i>id</i>/</a></li>
-</ul>
-
-
-<h4><span class="description">{% trans 'Topology' %}</h4>
-<ul class="endpoints">
-<li class="get-method"><span class="description">{% trans 'Lines:' %}</span><a class="example-url" href="topology/lines/"
-  >{{ site_base_uri }}{{ object.get_absolute_url }}topology/lines/</a></li>
-<li class="get-method"><span class="description">{% trans 'Networks:' %}</span><a class="example-url" href="topology/networks/"
-  >{{ site_base_uri }}{{ object.get_absolute_url }}topology/networks/</a></li>
-<li class="get-method"><span class="description">{% trans 'Vehicle journeys:' %}</span><a class="example-url" href="topology/vehicle-journeys/"
-  >{{ site_base_uri }}{{ object.get_absolute_url }}topology/vehicle-journeys/</a></li>
-</ul>
-
-{% endblock %}
-
 {% block security %}
 <p>
   {% trans 'Access to subscription endpoints is limited to the following API users:' %}
-- 
2.20.1

