From 654f088bab35aff16cd999a5744b8f045e2cc49b Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Sun, 10 Mar 2019 14:40:14 +0200 Subject: Add: Delete members --- effiapi | 42 ++++++++++++++++++++++++++++++++++++++---- yarns/000.yarn | 37 +++++++++++++++++++++++++++++-------- yarns/lib.py | 3 +++ 3 files changed, 70 insertions(+), 12 deletions(-) diff --git a/effiapi b/effiapi index f3894fc..5f92901 100755 --- a/effiapi +++ b/effiapi @@ -81,7 +81,7 @@ class FakeHTTPAPI(HTTPAPI): def POST(self, url, headers, body): logging.debug( - 'FakeHTTPAPI.POST url=%r headers=%r body=r', + 'FakeHTTPAPI.POST url=%r headers=%r body=%r', url, headers, body) rid = str(uuid.uuid4()) @@ -93,7 +93,7 @@ class FakeHTTPAPI(HTTPAPI): def PUT(self, url, headers, body): logging.debug( - 'FakeHTTPAPI.PUT url=%r headers=%r body=r', + 'FakeHTTPAPI.PUT url=%r headers=%r body=%r', url, headers, body) rid = headers.get('Muck-Id') @@ -117,7 +117,7 @@ class FakeHTTPAPI(HTTPAPI): if url.endswith('/res'): return self._get_resource(headers) - logging.error('Cannot server url') + logging.error('Cannot serve url') assert 0 def _get_status(self): @@ -136,6 +136,10 @@ class FakeHTTPAPI(HTTPAPI): logging.warning('FakeHTTPAPI.GET: empty resource id in headers') return FakeResponse(404, {}, 'No such member') + if rid not in self._memb: + logging.debug('Members: %r', self._memb) + return FakeResponse(404, {}, 'Retrieving member that does not exist') + memb = self._memb[rid] headers = { 'Muck-Id': rid, @@ -144,7 +148,19 @@ class FakeHTTPAPI(HTTPAPI): return FakeResponse(200, headers, memb) def DELETE(self, url, headers): - raise NotImplementedError() + logging.debug('FakeHTTPAPI.DELETE url=%r headers=%r', url, headers) + + rid = headers.get('Muck-Id') + if not rid: + logging.warning('FakeHTTPAPI.DELETE: empty resource id in headers') + return FakeResponse(404, {}, 'No such member') + + if rid not in self._memb: + logging.debug('Members: %r', self._memb) + return FakeResponse(404, {}, 'Deleting member that does not exist') + + del self._memb[rid] + return FakeResponse(200, {}, {}) class MuckError(Exception): @@ -214,6 +230,14 @@ class MuckAPI: def update(self, member): return self._write(member, self._httpapi.PUT) + def delete(self): + url = self.url('/res') + headers = self._get_headers() + r = self._httpapi.DELETE(url, headers) + logging.info('Delete result: %s %s', r.status_code, r.text) + if not r.ok: + raise MuckError('{} {}'.format(r.status_code, r.text)) + def search(self, cond): url = self.url('/search') headers = self._get_headers() @@ -258,6 +282,11 @@ class API: 'path': '/memb', 'callback': self._call(self._update), }, + { + 'method': 'DELETE', + 'path': '/memb', + 'callback': self._call(self._delete), + }, ] for route in routes: @@ -335,6 +364,11 @@ class API: rid, newobj = self._muck.update(obj) return response(200, rid, newobj) + def _delete(self): + r = bottle.request + self._muck.delete() + return response(200, None, None) + def response(status, rid, body): headers = { diff --git a/yarns/000.yarn b/yarns/000.yarn index adff964..79e398d 100644 --- a/yarns/000.yarn +++ b/yarns/000.yarn @@ -33,17 +33,20 @@ Examples will be provided. ## Manage memberships -This section shows the API calls to manage a memberhip: to create the -member, to update and retrieve it, and to search memberships. +This section shows the API calls to manage a memberhip. SCENARIO Manage memberships GIVEN An effiapi instance +First make sure the register is empty. + WHEN admin requests GET /status THEN HTTP status is 200 AND body matches { "resources": 0 } +Create a member. + WHEN admin requests POST /memb with body { "fullname": "James Bond" } THEN HTTP status is 201 AND remember header Muck-Id as ID @@ -58,6 +61,8 @@ member, to update and retrieve it, and to search memberships. AND body matches { "fullname": "James Bond" } AND header Muck-Revision is ${REV1} +Update the member. + WHEN admin requests PUT /memb with id ${ID}, revision ${REV1}, ... and body { "fullname": "Alfred Pennyworth" } THEN HTTP status is 200 @@ -68,12 +73,24 @@ member, to update and retrieve it, and to search memberships. AND body matches { "fullname": "Alfred Pennyworth" } AND header Muck-Revision is ${REV2} +Delete the member. + + WHEN admin requests DELETE /memb with id ${ID} + THEN HTTP status is 200 + + WHEN admin requests GET /status + THEN HTTP status is 200 + AND body matches { "resources": 0 } + + WHEN admin requests GET /memb with header Muck-Id: ${ID} + THEN HTTP status is 404 + +Done. + FINALLY Effiapi is terminated TODO: -* update -* delete * search * members can see their own data, and can't see each others' * member follows authn link emailed to them @@ -119,12 +136,16 @@ TODO: headers = { header: value, } - V['xx'] = { - 'header': header, - 'value': value, - } effiapi.GET('/memb', headers, None) + IMPLEMENTS WHEN admin requests DELETE /memb with id (\S+) + rid = get_expanded_match() + print('rid', repr(rid)) + headers = { + 'Muck-id': rid, + } + effiapi.DELETE('/memb', headers, None) + ## Inspect HTTP responses IMPLEMENTS THEN HTTP status is (\d+) diff --git a/yarns/lib.py b/yarns/lib.py index 100511e..2e76b88 100644 --- a/yarns/lib.py +++ b/yarns/lib.py @@ -104,6 +104,9 @@ class EffiAPI: def GET(self, path, headers, body): self.request(requests.get, path, headers, body) + def DELETE(self, path, headers, body): + self.request(requests.delete, path, headers, body) + def request(self, func, path, headers, body): url = '{}{}'.format(self.v['baseurl'], path) self.v['request'] = { -- cgit v1.2.1