general: be explicit about open endpoints (#78041)

This commit is contained in:
Frédéric Péters 2023-05-31 10:53:43 +02:00
parent 29b8775a16
commit e4a9d16719
24 changed files with 86 additions and 41 deletions

View File

@ -102,6 +102,7 @@ class AddressResource(BaseResource):
@endpoint(
name='sectors',
description=_('List related Sectorizations'),
perm='OPEN',
parameters={
'id': {'description': _('Sector Identifier (slug)')},
'q': {'description': _('Filter by Sector Title or Identifier')},

View File

@ -44,6 +44,7 @@ class AirQuality(BaseResource):
@endpoint(
pattern=r'^(?P<country>\w+)/(?P<city>\w+)/$',
example_pattern='{country}/{city}/',
perm='OPEN',
parameters={
'country': {'description': _('Country Code'), 'example_value': 'fr'},
'city': {'description': _('City Name'), 'example_value': 'lyon'},

View File

@ -321,6 +321,7 @@ class ArcGIS(BaseResource, HTTPResource):
@endpoint(
name='tile',
description=_('Tiles layer'),
perm='OPEN',
pattern=r'^(?P<layer>[\w/]+)/(?P<zoom>\d+)/(?P<tile_x>\d+)/(?P<tile_y>\d+)\.png$',
)
def tile(self, request, layer, zoom, tile_x, tile_y):

View File

@ -109,6 +109,7 @@ class BaseAdresse(AddressResource):
@endpoint(
pattern='(?P<q>.+)?$',
description=_('Addresses list'),
perm='OPEN',
parameters={
'id': {'description': _('Address identifier')},
'q': {'description': _('Address'), 'example_value': '169 rue du chateau, paris'},
@ -238,6 +239,7 @@ class BaseAdresse(AddressResource):
@endpoint(
pattern='(?P<q>.+)?$',
description=_('Geocoding (Nominatim API)'),
perm='OPEN',
parameters={
'q': {'description': _('Address'), 'example_value': '169 rue du chateau, paris'},
'zipcode': {'description': _('Zipcode')},
@ -276,6 +278,7 @@ class BaseAdresse(AddressResource):
@endpoint(
description=_('Reverse geocoding'),
perm='OPEN',
parameters={
'lat': {'description': _('Latitude'), 'example_value': 48.833708},
'lon': {'description': _('Longitude'), 'example_value': 2.323349},
@ -319,6 +322,7 @@ class BaseAdresse(AddressResource):
@endpoint(
description=_('Streets from zipcode'),
perm='OPEN',
parameters={
'id': {'description': _('Street identifier')},
'q': {'description': _("Street name")},
@ -372,6 +376,7 @@ class BaseAdresse(AddressResource):
@endpoint(
description=_('Cities list'),
perm='OPEN',
parameters={
'id': {
'description': _('Get exactly one city using its code and postal code separated with a dot'),
@ -433,6 +438,7 @@ class BaseAdresse(AddressResource):
@endpoint(
description=_('Departments list'),
perm='OPEN',
parameters={
'id': {'description': _('Get exactly one department using its code'), 'example_value': '59'},
'q': {'description': _('Search text in name or code'), 'example_value': 'Nord'},
@ -457,6 +463,7 @@ class BaseAdresse(AddressResource):
@endpoint(
description=_('Regions list'),
perm='OPEN',
parameters={
'id': {'description': _('Get exactly one region using its code'), 'example_value': '32'},
'q': {'description': _('Search text in name or code'), 'example_value': 'Hauts-de-France'},

View File

@ -174,6 +174,7 @@ class Resource(BaseResource, HTTPResource):
@endpoint(
methods=['get'],
name='meeting',
perm='OPEN',
pattern=r'^(?P<guid>[0-9a-f]{32})/is-running/?$',
example_pattern='{guid}/is-running/',
description_post=_('Report if meeting is running'),
@ -196,6 +197,7 @@ class Resource(BaseResource, HTTPResource):
@endpoint(
methods=['get'],
name='meeting',
perm='OPEN',
pattern=r'^(?P<guid>[0-9a-f]{32})/join/agent/(?P<key>[^/]*)/?$',
example_pattern='{guid}/join/agent/',
description_post=_('Get a meeting'),
@ -223,6 +225,7 @@ class Resource(BaseResource, HTTPResource):
@endpoint(
methods=['get'],
name='meeting',
perm='OPEN',
pattern=r'^(?P<guid>[0-9a-f]{32})/join/user/(?P<key>[^/]*)/?$',
example_pattern='{guid}/join/user/',
description_post=_('Get a meeting'),

View File

@ -359,7 +359,7 @@ class AbstractCartaDSCS(BaseResource):
super().daily()
self.update_data_cache()
@endpoint(description=_('Get list of collectivities'))
@endpoint(description=_('Get list of collectivities'), perm='OPEN')
def communes(self, request):
cache = CartaDSDataCache.objects.get(data_type='communes')
return cache.data_values
@ -384,6 +384,7 @@ class AbstractCartaDSCS(BaseResource):
@endpoint(
description=_('Get list of file types'),
perm='OPEN',
parameters={
'commune_id': COMMUNE_ID_PARAM,
'filter': {
@ -404,6 +405,7 @@ class AbstractCartaDSCS(BaseResource):
@endpoint(
description=_('Get list of demand subjects'),
perm='OPEN',
parameters={'type_dossier_id': TYPE_DOSSIER_ID_PARAM},
)
def objets_demande(self, request, type_dossier_id):
@ -414,6 +416,7 @@ class AbstractCartaDSCS(BaseResource):
@endpoint(
description=_('Get list of CERFA documents'),
perm='OPEN',
parameters={
'type_dossier_id': TYPE_DOSSIER_ID_PARAM,
'type_compte': {'description': _('Type of account')},
@ -682,6 +685,7 @@ class AbstractCartaDSCS(BaseResource):
@endpoint(
methods=['post'],
pattern=r'^(?P<id_piece>[\w-]+)/(?P<token>[\w:_-]+)/$',
perm='OPEN',
description=_('Upload a single document file'),
parameters={
'id_piece': PIECE_ID_PARAM,
@ -720,6 +724,7 @@ class AbstractCartaDSCS(BaseResource):
@endpoint(
methods=['post'],
name='upload',
perm='OPEN',
pattern=r'^(?P<id_piece>[\w-]+)/(?P<token>[\w:_-]+)/(?P<file_upload>[\w:_-]+)/delete/$',
description=_('Delete a single document file'),
parameters={
@ -872,6 +877,7 @@ class AbstractCartaDSCS(BaseResource):
@endpoint(
pattern=r'^(?P<signed_dossier_id>[\w:_-]+)/$',
perm='OPEN',
methods=['post'],
description=_('Notification of file processing by Cart@DS CS'),
parameters={

View File

@ -65,7 +65,7 @@ class ClicRdv(BaseResource):
}
return response.json()
@endpoint(name='interventionsets')
@endpoint(name='interventionsets', perm='OPEN')
def get_interventionsets(self, request, **kwargs):
response = self.request('interventionsets')
if 'error' in response:
@ -78,7 +78,7 @@ class ClicRdv(BaseResource):
ret.append({'id': record['id'], 'text': record['publicname'], 'details': record})
return {'data': ret}
@endpoint(name='interventionsets', pattern=r'(?P<set>\d+)/')
@endpoint(name='interventionsets', pattern=r'(?P<set>\d+)/', perm='OPEN')
def get_interventions(self, request, set, **kwargs):
ret = []
response = self.request('interventions?interventionset_id=%s' % set)

View File

@ -369,7 +369,7 @@ class GenericFamily(BaseResource):
invoices.append(format_invoice(i))
return invoices
@endpoint(name='regie', pattern='^invoices/$')
@endpoint(name='regie', perm='OPEN', pattern='^invoices/$')
def active_invoices(self, request, NameID):
return {'data': self.get_invoices(NameID)}

View File

@ -108,6 +108,7 @@ class Resource(BaseResource):
@endpoint(
description=_('Init request'),
perm='OPEN',
parameters={
'mode': {
'description': _('What to retrieve, default to FranceConnect identity, can be "dgfip"'),
@ -139,6 +140,7 @@ class Resource(BaseResource):
@endpoint(
description=_('FranceConnect callback (internal use)'),
perm='OPEN',
parameters={
'origin': {
'description': _('HTTP Origin, needed to secure window.postMessage'),
@ -217,6 +219,7 @@ class Resource(BaseResource):
@endpoint(
description=_('Demo page (to check your configuration)'),
perm='OPEN',
)
def demo(self, request, **kwargs):
if not request.user.is_superuser:
@ -229,6 +232,7 @@ class Resource(BaseResource):
@endpoint(
description=_('Data source'),
perm='OPEN',
)
def data_source(self, request, id=None, test=None, mode=None, **kwargs):
if id:

View File

@ -110,7 +110,7 @@ class Gdc(BaseResource):
return ET.ElementTree(ET.fromstring(resp.content))
@endpoint()
@endpoint(perm='OPEN')
def communes(self, request, *args, **kwargs):
resp = self.call_soap('getListeCommune')
soap_result = phpserialize_loads(resp.findall('.//listeCommune')[0].text)
@ -120,7 +120,7 @@ class Gdc(BaseResource):
result.sort(key=lambda x: x['id'])
return result
@endpoint()
@endpoint(perm='OPEN')
def objets(self, request, *args, **kwargs):
resp = self.call_soap('getListeObjet')
soap_result = phpserialize_loads(resp.findall('.//listeObjet')[0].text)

View File

@ -78,7 +78,7 @@ class Holidays(BaseResource):
def get_holidays_display(self):
return ', '.join(HOLIDAYS_LABELS[holiday] for holiday in self.holidays)
@endpoint(name='holidays.ics', description=_('Get holidays ICS.'))
@endpoint(name='holidays.ics', description=_('Get holidays ICS.'), perm='OPEN')
def holidays_ics(self, request):
try:
response = self.requests.get(ZONE_URLS[self.zone])

View File

@ -74,7 +74,7 @@ class Okina(BaseResource):
raise APIError('HTTP request failed, error %s' % response.status_code, data=data)
return data
@endpoint()
@endpoint(perm='OPEN')
def cities(self, request):
okina_cities = self.request('cities')
cities = []
@ -91,7 +91,7 @@ class Okina(BaseResource):
cities.sort(key=lambda x: x['text'])
return {'data': cities}
@endpoint()
@endpoint(perm='OPEN')
def classes(self, request):
return {
'data': [{'id': '%s' % item['id'], 'text': item['label']} for item in self.request('classes')]
@ -112,9 +112,10 @@ class Okina(BaseResource):
return institutions
@endpoint(
perm='OPEN',
parameters={
'insee': {'description': _('INSEE City code'), 'example_value': '36005'},
}
},
)
def institutions(self, request, insee=None):
if insee:
@ -123,7 +124,7 @@ class Okina(BaseResource):
query = ''
return {'data': self.get_institutions(query)}
@endpoint(name='institutions', pattern=r'^from-city/(?P<city_insee_code>\d+)/*$')
@endpoint(name='institutions', pattern=r'^from-city/(?P<city_insee_code>\d+)/*$', perm='OPEN')
def institutions_from_city(self, request, city_insee_code):
return {'data': self.get_institutions('/subscriberCity/%s' % city_insee_code)}
@ -158,6 +159,7 @@ class Okina(BaseResource):
@endpoint(
name='stop-areas',
pattern=r'^from-city/(?P<city_insee_code>\d+)/to-institution/(?P<institution_id>\d+)/*$',
perm='OPEN',
)
def stop_areas(self, request, city_insee_code, institution_id):
stops = self.request(
@ -191,17 +193,18 @@ class Okina(BaseResource):
)
return {'data': ods}
@endpoint(name='origin-destinations')
@endpoint(name='origin-destinations', perm='OPEN')
def origin_destinations(self, request):
return self.get_ods()
@endpoint(name='origin-destinations', pattern=r'^to-institution/(?P<institution_id>\d+)/*$')
@endpoint(name='origin-destinations', pattern=r'^to-institution/(?P<institution_id>\d+)/*$', perm='OPEN')
def origin_destinations_to_institution(self, request, institution_id):
return self.get_ods('/institution/%s' % institution_id)
@endpoint(
name='origin-destinations',
pattern=r'^from-stop-area/(?P<stop_area_id>\d+)/to-institution/(?P<institution_id>\d+)/*$',
perm='OPEN',
)
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)
@ -225,15 +228,16 @@ class Okina(BaseResource):
@endpoint(
name='origin-destinations',
pattern=r'^from-city/(?P<city_insee_code>\d+)/to-institution/(?P<institution_id>\d+)/*$',
perm='OPEN',
)
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=r'^from-city/(?P<city_insee_code>\d+)/*$')
@endpoint(name='origin-destinations', pattern=r'^from-city/(?P<city_insee_code>\d+)/*$', perm='OPEN')
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(name='topology', pattern='^(?P<kind>(lines|networks|vehicle-journeys))/*$', perm='OPEN')
def topology(self, request, kind):
return {
'data': [

View File

@ -310,6 +310,7 @@ class OpenGIS(BaseResource):
@endpoint(
name='tile',
pattern=r'^(?P<zoom>\d+)/(?P<tile_x>\d+)/(?P<tile_y>\d+).png',
perm='OPEN',
description=_('Get Map Tile'),
example_pattern='{zoom}/{tile_x}/{tile_y}.png',
parameters={

View File

@ -103,6 +103,7 @@ class Photon(BaseResource):
@endpoint(
pattern='(?P<q>.+)?$',
description=_('Addresses list'),
perm='OPEN',
parameters={
'id': {'description': _('Address identifier')},
'q': {'description': _('Address'), 'example_value': '169 rue du chateau, paris'},
@ -173,6 +174,7 @@ class Photon(BaseResource):
@endpoint(
description=_('Geocoding (Nominatim API)'),
pattern='(?P<q>.+)?$',
perm='OPEN',
parameters={
'q': {'description': _('Address'), 'example_value': '169 rue du chateau, paris'},
'zipcode': {'description': _('Zipcode')},
@ -192,6 +194,7 @@ class Photon(BaseResource):
@endpoint(
description=_('Reverse geocoding (Nominatim API)'),
perm='OPEN',
parameters={
'lat': {'description': _('Latitude'), 'example_value': 48.833708},
'lon': {'description': _('Longitude'), 'example_value': 2.323349},

View File

@ -138,7 +138,7 @@ class Solis(BaseResource):
raise APIError('invalid response: %r' % pong, data=pong)
return {'data': 'pong', 'response': pong.get('response')}
@endpoint(name='ping', show=False, description=_('Check Solis API availability'))
@endpoint(name='ping', show=False, description=_('Check Solis API availability'), perm='OPEN')
def ping(self, request):
# deprecated endpoint
return self.check_status()

View File

@ -335,7 +335,7 @@ class BaseResource(models.Model):
status = self.get_availability_status()
return status and status.down()
@endpoint(description=_('Check service availability'), display_order=-1)
@endpoint(description=_('Check service availability'), perm='OPEN', display_order=-1)
def up(self, request, **kwargs):
if self.down():
raise APIError('service not available')

View File

@ -61,7 +61,7 @@ class LilleUrbanCard(BaseResource):
raise TokenError(response['erreur'])
return response['token']
@endpoint(description=_('List of socioprofessional categories'))
@endpoint(description=_('List of socioprofessional categories'), perm='OPEN')
def csp(self, request, *args, **kwargs):
return {
'data': [

View File

@ -29,7 +29,7 @@ class NancyPoll(BaseResource):
def get_verbose_name(cls):
return cls._meta.verbose_name
@endpoint()
@endpoint(perm='OPEN')
def data(self, request, *args, **kwargs):
street_no = request.GET.get('street_no')
street_name = request.GET.get('street_name')

View File

@ -68,6 +68,7 @@ class StubInvoicesConnector(BaseResource):
@endpoint(
name='invoices',
pattern='^history/$',
perm='OPEN',
description=_('Get list of paid invoices'),
example_pattern='history/',
)
@ -81,6 +82,7 @@ class StubInvoicesConnector(BaseResource):
@endpoint(
name='invoice',
pattern=r'^(?P<invoice_id>\w+)/?$',
perm='OPEN',
description=_('Get invoice details'),
example_pattern='{invoice_id}/',
parameters={
@ -96,6 +98,7 @@ class StubInvoicesConnector(BaseResource):
@endpoint(
name='invoice',
pattern=r'^(?P<invoice_id>\w+)/pdf/?$',
perm='OPEN',
description=_('Get invoice as a PDF file'),
long_description=_('not yet implemented'),
example_pattern='{invoice_id}/pdf/',

View File

@ -552,6 +552,7 @@ class Resource(BaseResource, HTTPResource):
long_description=_('Do not use directly, use the pdf_url field of announces instead.'),
name='announce',
pattern=r'^(?P<announce_id>[0-9]+)/pdf/$',
perm='OPEN',
example_pattern='{announce_id}/pdf/',
parameters={
'announce_id': {'description': _('Announce id'), 'example_value': '12345'},

View File

@ -333,6 +333,7 @@ class ToulouseSmartResource(BaseResource, HTTPResource):
parameters={
'uuid': {'description': _('Notification identifier')},
},
perm='can_access',
post={'request_body': {'schema': {'application/json': schemas.UPDATE_SCHEMA}}},
)
def update_intervention(self, request, uuid, post_data):

View File

@ -31,7 +31,7 @@ class endpoint:
def __init__(
self,
serializer_type='json-api',
perm=None,
perm='can_access',
methods=None,
name=None,
pattern=None,
@ -62,6 +62,8 @@ class endpoint:
post_json_schema=None,
):
self.perm = perm
if self.perm == 'OPEN':
self.perm = None
self.methods = methods or ['get']
self.serializer_type = serializer_type
self.pattern = pattern

View File

@ -209,23 +209,23 @@ class FakeConnectorBase:
def get_connector_slug(self):
return 'fake'
@endpoint()
@endpoint(perm='OPEN')
def foo1(self, request):
pass
@endpoint(name='bar')
@endpoint(name='bar', perm='OPEN')
def foo2(self, request, param1):
pass
@endpoint()
@endpoint(perm='OPEN')
def foo3(self, request, param1, param2):
pass
@endpoint()
@endpoint(perm='OPEN')
def foo4(self, request, param1, param2='a', param3='b'):
pass
@endpoint(pattern='^test/$', example_pattern='test/')
@endpoint(pattern='^test/$', example_pattern='test/', perm='OPEN')
def foo5(self, request, param1='a', param2='b', param3='c'):
pass
@ -233,6 +233,7 @@ class FakeConnectorBase:
pattern=r'^(?P<param1>\w+)/?$',
example_pattern='{param1}/',
parameters={'param1': {'description': 'param 1', 'example_value': 'bar'}},
perm='OPEN',
)
def foo6(self, request, param1, param2='a'):
pass
@ -242,6 +243,7 @@ class FakeConnectorBase:
description_post='foo7 post',
description_put='foo7 put',
methods=['get', 'post', 'put'],
perm='OPEN',
)
def foo7(self, request, param1='a', param2='b', param3='c'):
pass
@ -251,6 +253,7 @@ class FakeConnectorBase:
long_description_post='foo7 post',
long_description_put='foo7 put',
methods=['get', 'post', 'put'],
perm='OPEN',
)
def foo7b(self, request, param1='a', param2='b', param3='c'):
pass
@ -259,7 +262,8 @@ class FakeConnectorBase:
parameters={
'test': {'description': 'test', 'example_value': 'test'},
'reg': {'description': 'test', 'example_value': 'test'},
}
},
perm='OPEN',
)
def foo8(self, request, test, reg):
pass
@ -267,12 +271,13 @@ class FakeConnectorBase:
@endpoint(
post={
'long_description': 'foo9 post',
}
},
perm='OPEN',
)
def foo9(self, request):
pass
@endpoint(cache_duration=10)
@endpoint(cache_duration=10, perm='OPEN')
def cached_endpoint(self, request):
pass
@ -391,12 +396,12 @@ class FakeJSONConnector:
BAR_SCHEMA['pre_process'] = pre_process
@endpoint(post={'request_body': {'schema': {'application/json': FOO_SCHEMA}}})
@endpoint(perm='OPEN', post={'request_body': {'schema': {'application/json': FOO_SCHEMA}}})
# pylint: disable=disallowed-name
def foo(self, request, post_data):
return {'data': post_data}
@endpoint(post={'request_body': {'schema': {'application/json': BAR_SCHEMA}}})
@endpoint(perm='OPEN', post={'request_body': {'schema': {'application/json': BAR_SCHEMA}}})
# pylint: disable=disallowed-name
def bar(self, request, post_data):
return {'data': post_data}
@ -481,31 +486,31 @@ class FakeConnectorDatasource:
def down(self):
return False
@endpoint()
@endpoint(perm='OPEN')
def a(self, request):
return copy.deepcopy(self.payload)
@endpoint(datasource=True)
@endpoint(datasource=True, perm='OPEN')
def b(self, request):
return copy.deepcopy(self.payload)
@endpoint(datasource=True, cache_duration=10)
@endpoint(datasource=True, cache_duration=10, perm='OPEN')
def cached_b(self, request):
return copy.deepcopy(self.payload)
@endpoint(datasource=True)
@endpoint(datasource=True, perm='OPEN')
def bb(self, request, id=None, q=None):
return copy.deepcopy(self.payload)
@endpoint(datasource=True)
@endpoint(datasource=True, perm='OPEN')
def c(self, request):
return {}
@endpoint(datasource=True)
@endpoint(datasource=True, perm='OPEN')
def d(self, request):
return {'data': 'foobar'}
@endpoint(datasource=True)
@endpoint(datasource=True, perm='OPEN')
def e(self, request):
return {'data': ['foobar']}
@ -620,7 +625,7 @@ def test_endpoint_description_in_template(app, db):
def test_endpoint_cache(app, db, monkeypatch):
@endpoint(cache_duration=10, methods=['get', 'post'], pattern=r'^(?P<url_param>\w+)/$')
@endpoint(cache_duration=10, perm='OPEN', methods=['get', 'post'], pattern=r'^(?P<url_param>\w+)/$')
def randominvoice(obj, request, url_param, get_param=None):
return {'data': random.randint(0, pow(10, 12))}
@ -685,7 +690,7 @@ def test_endpoint_cache(app, db, monkeypatch):
def test_endpoint_cookies(app, db, monkeypatch):
@endpoint(methods=['get'])
@endpoint(methods=['get'], perm='OPEN')
def httpcall(obj, request):
with responses.RequestsMock() as rsps:
rsps.get('https://foo.invalid/set-cookie', json={}, headers={"set-cookie": "foo=bar;"})
@ -745,6 +750,7 @@ def test_endpoint_typed_params(app, db, monkeypatch):
'type': 'date',
},
},
perm='OPEN',
)
def httpcall(obj, request, boolean=False, integer=1, floating=1.1, date=None):
return {'boolean': boolean, 'integer': integer, 'floating': floating, 'date': date}
@ -822,6 +828,7 @@ def test_endpoint_params_type_detection(app, db, monkeypatch):
'example_value': '1970-01-01',
},
},
perm='OPEN',
)
def httpcall(
obj,

View File

@ -282,7 +282,7 @@ def test_proxy_logger_context(db, connector):
def test_logged_requests_and_responses_max_size(app, db, monkeypatch, settings):
URL = 'http://whatever.invalid'
@endpoint(methods=['post'])
@endpoint(methods=['post'], perm='OPEN')
def httpcall(self, request):
connector_payload = {'connector_query_var': '2' * 20}
self.requests.post(URL, connector_payload)
@ -368,7 +368,7 @@ def test_proxy_logger_email_traceback(app, db, email_handler, settings, mailoutb
settings.ADMINS = [('admin', 'admin@example.net')]
endpoint_url = tests.utils.generic_endpoint_url('feeds', 'json', slug=connector.slug)
@endpoint()
@endpoint(perm='OPEN')
def json(self, request):
raise requests.ConnectionError('timeout')