Skip to content

Commit

Permalink
(PXP-5525): Add blank version of record (#271)
Browse files Browse the repository at this point in the history
* Update swagger API docs

* First pass implement POST /index/blank/{GUID}

- Create a blank record that is a new version of a previous record
(i.e. shared a baseid with previous record)
- acl/authz carry over from previous record
- requires update permission on previous record
- user must specify uploader field, can optionally specify file_name field
(following convention of POST /index/blank)

* Add unit tests for POST /index/blank/{GUID}

* Fix errors

- Return 201 on success
- Fix syntax error in driver

* Run black

* Remove buggy test

* Test no record found condition

* Run black

* Remove unnecessary guard for duplicate GUID

* Revert deletion of test_create_blank_record_with_baseid

* Run black

* Update indexd/index/blueprint.py

Co-authored-by: Pauline Ribeyre <ribeyre@uchicago.edu>

* Support specifying guid

- allow specifying guid
- update swagger docs
- check for GUID already exists
- write tests for specifying guid

* Update swagger docs

- Remove unneeded OutputRefWithUrl
- Update index/blank and index/blank/{{GUID}} endpoints to return 201, not 200

* Add test for creating blank version of blank record

* Fix typo, remove unused import, run black

Co-authored-by: Pauline Ribeyre <ribeyre@uchicago.edu>
  • Loading branch information
mpingram and paulineribeyre committed May 22, 2020
1 parent 908c40d commit 16c3e4f
Show file tree
Hide file tree
Showing 4 changed files with 380 additions and 13 deletions.
25 changes: 25 additions & 0 deletions indexd/index/blueprint.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,31 @@ def post_index_blank_record():
return flask.jsonify(ret), 201


@blueprint.route("/index/blank/<path:record>", methods=["POST"])
def add_index_blank_record_version(record):
"""
Create a new blank version of the record with this GUID.
Authn/authz fields carry over from the previous version of the record.
Only uploader and optionally file_name fields are filled.
Returns the GUID of the new blank version and the baseid common to all versions
of the record.
"""
uploader = flask.request.get_json().get("uploader")
file_name = flask.request.get_json().get("file_name")
new_did = flask.request.json.get("did")
if not uploader:
raise UserError("no uploader specified")

# authorize done in add_blank_version for the existing record's authz
did, baseid, rev = blueprint.index_driver.add_blank_version(
record, new_did=new_did, uploader=uploader, file_name=file_name
)

ret = {"did": did, "baseid": baseid, "rev": rev}

return flask.jsonify(ret), 201


@blueprint.route("/index/blank/<path:record>", methods=["PUT"])
def put_index_blank_record(record):
"""
Expand Down
48 changes: 48 additions & 0 deletions indexd/index/drivers/alchemy.py
Original file line number Diff line number Diff line change
Expand Up @@ -1153,6 +1153,54 @@ def add_version(

return record.did, record.baseid, record.rev

def add_blank_version(
self, current_did, new_did=None, file_name=None, uploader=None
):
"""
Add a blank record version given did.
Authn/authz fields carry over from previous version.
"""
with self.session as session:
query = session.query(IndexRecord).filter_by(did=current_did)

try:
old_record = query.one()
except NoResultFound:
raise NoRecordFound("no record found")
except MultipleResultsFound:
raise MultipleRecordsFound("multiple records found")

auth.authorize("update", [u.resource for u in old_record.authz])

# handle the edgecase where new_did matches the original doc's did to
# prevent sqlalchemy FlushError
if new_did == old_record.did:
raise UserError("{did} already exists".format(did=new_did), 400)

new_record = IndexRecord()
did = new_did
if not did:
did = str(uuid.uuid4())
if self.config.get("PREPEND_PREFIX"):
did = self.config["DEFAULT_PREFIX"] + did

new_record.did = did
new_record.baseid = old_record.baseid
new_record.rev = str(uuid.uuid4())[:8]
new_record.file_name = file_name
new_record.uploader = uploader

new_record.acl = old_record.acl
new_record.authz = old_record.authz

try:
session.add(new_record)
session.commit()
except IntegrityError:
raise UserError("{did} already exists".format(did=did), 400)

return new_record.did, new_record.baseid, new_record.rev

def get_all_versions(self, did):
"""
Get all record versions (in order of creation) given DID
Expand Down
71 changes: 58 additions & 13 deletions openapis/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ paths:
schema:
$ref: '#/definitions/InputBlankInfo'
responses:
'200':
'201':
description: successful operation
schema:
$ref: '#/definitions/OutputRef'
Expand All @@ -245,6 +245,39 @@ paths:
security:
- basic_auth: []
'/index/blank/{GUID}':
post:
tags:
- index
summary: Create a new, blank version for the document associated to the provided uuid.
description: Creates a new blank version of a record with the provided GUID. Returns the GUID of the new version of the record and the baseid common to all versions of the record. Authorization (acl/authz fields) carry over from the original record to the new blank version. No other metadata (md5sum, etc) carries over from the original record to the new blank version.
operationId: addNewBlankVersion
consumes:
- application/json
produces:
- application/json
parameters:
- name: GUID
in: path
description: the uuid associated to the record needed to have new version
required: true
type: string
- in: body
name: body
description: Metadata object that needs to be added to the store
required: true
schema:
$ref: '#/definitions/InputBlankVersionInfo'
responses:
'201':
description: successful operation
schema:
$ref: '#/definitions/OutputRef'
'400':
description: Invalid status value
'404':
description: GUID does not exist
security:
- basic_auth: []
put:
tags:
- index
Expand Down Expand Up @@ -898,7 +931,7 @@ paths:
- DOS
'/ga4gh/drs/v1/objects':
get:
summary: List all DrsObject.
summary: List all DrsObject.
description: 'Url field here contains their location and not the presigned url.'
operationId: ListDrsObject
responses:
Expand Down Expand Up @@ -966,13 +999,13 @@ paths:
type: boolean
default: false
description: >-
NOT IMPLEMENTED YET.
NOT IMPLEMENTED YET.
If false and the object_id refers to a bundle, then the ContentsObject array
contains only those objects directly contained in the bundle. That is, if the
bundle contains other bundles, those other bundles are not recursively
included in the result.
If true and the object_id refers to a bundle, then the entire set of objects
in the bundle is expanded. That is, if the bundle contains aother bundles,
then those other bundles are recursively expanded and included in the result.
Expand Down Expand Up @@ -1047,7 +1080,7 @@ paths:
tags:
- DRS
x-swagger-router-controller: ga4gh.drs.server

'/bulk/documents':
post:
tags:
Expand All @@ -1071,7 +1104,7 @@ paths:
'400':
description: Invalid status value
security: []

'/_query/urls/q':
get:
tags:
Expand Down Expand Up @@ -1311,6 +1344,18 @@ definitions:
file_name:
type: string
description: name of the uploaded file
InputBlankVersionInfo:
type: object
properties:
uploader:
type: string
description: user who uploaded this file
file_name:
type: string
description: optional; name of the uploaded file
did:
type: string
description: optional; specify the GUID of the new blank version that is created.
UpdateInputInfo:
type: object
properties:
Expand Down Expand Up @@ -1790,7 +1835,7 @@ definitions:
format: date-time
description: |-
Timestamp of content creation in RFC3339.
(This is the creation time of the underlying content, not of the JSON object.)
(This is the creation time of the underlying content, not of the JSON object.)
updated_time:
type: string
format: date-time
Expand Down Expand Up @@ -1909,7 +1954,7 @@ definitions:
A name declared by the bundle author that must be
used when materialising this object,
overriding any name directly associated with the object itself.
The name must be unique with the containing bundle.
The name must be unique with the containing bundle.
This string is made up of uppercase and lowercase letters, decimal digits, hypen, period, and underscore [A-Za-z0-9.-_]. See http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_282[portable filenames].
id:
type: string
Expand All @@ -1936,7 +1981,7 @@ definitions:
items:
example:
{}

required:
- name
Error:
Expand All @@ -1949,15 +1994,15 @@ definitions:
description: A detailed error message.
status_code:
type: integer
description: The integer representing the HTTP status code (e.g. 200, 404).
description: The integer representing the HTTP status code (e.g. 200, 404).
ListDrsObject:
type: object
properties:
drs_objects:
drs_objects:
type: array
items:
$ref: '#/definitions/DrsObject'

ListRecords:
type: object
properties:
Expand Down
Loading

0 comments on commit 16c3e4f

Please sign in to comment.