diff --git a/passerelle/contrib/toulouse_foederis/models.py b/passerelle/contrib/toulouse_foederis/models.py index 11a87c97..7bd00001 100644 --- a/passerelle/contrib/toulouse_foederis/models.py +++ b/passerelle/contrib/toulouse_foederis/models.py @@ -29,6 +29,51 @@ from passerelle.base.models import BaseResource, HTTPResource from passerelle.utils.api import endpoint from passerelle.utils.json import datasource_array_schema, datasource_schema, response_schema +ATTACHMENT_SCHEMA = { + '$schema': 'http://json-schema.org/draft-04/schema#', + 'title': _('Attachment data.'), + 'description': '', + 'required': ['application_id', 'name', 'file'], + 'type': 'object', + 'properties': { + 'application_id': { + 'description': _('ID of the application to which to attach the file.'), + 'oneOf': [ + { + 'type': 'string', + 'pattern': '^[0-9]+$', + }, + { + 'type': 'integer', + }, + ], + }, + 'name': { + 'description': _('Name of the attachment.'), + 'type': 'string', + }, + 'file': { + 'description': _('File to attach.'), + 'type': 'object', + 'required': ['filename', 'content_type', 'content'], + 'properties': { + 'filename': { + 'description': _("File name"), + 'type': 'string', + }, + 'content_type': { + 'description': _("MIME type"), + 'type': 'string', + }, + 'content': { + 'description': _("Content"), + 'type': 'string', + }, + }, + }, + }, +} + def boolean_field(description): return { @@ -590,6 +635,31 @@ class Resource(BaseResource, HTTPResource): 'data': {'application_id': results[0]['id']}, } + @endpoint( + name='attach-file', + perm='can_access', + post={ + "description": _("Attach a file to an application."), + "request_body": {"schema": {"application/json": ATTACHMENT_SCHEMA}}, + }, + ) + def attach_file(self, request, post_data): + application_id = post_data["application_id"] + attachment_name = post_data["name"] + file = post_data["file"] + + self.http_request( + 'POST', + f'data/candidature/{application_id}/fields/{attachment_name}?viewIntegrationName=api_publik', + json={ + "contentType": file["content_type"], + "value": file["content"], + "fileName": file["filename"], + }, + ) + + return {'err': 0} + @endpoint( description=_('List announces'), long_description=_( diff --git a/tests/test_toulouse_foederis.py b/tests/test_toulouse_foederis.py index f71d1531..dc458b7e 100644 --- a/tests/test_toulouse_foederis.py +++ b/tests/test_toulouse_foederis.py @@ -513,6 +513,40 @@ class TestEndpoints: assert response.json["data"]["application_id"] == 42 + def test_attach_file(self, resource, app): + @httmock.urlmatch(path=r'^.*/data/candidature/424242/fields/cv$') + def handler(url, request): + assert request.headers['content-type'] == 'application/json' + assert request.headers['api-key'] == APIKEY + payload = json.loads(request.body) + assert payload == { + "contentType": "application/pdf", + "value": "base 64 content", + "fileName": "cv.pdf", + } + + return httmock.response(200, json.dumps({"code": 200, "results": ['Field updated']})) + + @httmock.urlmatch() + def error_handler(url, request): + assert False, 'should not be reached' + + with httmock.HTTMock(handler, error_handler): + response = app.post_json( + '/toulouse-foederis/foederis/attach-file', + params={ + "application_id": "424242", + "name": "cv", + "file": { + "content_type": "application/pdf", + "content": "base 64 content", + "filename": "cv.pdf", + }, + }, + ) + + assert response.json["err"] == 0 + def test_migration_0003_no_null_no_charfield(migration): with connection.cursor() as cur: