summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fatcat/api.py132
-rw-r--r--fatcat/models.py19
-rw-r--r--tests/test_backend.py104
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/<work_id>', 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/<int:ident>', 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/<file_id>', 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/<int:ident>', 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/<int:ident>', 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/<int:ident>', 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/<int:ident>', 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/<int:ident>', 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