From 22e062edb9a89f524b553f3f5f1158bfa77d4b9f Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Sun, 15 Apr 2018 00:56:11 -0700 Subject: so much copy/pasta... starting to flush out API --- fatcat/api.py | 132 ++++++++++++++++++++++++++++++++++++++++++++------ fatcat/models.py | 19 +++++++- tests/test_backend.py | 104 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 239 insertions(+), 16 deletions(-) diff --git a/fatcat/api.py b/fatcat/api.py index 70346754..2f691f57 100644 --- a/fatcat/api.py +++ b/fatcat/api.py @@ -23,11 +23,9 @@ def get_or_create_edit_group(): ### Views ################################################################### -@app.route('/v0/work/', methods=['GET']) -def api_work_get(work_id): - if not work_id.isdigit(): - return abort(404) - entity = WorkIdent.query.filter(WorkIdent.id==work_id).first_or_404() +@app.route('/v0/work/', methods=['GET']) +def api_work_get(ident): + entity = WorkIdent.query.filter(WorkIdent.id==ident).first_or_404() return work_schema.jsonify(entity) @app.route('/v0/work', methods=['POST']) @@ -58,14 +56,120 @@ def api_work_random(): entity = WorkIdent.query.order_by(db.func.random()).first() return redirect('/v0/work/{}'.format(entity.id)) -@app.route('/v0/file/', methods=['GET']) -def api_file_get(file_id): - if not file_id.isdigit(): - return abort(404) - entity = FileIdent.query.filter(FileIdent.id==file_id).first_or_404() + +@app.route('/v0/release/', methods=['GET']) +def api_release_get(ident): + entity = ReleaseIdent.query.filter(ReleaseIdent.id==ident).first_or_404() + return release_schema.jsonify(entity) + +@app.route('/v0/release', methods=['POST']) +def api_release_create(): + params = request.get_json() + edit_group = get_or_create_edit_group() + rev = ReleaseRev( + title=params.get('title', None), + release_type=params.get('release_type', None), + creators=params.get('creators', []), + #work=params.get('work', None), + container=params.get('container', None), + doi=params.get('doi', None), + ) + ident = ReleaseIdent(is_live=False, rev=rev) + edit = ReleaseEdit(edit_group=edit_group, ident=ident, rev=rev) + if params.get('extra', None): + ser = json.dumps(params['extra'], indent=False).encode('utf-8') + rev.extra_json = ExtraJson(json=ser, sha1=hashlib.sha1(ser).hexdigest()) + db.session.add_all([edit, ident, rev]) + db.session.commit() + return release_schema.jsonify(ident) + + +@app.route('/v0/creator/', methods=['GET']) +def api_creator_get(ident): + entity = CreatorIdent.query.filter(CreatorIdent.id==ident).first_or_404() + return creator_schema.jsonify(entity) + +@app.route('/v0/creator', methods=['POST']) +def api_creator_create(): + params = request.get_json() + edit_group = get_or_create_edit_group() + rev = CreatorRev( + name=params.get('name', None), + orcid=params.get('orcid', None), + ) + ident = CreatorIdent(is_live=False, rev=rev) + edit = CreatorEdit(edit_group=edit_group, ident=ident, rev=rev) + if params.get('extra', None): + ser = json.dumps(params['extra'], indent=False).encode('utf-8') + rev.extra_json = ExtraJson(json=ser, sha1=hashlib.sha1(ser).hexdigest()) + db.session.add_all([edit, ident, rev]) + db.session.commit() + return creator_schema.jsonify(ident) + + +@app.route('/v0/container/', methods=['GET']) +def api_container_get(ident): + entity = ContainerIdent.query.filter(ContainerIdent.id==ident).first_or_404() + return container_schema.jsonify(entity) + +@app.route('/v0/container', methods=['POST']) +def api_container_create(): + params = request.get_json() + edit_group = get_or_create_edit_group() + rev = ContainerRev( + name=params.get('name', None), + publisher=params.get('publisher', None), + ) + ident = ContainerIdent(is_live=False, rev=rev) + edit = ContainerEdit(edit_group=edit_group, ident=ident, rev=rev) + if params.get('extra', None): + ser = json.dumps(params['extra'], indent=False).encode('utf-8') + rev.extra_json = ExtraJson(json=ser, sha1=hashlib.sha1(ser).hexdigest()) + db.session.add_all([edit, ident, rev]) + db.session.commit() + return container_schema.jsonify(ident) + + +@app.route('/v0/file/', methods=['GET']) +def api_file_get(ident): + entity = FileIdent.query.filter(FileIdent.id==ident).first_or_404() return file_schema.jsonify(entity) -@app.route('/v0/file/random', methods=['GET']) -def api_file_random(): - entity = FileIdent.query.order_by(db.func.random()).first() - return redirect('/v0/file/{}'.format(entity.id)) +@app.route('/v0/file', methods=['POST']) +def api_file_create(): + params = request.get_json() + edit_group = get_or_create_edit_group() + rev = FileRev( + sha1=params.get('sha1', None), + size=params.get('size', None), + url=params.get('url', None), + ) + ident = FileIdent(is_live=False, rev=rev) + edit = FileEdit(edit_group=edit_group, ident=ident, rev=rev) + if params.get('extra', None): + ser = json.dumps(params['extra'], indent=False).encode('utf-8') + rev.extra_json = ExtraJson(json=ser, sha1=hashlib.sha1(ser).hexdigest()) + db.session.add_all([edit, ident, rev]) + db.session.commit() + return file_schema.jsonify(ident) + + +@app.route('/v0/editgroup/', methods=['GET']) +def api_edit_group_get(ident): + entity = EditGroupIdent.query.filter(EditGroupIdent.id==ident).first_or_404() + return edit_group_schema.jsonify(entity) + +@app.route('/v0/editgroup', methods=['POST']) +def api_edit_group_create(): + params = request.get_json() + eg = EditGroup( + editor_id=1, + description=params.get('description', None), + ) + if params.get('extra', None): + ser = json.dumps(params['extra'], indent=False).encode('utf-8') + eg.extra_json = ExtraJson(json=ser, sha1=hashlib.sha1(ser).hexdigest()) + db.session.add(eg) + db.session.commit() + return edit_group_schema.jsonify(eg) + diff --git a/fatcat/models.py b/fatcat/models.py index 25791cd7..6c413dc7 100644 --- a/fatcat/models.py +++ b/fatcat/models.py @@ -22,8 +22,9 @@ class ReleaseContrib(db.Model): __tablename__ = "release_contrib" release_rev = db.Column(db.ForeignKey('release_rev.id'), nullable=False, primary_key=True) creator_ident_id = db.Column(db.ForeignKey('creator_ident.id'), nullable=False, primary_key=True) - type = db.Column(db.String, nullable=True) stub = db.Column(db.String, nullable=True) + type = db.Column(db.String, nullable=True) + # TODO: index (int)? creator = db.relationship("CreatorIdent") release = db.relationship("ReleaseRev") @@ -86,7 +87,7 @@ class WorkEdit(db.Model): redirect_id = db.Column(db.ForeignKey('work_ident.id'), nullable=True) edit_group_id = db.Column(db.ForeignKey('edit_group.id'), nullable=True) extra_json = db.Column(db.ForeignKey('extra_json.sha1'), nullable=True) - ident = db.relationship("WorkIdent", foreign_keys="WorkEdit.ident_id") # XXX: add to all other entities + ident = db.relationship("WorkIdent", foreign_keys="WorkEdit.ident_id") rev = db.relationship("WorkRev") edit_group = db.relationship("EditGroup") @@ -128,6 +129,9 @@ class ReleaseEdit(db.Model): redirect_id = db.Column(db.ForeignKey('release_ident.id'), nullable=True) edit_group_id = db.Column(db.ForeignKey('edit_group.id'), nullable=True) extra_json = db.Column(db.ForeignKey('extra_json.sha1'), nullable=True) + ident = db.relationship("ReleaseIdent", foreign_keys="ReleaseEdit.ident_id") + rev = db.relationship("ReleaseRev") + edit_group = db.relationship("EditGroup") class CreatorRev(db.Model): @@ -155,6 +159,9 @@ class CreatorEdit(db.Model): redirect_id = db.Column(db.ForeignKey('creator_ident.id'), nullable=True) edit_group_id = db.Column(db.ForeignKey('edit_group.id'), nullable=True) extra_json = db.Column(db.ForeignKey('extra_json.sha1'), nullable=True) + ident = db.relationship("CreatorIdent", foreign_keys="CreatorEdit.ident_id") + rev = db.relationship("CreatorRev") + edit_group = db.relationship("EditGroup") class ContainerRev(db.Model): @@ -185,6 +192,9 @@ class ContainerEdit(db.Model): redirect_id = db.Column(db.ForeignKey('container_ident.id'), nullable=True) edit_group_id = db.Column(db.ForeignKey('edit_group.id'), nullable=True) extra_json = db.Column(db.ForeignKey('extra_json.sha1'), nullable=True) + ident = db.relationship("ContainerIdent", foreign_keys="ContainerEdit.ident_id") + rev = db.relationship("ContainerRev") + edit_group = db.relationship("EditGroup") class FileRev(db.Model): @@ -213,6 +223,9 @@ class FileEdit(db.Model): redirect_id = db.Column(db.ForeignKey('file_ident.id'), nullable=True) edit_group_id = db.Column(db.ForeignKey('edit_group.id'), nullable=True) extra_json = db.Column(db.ForeignKey('extra_json.sha1'), nullable=True) + ident = db.relationship("FileIdent", foreign_keys="FileEdit.ident_id") + rev = db.relationship("FileRev") + edit_group = db.relationship("EditGroup") ### Editing ################################################################# @@ -223,6 +236,8 @@ class EditGroup(db.Model): editor_id = db.Column(db.ForeignKey('editor.id'), nullable=False) description = db.Column(db.String) editor = db.relationship('Editor', foreign_keys='EditGroup.editor_id') + extra_json_id = db.Column(db.ForeignKey('extra_json.sha1'), nullable=True) + extra_json = db.relationship("ExtraJson") # XXX: for all entities class Editor(db.Model): __tablename__ = 'editor' diff --git a/tests/test_backend.py b/tests/test_backend.py index 873009f9..3ca33add 100644 --- a/tests/test_backend.py +++ b/tests/test_backend.py @@ -179,3 +179,107 @@ class APITestCase(FatcatTestCase): assert WorkEdit.query.count() == 1 # not alive yet assert WorkIdent.query.filter(WorkIdent.is_live==True).count() == 0 + + def test_api_complete_create(self): + + # TODO: create user? + + rv = self.app.post('/v0/editgroup', + data=json.dumps(dict( + extra=dict(q=1, u="zing"))), + headers={"content-type": "application/json"}) + assert rv.status_code == 200 + obj = json.loads(rv.data.decode('utf-8')) + editgroup_id = obj['id'] + + for cls in (WorkIdent, WorkRev, WorkEdit, + ContainerIdent, ContainerRev, ContainerEdit, + CreatorIdent, CreatorRev, CreatorEdit, + ReleaseIdent, ReleaseRev, ReleaseEdit, + FileIdent, FileRev, FileEdit, + ChangelogEntry): + assert cls.query.count() == 0 + + rv = self.app.post('/v0/container', + data=json.dumps(dict( + name="schmournal", + publisher="society of authors", + issn="2222-3333", + editgroup=editgroup_id)), + #extra=dict(a=1, i="zing"))), + headers={"content-type": "application/json"}) + assert rv.status_code == 200 + obj = json.loads(rv.data.decode('utf-8')) + container_id = obj['id'] + + rv = self.app.post('/v0/creator', + data=json.dumps(dict( + name="anon y. mouse", + orcid="0000-0002-1825-0097", + editgroup=editgroup_id)), + #extra=dict(w=1, q="zing"))), + headers={"content-type": "application/json"}) + assert rv.status_code == 200 + obj = json.loads(rv.data.decode('utf-8')) + creator_id = obj['id'] + + rv = self.app.post('/v0/work', + data=json.dumps(dict( + title="dummy work", + work_type="book", + editgroup=editgroup_id)), + #extra=dict(a=1, b="zing"))), + headers={"content-type": "application/json"}) + assert rv.status_code == 200 + obj = json.loads(rv.data.decode('utf-8')) + work_id = obj['id'] + + rv = self.app.post('/v0/release', + data=json.dumps(dict( + title="dummy work", + work_type="book", + #work=work_id, + #container=container_id, + #creators=[creator_id], + doi="10.1234/5678", + editgroup=editgroup_id, + refs=[ + dict(stub="some other journal article"), + ])), + #extra=dict(f=7, b="zing"))), + headers={"content-type": "application/json"}) + assert rv.status_code == 200 + obj = json.loads(rv.data.decode('utf-8')) + release_id = obj['id'] + + rv = self.app.post('/v0/file', + data=json.dumps(dict( + sha1="deadbeefdeadbeef", + size=1234, + release=release_id, + editgroup=editgroup_id)), + #extra=dict(f=7, b="zing"))), + headers={"content-type": "application/json"}) + assert rv.status_code == 200 + obj = json.loads(rv.data.decode('utf-8')) + + for cls in (WorkIdent, WorkRev, WorkEdit, + ContainerIdent, ContainerRev, ContainerEdit, + CreatorIdent, CreatorRev, CreatorEdit, + ReleaseIdent, ReleaseRev, ReleaseEdit, + FileIdent, FileRev, FileEdit): + assert cls.query.count() == 1 + # Ident only: assert cls.query.filter(is_live=True).count() == 1 + + rv = self.app.post('/v0/editgroup/{}/accept'.format(editgroup_id), + headers={"content-type": "application/json"}) + # XXX: assert rv.status_code == 200 + # XXX: assert ChangelogEntry.query.count() == 1 + + for cls in (WorkIdent, WorkRev, WorkEdit, + ContainerIdent, ContainerRev, ContainerEdit, + CreatorIdent, CreatorRev, CreatorEdit, + ReleaseIdent, ReleaseRev, ReleaseEdit, + FileIdent, FileRev, FileEdit): + assert cls.query.count() == 1 + # Ident only: assert cls.query.filter(is_live=True).count() == 1 -- cgit v1.2.3