Menu

APIsandStandards

Domhnall101

APIs, Standards and Guidlines

Tradamus Coding Guidelines
Annotation API
Collation API
Core API
Edition API
Edition API Structures
Publication API
Publication API Structures
T-PEN Proxy API

Endpoint Permissions
Help Documents
JavaScript Guidelines
Publication Printing Conventions
Permissions and Roles
Tradamus Coding Guidelines

Draft 2015-06-05

Get annotation details

Endpoint: /annotation/annID
Method: GET
Request body: none
Response body: {"id":81538,"startOffset":1938,"endOffset":1938,"target":null,"selector":null,"type":"g","purpose":"NONE","content":null,"attributes":"{\"ref\":\"#slash\"}","modifiedBy":0,"approvedBy":0,"startPage":17000,"endPage":17000,"bounds":null,"canvas":null}
Status: 200 on success, 404 if annID does not exist.

Set annotation details

Endpoint: /annotation/annID
Method: PUT
Request body: {"content":"/"}
Response body: none
Status: 204 on success, 404 if annID does not exist.
Comments:
The JSON object in the request body should contain all fields which are to be modified; fields which aren't being changed can be omitted.

Add a sub-annotation

Endpoint: /annotation/annID₁/annotations
Method: POST
Request content-type: application/json
Request body: {"type":"colour","content":"turquoise"}
Response body: none
Response location: /annotation/annID₂
Status: 201 on success, 404 if annID₁ does not exist.
Comments:
The request body should contain a single annotation object. The Location header of the response gives the caller the ID of the newly-created annotation.

Get sub-annotations

Endpoint: /annotation/annID/annotations
Method: GET
Request body: none
Response body: Array of annotations attached to annID.
Status: 200 on success, 404 if annID does not exist.
Comments:
Response contains an array with all annotations attached the given annotation.

Set sub-annotations

Endpoint: /annotation/annID/annotations
Method: PUT
Request body: Array of new annotations to be attached to annID.
Request parameters: merge=true|false (default true)
Response body: none
Status: 204 on success, 404 if annID does not exist.
Comments:
The JSON array in the request body should contain new values for the annotation's sub-annotations. If the merge parameter is false, the existing sub-annotations will be completely replaced; if it is true or omitted, only annotations mentioned in the request body will be affected.

Approve an annotation

Endpoint: /annotation/annID/approval
Method: PUT
Request body: none
Response body: none
Status: 204 on success, 403 if the user does not have EDITOR permission on annID, 404 if annID does not exist.
Comments:
Sets the approvedBy field of the annotation to the ID of the current user.

Delete an annotation

Endpoint: /annotation/annID
Method: DELETE
Request body: none
Response body: none
Status: 204 on success.
Comments:
Deletes the single annotation identified by annID.


Draft 2015-06-16

Collation API

Invokes the CollateX engine to generate a comparison of the specified witnesses. CollateX is invoked with the Needleman-Wunsch algorithm. The details of the collation can be controlled using the parameters described here:

parameter value effect
comparison plain Witnesses are compared using just their text content.
comparison morph Witnesses are compared based on their morphological content, using analysis performed by the Perseus morphology engine.
comparison orth Witnesses are compared in an orthographically-aware manner, taking into account common spelling irregularities. The dict parameter can be specified, to indicate the spelling dictionary to be used.
dict lat Specifies a spelling dictionary to be used for orth comparison. May be specified multiple times to use multiple spelling dictionaries.
ignoreCase true Upper/lower case differences are ignored.
ignoreCase false Upper/lower case differences are considered significant.
ignoreLineBreaks true The collator ignores line-breaks and hyphenation.
ignoreLineBreaks hyphens The collator ignores line-breaks which immediately follow a hyphen.
ignoreLineBreaks false The collator considers line-breaks as ordinary white-space.
ignorePunctuation true Punctuation differences are ignored.
ignorePunctuation false Punctuation differences are considered significant.
useTEITags true Embedded TEI editorial tags (e.g those from §3.4 Simple Editorial Changes) are applied to the content before making the comparison.
useTEITags false No special treatment for embedded TEI tags.

Full-edition collation

Endpoint: /collation/edID
Method: POST
Request body: none
Request parameters:
comparison=plain|morph|orth (default plain)
dict=dictionary (default lat; may be specified multiple times)
ignoreCase=true|false (default false)
ignoreLineBreaks=true|hyphens|false (default false)
ignorePunctuation=true|false (default false)
useTEITags=true|false (default false)
deferred=true|false (default false)
Response content-type: application/json
Response location: if deferred=true, /deliverable/delID
Response body: an array of arrays of mote annotations (empty if deferred=true):
[
   [
      {"content":"Lectio 1, Prologus","endOffset":18,"target":"#2","endPage":2000,"startPage":2000,"startOffset":0,"type":"tr-mote"},
      {"content":"Lectio 1, Prologus","endOffset":18,"target":"#1","endPage":1000,"startPage":1000,"startOffset":0,"type":"tr-mote"}
   ],
   [
      {"content":"[Reims","endOffset":25,"target":"#1","endPage":1000,"startPage":1000,"startOffset":19,"type":"tr-mote"}
   ],
   [
      {"content":"[Sorbonne","endOffset":28,"target":"#2","endPage":2000,"startPage":2000,"startOffset":19,"type":"tr-mote"}
   ],
   …
]
Status: 200 on success if deferred=false or 303 if deferred=true, 404 if edID does not exist.
Comments: This provides a full collation of all the witnesses in the specified edition. The response contains an array of arrays of mote annotations. Each of the subarrays contains mote annotations which the collator has determined to be in correspondence. The target field of the mote annotations is used to indicate the witness whose content provides support for the annotation. If deferred=true is supplied on the parameter list, the response body will be empty, but the location header will return the URI where the results of the collation will be available.

Sub-collation

Endpoint: /collation
Method: POST
Request content-type: application/json
Request body: an array of text ranges:
[
   {"startPage":1000,"startOffset":0,"endPage":1000,"endOffset":477},
   {"startPage":2000,"startOffset":0,"endPage":2000,"endOffset":360}
]
Request parameters:
comparison=text|morph|orth (default text)
dict=dictionary (default lat; may be specified multiple times)
ignoreCase=true|false (default false)
ignoreLineBreaks=true|hyphens|false (default false)
ignorePunctuation=true|false (default false)
useTEITags=true|false (default false)
deferred=true|false (default false)
Response content-type: application/json
Response location: if deferred=true, /deliverable/delID
Response body: an array of arrays of mote annotations (empty if deferred=true):
[
   [
      {"content":"Lectio 1, Prologus","endOffset":18,"target":"#2","endPage":2000,"startPage":2000,"startOffset":0,"type":"tr-mote"},
      {"content":"Lectio 1, Prologus","endOffset":18,"target":"#1","endPage":1000,"startPage":1000,"startOffset":0,"type":"tr-mote"}
   ],
   [
      {"content":"[Reims","endOffset":25,"target":"#1","endPage":1000,"startPage":1000,"startOffset":19,"type":"tr-mote"}
   ],
   [
      {"content":"[Sorbonne","endOffset":28,"target":"#2","endPage":2000,"startPage":2000,"startOffset":19,"type":"tr-mote"}
   ],
   …
]
Status: 200 on success if deferred=false or 303 if deferred=true, 400 if the text ranges are not consistent (e.g. a range has a negative length, or refers to pages from two separate witnesses).
Comments: The request body must contain an array of JSON objects specifying the text ranges to be collated. In practice, this may be an array of annotations, but that need not be the case. The response contains an array of arrays of mote annotations. Each of the subarrays contains mote annotations which the collator has determined to be in correspondence. The target field of the mote annotations is used to indicate the witness whose content provides support for the annotation. If deferred=true is supplied on the parameter list, the response body will be empty, but the location header will return the URI where the results of the collation will be available.


Draft 2015-06-16

Core API

1. Users

Users are created by POSTing JSON data to the /users endpoint. Information about a particular user can be retrieved by a get request to /user/userID.

Add new user

Endpoint: /users
Method: POST
Request content-type: application/json
Request body: { "mail" : "emailAddress", "name" : "fullName", "password" : "password" }
Response location: /user/userID
Response body: none
Status: 201 on success, 409 if email address already in use.
Comments:
The newly-registered user will be sent an email, which requires them to click a link to confirm their registration. The user's creation and last_login fields will be set to the current time.

Invite new user to edition

Endpoint: /users
Method: POST
Request content-type: application/json
Request body: { "mail" : "emailAddress", "name" : "fullName", "edition" : edID }
Response location: /user/userID
Response body: none
Status: 201 on success, 409 if email address already in use.
Comments:
The invitee will receive an email indicating that they have been invited by the current user (i.e. the one whose session invoked the endpoint) to work on the given edition. The email provides a temporary randomly-generated password, as well as a link which has to be clicked to activate the new account. The new user's creation field will be set to the current time, but their last_login field will be left as NULL. The new user will be granted CONTRIBUTOR access to the edition; it is up to the edition's owner to upgrade their access if so desired.

Invite new user to publication

Endpoint: /users
Method: POST
Request content-type: application/json
Request body: { "mail" : "emailAddress", "name" : "fullName", "publication" : pubID }
Response location: /user/userID
Response body: none
Status: 201 on success, 409 if email address already in use.
Comments:
The invitee will receive an email indicating that they have been invited by the current user (i.e. the one whose session invoked the endpoint) to work on the given publication. The email provides a temporary randomly-generated password, as well as a link which has to be clicked to activate the new account. The new user's creation field will be set to the current time, but their last_login field will be left as NULL. The new user will be granted CONTRIBUTOR access to the publication; it is up to the publication's owner to upgrade their access if so desired.

Invite new anonymous user to publication

Endpoint: /users
Method: POST
Request content-type: application/json
Request body: { "mail" : "emailAddress", "publication" : pubID }
Response location: /user/userID
Response body: none
Status: 201 on success.
Comments:
The invitee will receive an email indicating that they have been invited by the current user (i.e. the one whose session invoked the endpoint) to work on the given publication. The email provides a randomly-generated user-name (which will also double as a password), as well as a link to the review page for the given publication. Unlike ordinary users, newly-created anonymous users do not have to visit the confirmation page. Once the invitation email has been sent, the email address is not stored anywhere by Tradamus. The new user's creation field will be set to the current time, but their last_login field will be left as NULL. The new user will be granted CONTRIBUTOR access to the publication.

Get user details

Endpoint: /user/userID
Method: GET
Request body: none
Response content-type: application/json
Response body: {"id":1,"mail":"ericsmith@slu.edu","name":"Eric Smith","disabled":false,"creation":1372884249000,"lastLogin":1372885349000}
Status: 200 on success, 401 if not logged in, 404 if user not found.
Comments:
Returns a JSON object providing details about the requested user.

Get user details by email

Endpoint: /user?mail=emailAddress
Method: GET
Request body: none
Response content-type: application/json
Response body: {"id":1,"mail":"ericsmith@slu.edu","name":"Eric Smith","disabled":false,"creation":1372884249000,"lastLogin":1372885349000}
Response location: /user/userID
Status: 200 on success, 401 if not logged in, 404 if user not found.
Comments:
Returns a JSON object providing details about the requested user.

Modify user details

Endpoint: /user/userID
Method: PUT
Request content-type: application/json
Request body (all fields optional) { "mail" : "emailAddress", "name" : "fullName", "password" : "password" }
Response body: none
Status: 204 on success, 401 if not logged in, 403 if you try to modify another user.
Comments:
Any fields which are specified in the request body will be set to the supplied values. Fields which are omitted will be unchanged.

Reset user password

Endpoint: /user?reset=emailAddress
Method: PUT
Request content-type: n/a
Request body: none
Response body: none
Status: 204 on success, 404 if emailAddress is not found.
Comments:
A new random password will be generated and emailed to the user.

Ask to resend confirmation email

Endpoint: /user?resend=emailAddress
Method: PUT
Request content-type: n/a
Request body: none
Response body: none
Status: 204 on success, 404 if emailAddress is not found, 410 if emailAddress has already been confirmed.
Comments:
The confirmation email will be resent to the given email.

2. Login

Log in to Tradamus

Endpoint: /login
Method: POST
Request content-type: application/json
Request body: { "mail" : "emailAddress", "password" : "password" }
Response location: /user/userID
Response body: none
Response cookies: JSESSIONID=sessionID; Path=/Tradamus/; HttpOnly
Status: 204 on success, 401 on invalid login.

Log out of Tradamus

Endpoint: /login
Method: POST
Request content-type: n/a
Request body: must be empty
Response body: none
Response cookies: JSESSIONID=sessionID; Path=/Tradamus/; HttpOnly
Status: 204 on success.

Check login status

Endpoint: /login
Method: GET
Request body: none
Response content-type: application/json
Response body: { "id":userID, "mail":"emailAddress","name":"fullName","disabled":false,"creation":creationTime,"lastLogin":lastLoginTime }
Status: 200 if JSESSIONID is valid, 401 if it's not.

3. Config

Endpoint: /config
Method: GET
Request body: none
Response content-type: application/json
Response body: {"version":"0.9.1", "revision":189}
Status: 200 on success.
Comments: The response's "version" property contains the "version-num" property from build.xml. The "revision" property contains the SVN revision which was used to build the WAR file. At present, this endpoint does not require authentication.

4. Activity Log

Endpoint: /activity
Method: GET
Parameters: user=userID to retrieve activities of a given user
table=table&id=id to retrieve activities associated with a given entity. The table parameter can be one of annotations, canvasses, editions, images, manifests, outlines, pages, transcriptions, users, or witnesses. The optional id parameter identifies the particular entity of that type.
limit=limit to limit the number of records returned
Request body: none
Response body: An array of activity records:
[
   {
      "content":"Lectio 1, Prologus [Reims Transcription]",
      "operation":"INSERT",
      "time":1381535382000,
      "entity":"witness/1",
      "parent":"edition/1",
      "user":2
   },
   …
]
Status: 200 on success
Comments: The endpoint returns an array of activity entries. The operation property can be INSERT, UPDATE, DELETE, or VIEW. The entity which changed is identified by the entity property. The time of the activity and the user responsible are specified by the time and user properties. For insertions, there will also be a parent property which identifies where the newly-created entity was inserted.

The content property describes the change that occurred. The values are summarised in this table:

operation type content
INSERT editions Title of newly-created edition
UPDATE editions JSON object containing changes sent by the client
For /editions sub-endpoints, it may be a JSON array of motes, or permissions.
INSERT users Name of newly-created user
UPDATE users "Account confirmed."
INSERT witnesses Title of newly-created witness
UPDATE witnesses "Witness updated."
UPDATE other JSON object containing changes sent by the client
DELETE all none

5. Deferred Results

Certain endpoints which invoke long-running processes (currently collation and generation of PDFs) have the option of producing deferred results. The endpoint will return immediately with a 303 "See Other" result and a location header which points to the /deliverable endpoint along with a particular deliverable ID.

Endpoint: /deliverable/delID
Method: GET
Parameters: none
Request body: none
Response content-type: application/json for deferred collation, application/pdf for PDF generation
Response body: results of the long-running process


Draft 2015-06-09

Edition API

1. Editions

Editions are created by POSTing JSON data to the /editions endpoint. The list of editions can be retrieved by a GET request to the /editions endpoint.

Add new edition

Endpoint: /editions
Method: POST
Request content-type: application/json
Request body: { "title" : "title" }
Response location: /edition/edID
Response body: none
Status: 201 on success.
Comments:
Requires valid JSESSIONID cookie to get the ID of the logged in user. This will be stored as the edition's creator field.

List editions

Endpoint: /editions
Method: GET
Request body: none
Response content-type: application/json
Response body: [{"id":edID₁, "title":"title₁"}, … ]
Comments:
Retrieves an array of all edition IDs and titles which for which the logged-in user has at least VIEWER permission. The GET /edition/edID endpoint can then be used to retrieve the details of that edition.

Get edition details

Endpoint: /edition/edID
Method: GET
Request body: none
Response content-type: application/json
Response body: {
  "id":1,"title":"Petrus Plaoul 1","creator":2
  "witnesses":[
    {"id":3,"title":"Lectio 1, Prologus [Reims Transcription]","siglum":"R"},
    {"id":7,"title":"Lectio 1, Prologus [Sorbonne Transcription]","siglum":"S"}
  ],
  "permissions":[
    {"id":2,"role":"OWNER","name":"Joe User","mail":"joe@slu.edu"}
  ]
  "metadata":[
    {"id":1856,"type":"colour","content":"turquoise"}
  ]
  "outlines":[6, 7]
}
Status: 200 on success, 404 if edID does not exist.
Comments:
The response's "creator" field contains a user ID. The "witnesses" field contains an array of witness information for this edition. The "permissions" field contains an array of all permissions associated with the edition. The "outlines" field contains an array of all outlines associated with this edition.

Set edition details

Endpoint: /edition/edID
Method: PUT
Request content-type: application/json
Request body: {"title":"New Title"}
Response body: none
Status: 204 on success, 404 if edID does not exist.
Comments:
The request body should contain a JSON object describing the fields to be changed. Currently, the only valid field is "title", but this may change.

Add an edition metadatum

Endpoint: /edition/edID/metadata
Method: POST
Request content-type: application/json
Request body: {"type":"colour","content":"turquoise"}
Response body: none
Response location: /annotation/annID
Status: 201 on success, 404 if edID does not exist.
Comments:
The request body should contain a single annotation object. The Location header of the response gives the caller the ID of the newly-created metadatum.

Set edition metadata

Endpoint: /edition/edID/metadata
Method: PUT
Request content-type: application/json
Request body: [{"type":"colour","content":"turquoise"}]
Request parameters: merge=true|false (default true)
Response body: none
Status: 204 on success, 404 if edID does not exist.
Comments:
The request body should contain an array of annotation objects. If the merge parameter is false, the contents of the array will completely replace the edition's existing metadata; if merge=true, the PUT will only affect metadata objects included in the request body. In either case, the call will create any objects found in the request body which don't already exist.

Approve edition metadata

Endpoint: /edition/edID/approval
Method: PUT
Request content-type: application/json
Request body (optional): [annID₁, annID₂,…]
Response body: none
Status: 204 on success, 403 if the user does not have EDITOR permission on edID, 404 if edID does not exist.
Comments:
Sets the approvedBy field of the edition's metadata to the ID of the current user. If the request body contains an array of annotation IDs, only those annotations will be marked as approved. If the request body is absent, all the edition's metadata will be approved.

Add edition outline

Endpoint: /edition/edID/outlines
Method: POST
Request content-type: application/json
Request body: {
   "edition":3,
   "title":"Conclusio",
   "index":2,
   "bounds":[
      {"startPage":1000,"startOffset":489,"endPage":1000,"endOffset":1177},
      {"startPage":2000,"startOffset":494,"endPage":2000,"endOffset":1186},
      {"startPage":3000,"startOffset":472,"endPage":3000,"endOffset":1170}
   ],
   "decisions":[
      {"content":"in primis",
         "motes":[
            {"content":"in\nprimis","endOffset":506,"target":"#2","endPage":2000,"startPage":2000,"type":"tr-mote","startOffset":497},
            {"content":"in primis","endOffset":485,"target":"#3","endPage":3000,"startPage":3000,"type":"tr-mote","startOffset":476},
            {"content":"inprimis","endOffset":500,"target":"#1","endPage":1000,"startPage":1000,"type":"tr-mote","startOffset":492}
         ]
      },
      subsequent decisions associated with this outline
   ]
}

Response body: none
Response location: /outline/outlID
Comments:
Creates a new outline associated with the given edition. The "title" field is optional. The "index" field indicates the outline's index relative to the edition's other outlines, and defaults to 0 if omitted. The "bounds" field specifies the collation ranges which were used as the basis for the outline, and should be null for a full-edition collation. The "decisions" field contains an initial set of decisions made by the user; this field can be an empty array if the user has not yet made any decisions.

Set edition outlines

Endpoint: /edition/*edID/outlines
Method: PUT
Request content-type: application/json
Request body: array of outlines
Response body: none
Comments: Use this method to update all outlines associated with the edition. Useful for doing large-scale reorderings.

Set edition permissions

Endpoint: /edition/edID/permissions
Method: PUT
Request content-type: application/json
Request body: [{"user":uID, "role":"OWNER"}]
Request parameters: merge=true|false (default true)
Response body: none
Status: 204 on success, 404 if edID does not exist, 409 if the request body refers to a nonexistent user ID.
Comments:
The request body should contains an array of user permissions objects. The "user" field of each object should contain a user ID, and the "role" field one of "NONE", "VIEWER", "CONTRIBUTOR", "EDITOR", or "OWNER", identifying the permissions that will be granted to that user for the given edition. Specify "user":0 to set permissions for the "public sharing" user. If the merge parameter is false, the contents of the array will completely replace the edition's existing permissions; if it is true or omitted, only permissions mentioned in the request body will be affected.

Delete an edition

Endpoint: /edition/edID
Method: DELETE
Request body: none
Response body: none
Status: 204 on success.
Comments:
Deletes the single edition identified by edID. Associated witnesses, transcriptions, pages, manifests, canvasses, images, outlines, parallels, and annotations will also be deleted.

2. Witnesses

Witnesses are created by posting JSON, JSON-LD or XML data to an edition's witnesses endpoint. The list of witnesses can be retrieved by a GET request to the edition's witnesses endpoint.

Create a new witness using JSON

Endpoint: /edition/edID/witnesses
Method: POST
Parameters: none
Request content-type: application/json
Request body: {"title":"My Witness","siglum":"M"}
Status: 201 on success, 404 if edID does not exist.
Comments:
This allows the creation of a witness from JSON (non-LD) data. The "title" and "siglum" fields are required.

Import JSON-LD witness

Endpoint: /edition/edID/witnesses
Method: POST
Request content-type: application/ld+json
Request body: single-file IIIF metadata representation
Status: 201 on success, 404 if edID does not exist.
Comments:
Currently the only source for this type of file is the JSON-LD export from T-PEN. The IIIF metadata spec is still under development, and does not appear to yet be supported by any other software.

Endpoint: /edition/edID/witnesses
Method: POST
Parameters: src URL of JSON-LD source (i.e. T-PEN project)
Request content-type: application/ld+json
Request body: none
Status: 201 on success, 404 if edID does not exist, or error codes from T-PEN
Comments:
This differs from importing a JSON-LD witness because the call creates a persistent link to T-PEN which is checked for updates every time the user logs in.

Import XML witness

Endpoint: /edition/edID/witnesses
Method: POST
Request content-type: text/xml
Request body: TEI XML file
Status: 201 on success, 404 if edID does not exist.
Comments:
This has so far only been tested with TEI files from Jeffrey Witt's Petrus Plaoul corpus. The implementation will need to be generalised as we encounter other TEI files.

Import plain text witness

Endpoint: /edition/edID/witnesses
Method: POST
Parameters:

  • lineBreak string to indicate line breaks (e.g. lineBreak=%0a for linefeed)
  • pageBreak string to indicate page breaks (e.g. `pageBreak=%0c for control-L)
  • title string for witness title
  • siglum string for siglum
    Request content-type: text/plain
    Request body: text file
    Status: 201 on success, 404 if edID does not exist.
    Comments:

Get witness details

Endpoint: /witness/witID
Method: GET
Request body: none
Response body:
{
  "id":4,
  "author":"Petrus Plaoul",
  "edition":1,
  "title":"Lectio 1, Prologus [Vatican Transcription]",
  "manifest":3,
  "siglum":"V",
  "transcription":3,
  "metadata":{
    "editor":"Jeffrey C. Witt",
    "pubPlace":"Boston, MA"
  }
}
Status: 200 on success, 404 if witID does not exist.
Comments:

Set witness details

Endpoint: /witness/witID
Method: PUT
Request content-type: application/json
Request body: {"author":"New Author", "title":"New Title", "siglum":"New Siglum"}
Response body: none
Status: 204 on success, 404 if witID does not exist.
Comments:
The request body should contain a JSON object describing the fields to be changed. Any fields which are omitted from the request will remain unchanged.

Add a witness metadatum

Endpoint: /witness/witID/metadata
Method: POST
Request content-type: application/json
Request body: {"type":"colour","content":"turquoise"}
Response body: none
Response location: /annotation/annID
Status: 201 on success, 404 if witID does not exist.
Comments:
The request body should contain a single annotation object. The Location header of the response gives the caller the ID of the newly-created metadatum.

Set witness metadata

Endpoint: /witness/witID/metadata
Method: PUT
Request content-type: application/json
Request body: [{"type":"colour","content":"turquoise"}]
Request parameters: merge=true|false (default true)
Response body: none
Status: 204 on success, 404 if witID does not exist.
Comments:
The request body should contain an array of annotation objects. If the merge parameter is false, the contents of the array will completely replace the witness' existing metadata; if merge is true or omitted, the PUT will only affect metadata objects included in the request body. In either case, the call will create any objects found in the request body which don't already exist.

Approve witness metadata

Endpoint: /witness/witID/approval
Method: PUT
Request content-type: application/json
Request body (optional): [annID₁, annID₂,…]
Response body: none
Status: 204 on success, 403 if the user does not have EDITOR permission on witID, 404 if witID does not exist.
Comments:
Sets the approvedBy field of the witness' metadata to the ID of the current user. If the request body contains an array of annotation IDs, only those annotations will be marked as approved. If the request body is absent, all the witness' metadata will be approved.

Delete a witness

Endpoint: /witness/witID
Method: DELETE
Request body: none
Response body: none
Status: 204 on success.
Comments:
Deletes the single witness identified by witID. Associated transcriptions, pages, manifests, canvasses, images, and annotations will also be deleted.

Recursively get all witness annotations

Endpoint: /witness/witID/annotations
Method: GET
Request body: none
Response body:
Status: 200 on success, 404 if witID does not exist.
Comments:
Convenience function which aggregates the annotations from all canvasses and pages associated with the witness.

3. Transcriptions

Each witness has exactly one corresponding transcription object, which is created automatically when the witness is created. A transcription contains some metadata (e.g. the editor name), but its main purpose is to serve as a container to group together all the pages.

Get transcription details

Endpoint: /transcription/transcrID
Method: GET
Request body: none
Response body: {
  "id":1,"editor":"J. Witt",
  "pages":[
    {"id":1000,"title":"1r"},
    {"id":6001,"title":"1v"}
  ]
}
Status: 200 on success, 404 if transcrID does not exist.
Comments:
The "pages" field of the transcription object provides an array with the IDs and titles of all pages associated with said transcription.

Add a transcription annotation

Endpoint: /transcription/transcrID/annotations
Method: POST
Request content-type: application/json
Request body: {"type":"colour","content":"turquoise","startPage":1000,"startOffset":0,"endPage":1001,"endOffset":15}
Response body: none
Response location: /annotation/annID
Status: 201 on success, 404 if transcrID does not exist.
Comments:
The request body should contain a single annotation object. The Location header of the response gives the caller the ID of the newly-created annotation.

Get transcription pages

Endpoint: /transcription/transcrID/pages
Method: GET
Request body: none
Response body: array of pages
Status: 200 on success, 404 if transcrID does not exist.
Comments:
The response body will be an array containing all the pages belonging to this transcription. The format will be the same as that returned by a GET request to /page/pgID.

Set transcription permissions

Endpoint: /transcription/transcrID/permissions
Method: PUT
Request content-type: application/json
Request body: [{"user":uID, "role":"OWNER"}]
Request parameters: merge=true|false (default true)
Response body: none
Status: 204 on success, 404 if transcrID does not exist, 409 if the request body refers to a nonexistent user ID.
Comments:
The request body should contains an array of user permissions objects. The "user" field of each object should contain a user ID, and the "role" field one of "NONE", "VIEWER", "CONTRIBUTOR", "EDITOR", or "OWNER", identifying the permissions that will be granted to that user for the given transcription. Specify "user":0 to set permissions for the "public sharing" user. If the merge parameter is false, the contents of the array will completely replace the transcription's existing permissions; if it is true or omitted, only permissions mentioned in the request body will be affected.

4. Pages

Get page details

Endpoint: /page/pageID
Method: GET
Request body: none
Response body: {"id":5, "text":"Quantum ad istud…", "title":"S4r.jpg", "index":4, "transcription":1}
Status: 200 on success, 404 if pageID does not exist.
Comments:
The "index" field contains the page's index within the transcription as a whole. If the "annotations" parameter is specified, the response will include an array of all annotation objects attached to the page. Similarly, specifying the "lines" parameter will include an array of all line objects.

Set page details

Endpoint: /page/pageID
Method: PUT
Request body: {"id":5, "text":"Quantum ad istud…"}
Response body: none
Status: 204 on success, 404 if pageID does not exist.
Comments:
The JSON object in the request body should contain all fields which are to be modified; fields which aren't being changed can be omitted. Changing the page's "text" property may result in annotations being recalculated. Changing the page's "index" property can be used to reorder pages within the transcription.

Add a page annotation

Endpoint: /page/pgID/annotations
Method: POST
Request content-type: application/json
Request body: {"type":"colour","content":"turquoise"}
Response body: none
Response location: /annotation/annID
Status: 201 on success, 404 if pgID does not exist.
Comments:
The request body should contain a single annotation object. The annotation will be constrained so that it's startPage and endPage are both equal to pgID (to add an annotation which spans multiple pages, use the /transcription/*transcrID/annotations endpoint instead). The Location header of the response gives the caller the ID of the newly-created annotation.

Get page annotations

Endpoint: /page/pgID/annotations
Method: GET
Request body: none
Response body: [{"id":38042,"startOffset":0,"endOffset":46,"type":"line","purpose":"LB","content":"fratres nostri quae acta sunt et quae difinita","motivation":"sc:painting","canvas":2085,"bounds":{"height":50,"width":627,"y":76,"x":40},"startPage":2085,"endPage":2085},…]
Status: 200 on success, 404 if pgID does not exist.
Comments:
Response contains an array with all annotations found on the given page. This includes multi-page annotations whose page range includes the page in question. Since lines are annotations, they will be included in the response.

Set page annotations

Endpoint: /page/pgID/annotations
Method: PUT
Request body: [{"id":38042,"startOffset":0,"endOffset":46,"type":"line","purpose":"LB","content":"fratres nostri quae acta sunt et quae difinita","motivation":"sc:painting","canvas":2085,"bounds":{"height":50,"width":627,"y":76,"x":40},"startPage":2085,"endPage":2085},…]
Request parameters: merge=true|false (default true)
Response body: none
Status: 204 on success, 404 if pgID does not exist.
Comments:
The JSON array in the request body should contain new values for the page's annotations. If the merge parameter is false, the existing annotations will be completely replaced; if it is true or omitted, only annotations mentioned in the request body will be affected. For the purposes of this endpoint, a page's annotations are considered to be all annotations whose "startPage" to "endPage" range includes pgID.

Get page lines

Endpoint: /page/pgID/lines
Method: GET
Request body: none
Response body: [
  {"id":34796,"startOffset":0,"endOffset":55,"selector":null,"type":"line","purpose":"LB","content":"episcopum fuisse aut esse neque ipsos qui ab eo ordina-","attributes":null,"startPage":6118,"endPage":6118,"bounds":{"height":94,"width":662,"y":9,"x":53},"canvas":6118},
  …
]
Status: 200 on success, 404 if pgID does not exist.
Comments:
Response contains an array with all line annotations found on the given page.

Set page lines

Endpoint: /page/pageID/lines
Method: PUT
Request body: [{"id":38042,"startOffset":0,"endOffset":46,"type":"line","purpose":"LB","content":"fratres nostri quae acta sunt et quae difinita","motivation":"sc:painting","canvas":2085,"bounds":{"height":50,"width":627,"y":76,"x":40},"startPage":2085,"endPage":2085},…]
Request parameters: merge=true|false (default true)
Response body: none
Status: 204 on success, 404 if pageID does not exist.
Comments:
The JSON array in the request body should contain new values for the page's lines. If the merge parameter is false, the existing lines will be completely replaced; if it is true or omitted, only lines mentioned in the request body will be affected. For the purposes of this endpoint, a page's lines are considered to be all annotations whose "purpose" is "LB" and whose "startPage" is pageID.

5. Manifests

Each witness has exactly one corresponding manifest object, which is created automatically when the witness is created. A manifest will eventually contain some metadata, but its main purpose is to serve as a container to group together all the canvasses.

Get manifest details

Endpoint: /manifest/manID
Method: GET
Request body: none
Response body: {"id":3,"canvasses":[9,10,11,12]}
Status: 200 on success, 404 if manID does not exist.
Comments:
The "canvasses" field of the manifest object provides an array with the IDs of all canvasses associated with said manifest.

Add a manifest annotation

Endpoint: /manifest/manID/annotations
Method: POST
Request content-type: application/json
Request body: {"type":"colour","content":"turquoise","canvas":"canvas/1000#xywh=0,0,100,100"}
Response body: none
Response location: /annotation/annID
Status: 201 on success, 404 if manID does not exist.
Comments:
The request body should contain a single annotation object. The Location header of the response gives the caller the ID of the newly-created annotation.

Get manifest canvasses

Endpoint: /manifest/manID/canvasses
Method: GET
Request body: none
Response body: array of canvasses
Status: 200 on success, 404 if manID does not exist.
Comments:
The response body will be an array containing all the canvasses belonging to this manifest. The format will be the same as that returned by a GET request to /canvas/canvID.

Set manifest permissions

Endpoint: /manifest/manID/permissions
Method: PUT
Request content-type: application/json
Request body: [{"user":uID, "role":"OWNER"}]
Request parameters: merge=true|false (default true)
Response body: none
Status: 204 on success, 404 if manID does not exist, 409 if the request body refers to a nonexistent user ID.
Comments:
The request body should contains an array of user permissions objects. The "user" field of each object should contain a user ID, and the "role" field one of "NONE", "VIEWER", "CONTRIBUTOR", "EDITOR", or "OWNER", identifying the permissions that will be granted to that user for the given manifest. Specify "user":0 to set permissions for the "public sharing" user. If the merge parameter is false, the contents of the array will completely replace the manifest's existing permissions; if it is true or omitted, only permissions mentioned in the request body will be affected.

6. Canvasses

Get canvas details

Endpoint: /canvas/canvID
Method: GET
Request body: none
Response body: {"id":1001,"index":1,"title":"R3.jpg","width":1472,"height":1000,"images":[{"id":2,"index":0,"uri":"http://localhost:8080/T-PEN/imageResize?folioNum=12841944&height=1000&user=ericsmith@slu.edu","format":"JPEG","width":1472,"height":2000,"canvas":1001}],"manifest":1,"page":1001}
Status: 200 on success, 404 if canvID does not exist.
Comments:
The "index" field contains the canvas' index within the manifest as a whole. For convenience, the response body also contains the canvas' "images" array.

Set canvas details

Endpoint: /canvas/canvID
Method: PUT
Request body: {"id":5,"title":"Frontispiece"}
Response body: none
Status: 204 on success, 404 if canvID does not exist.
Comments:
The JSON object in the request body should contain all fields which are to be modified; fields which aren't being changed can be omitted. Changing the canvas' "index" property can be used to reorder canvasses within the manifest.

Add a canvas annotation

Endpoint: /canvas/canvID/annotations
Method: POST
Request content-type: application/json
Request body: {"type":"colour","content":"turquoise"}
Response body: none
Response location: /annotation/annID
Status: 201 on success, 404 if canvID does not exist.
Comments:
The request body should contain a single annotation object. The Location header of the response gives the caller the ID of the newly-created annotation.

Get canvas annotations

Endpoint: /canvas/canvID/annotations
Method: GET
Request body: none
Response body: [{"id":36748,"startOffset":0,"endOffset":58,"type":"line","purpose":"LB","content":"de adulterio accussant et non habent latentia peccata uin-","motivation":"sc:painting","canvas":2033,"bounds":{"height":66,"width":601,"y":64,"x":31},"startPage":2033,"endPage":2033},…]
Status: 200 on success, 404 if canvID does not exist.
Comments:
Response contains an array with all annotations found on the given canvas. Since lines are annotations, they will be included in the response.

Set canvas annotations

Endpoint: /canvas/canvID/annotations
Method: PUT
Request body: [{"id":38042,"startOffset":0,"endOffset":46,"type":"line","purpose":"LB","content":"fratres nostri quae acta sunt et quae difinita","motivation":"sc:painting","canvas":2085,"bounds":{"height":50,"width":627,"y":76,"x":40},"startPage":2085,"endPage":2085},…]
Request parameters: merge=true|false (default true)
Response body: none
Status: 204 on success, 404 if canvID does not exist.
Comments:
The JSON array in the request body should contain new values for the canvas' annotations. If the merge parameter is false, the existing annotations will be completely replaced; if it is true or omitted, only annotations mentioned in the request body will be affected.

Set canvas images

Endpoint: /canvas/canvID/images
Method: PUT
Request body: [{"id":2,"index":0,"uri":"http://localhost:8080/TPEN/imageResize?folioNum=12841944&height=1000&user=ericsmith@slu.edu","format":"JPEG","width":1472,"height":2000,"canvas":1001},…]
Request parameters: merge=true|false (default true)
Response body: none
Status: 204 on success, 404 if canvID does not exist.
Comments:
The JSON array in the request body should contain new values for the canvas' images. If the merge parameter is false, the existing images will be completely replaced; if it is true or omitted, only images mentioned in the request body will be affected.

Get canvas lines

Endpoint: /canvas/canvID/lines
Method: GET
Request body: none
Response body: [{"id":37484,"index":0,"annotation":38042,"endOffset":46,"content":"fratres nostri quae acta sunt et quae difinita","startOffset":0,"page":2085},…]
Status: 200 on success, 404 if canvID does not exist.
Comments:
Response contains an array with all lines found on the given canvas. A line is actually an annotation, but with a slightly different set of fields. The "annotation" field of the line object can be used to retrieve the full set of annotation fields.

Set canvas lines

Endpoint: /canvas/canvID/lines
Method: PUT
Request body: [{"id":38042,"startOffset":0,"endOffset":46,"type":"line","purpose":"LB","content":"fratres nostri quae acta sunt et quae difinita","motivation":"sc:painting","canvas":2085,"bounds":{"height":50,"width":627,"y":76,"x":40},"startPage":2085,"endPage":2085},…]
Request parameters: merge=true|false (default true)
Response body: none
Status: 204 on success, 404 if canvID does not exist.
Comments:
The JSON array in the request body should contain new values for the canvas' lines. If the merge parameter is false the existing lines will be completely replaced; if it is true or omitted, only lines mentioned in the request body will be affected. For the purposes of this endpoint, a canvas' lines are considered to be all annotations whose "purpose" is "line" and whose "canvas" is canvID.

7. Images

Get an image

Endpoint: /image/imgID
Method: GET
Request body: none
Response body: Image data (usually image/jpeg).
Status: 200 if image is from a known T-PEN repository, 302 if not.
Comments: Retrieves the given image. If the image's uri field corresponds to a known repository, the image data will be fetched using the T-PEN proxy mechanism. Otherwise, the request will be redirected to the location given in the uri field.

8. Outlines

Get outline details

Endpoint: /outline/outlID
Method: GET
Request body: none
Response body: an Outline
Status: 200 on success.

Set outline details

Endpoint: /outline/outlID
Method: PUT
Request body: an Outline
Response body: none
Status: 200 on success.

Delete an outline

Endpoint: /outline/outlID
Method: DELETE
Request body: none
Response body: none
Status: 204 on success.
Comments:
Deletes the single outline identified by outlID.

Approve outline decisions

Endpoint: /outline/outlID/approval
Method: PUT
Request content-type: application/json
Request body (optional): [annID₁, annID₂,…]
Response body: none
Status: 204 on success, 403 if the user does not have EDITOR permission on outlID, 404 if outlID does not exist.
Comments:
Sets the approvedBy field of the outline's decisions to the ID of the current user. If the request body contains an array of annotation IDs, only those annotations will be marked as approved. If the request body is absent, all the outline's decisions will be approved.


Draft 2015-03-26

Edition API Structures

Basic Types

ID

An integer serving as the primary key of a table.

Target URI

Within Tradamus, each entity can be uniquely identified by means of a URI-like string (e.g. "edition/2" or "annotation/1234").

In some cases, these URIs may include a fragment to further specify the target. Thus, "parallel/11#3" specifies to the portion of "parallel/11" which draws from "witness/3". For a Canvas-targetted annotation, the fragment can specify the portion of the Canvas which is targetted (e.g. "canvas/12#xywh=10,10,320,240" to target a rectangular area within "canvas/12").

Edition

{
   "id": ID,
   "title": string,
   "creator": User ID,
   "permissions": array of long-form Permissions,
   "witnesses": array of short-form Witnesses,
   "outlines": array of Outline IDs
}

Outline

Returned by /outline/outlID.

{
   "id": ID,
   "title": string,
   "index":int,
   "bounds": array of Annotations (null for full-Edition outline)
   "edition": Edition ID,
   "decisions": array of Decisions
}

Decision

{
   "id": ID,
   "content": string,
   "type": "tr-decision",
   "motes": array of Annotations having "type":"tr-mote"
}

Annotation

{
   "id": ID,
   "content": string,
   "type": string,
   "target": URI of Tradamus object (may include fragment),
   "startPage": Page ID,
   "startOffset": int,
   "endPage": Page ID,
   "endOffset": int,
   "canvas": URI of Canvas (may include fragment)
   "attributes": map containing key/value pairs,
   "tags": string,
   "modifiedBy": User ID,
   "approvedBy": User ID
}

Permission

Long-form

Includes name and email address of User associated so that an extra call is not necessary. Returned in Edition.permissions, Manifest.permissions, Transcription.permissions, and Publication.permissions.

{
   "id": ID,
   "role": "NONE"|"VIEWER"|"CONTRIBUTOR"|"EDITOR"|"OWNER",
   "user": User ID
   "name": User's full name,
   "mail": User's email address,
   "target": Edition, Manifest, or Transcription URI
}

Short-form

Used when PUTting to /edition/edID/permissions, /transcription/transcrID/permissions, /manifest/manID/permissions, or /publication/pubID/permissions.

{
   "role": "NONE"|"VIEWER"|"CONTRIBUTOR"|"EDITOR"|"OWNER",
   "user": User ID (0 to indicate the "public sharing" user).
   "target": Edition, Manifest, or Transcription URI
}

Witness

Short-form

Returned in Edition.witnesses.

{
   "id": ID,
   "title": string,
   "siglum" string
}


Draft 2015-06-22

Publication API

1. Publications

Publications are created by POSTing JSON data to the /publications endpoint. Information about a particular publication can be retrieved by a GET request to /publication/pubID.

Add new publication

Endpoint: /publications
Method: POST
Request body: { "title":"title", "edition":edID, "type":type }
Response location: /publication/pubID
Response body: none
Status: 201 on success, 409 if title already in use.
Comments:
The "type" field should be one of "PDF", "TEI", "DYNAMIC", "OAC", or "XML". The publication's "creator" field will be set to the user who made the POST. The "creation" and "modification" fields will be set to the current time.

List publications

Endpoint: /publications
Method: GET
Request body: none
Response body: [{"id":pubID₁, "title":"title₁"}, … ]
Request parameters: public=true (optional)
Comments:
The endpoint returns the IDs and titles of all publications for which the user has VIEWER permissions or better. If the public=true parameter is passed to the endpoint, it will instead list all publications for which the public user (i.e. user 0) has VIEWER permissions.

Get publication details

Endpoint: /publication/pubID
Method: GET
Request body: none
Response body: a Publication object
Status: 200 on success, 404 if pubID doesn't exist
Comments: The returned Publication object will include an array of Permission objects and an array of Section IDs.

Set publication details

Endpoint: /publication/pubID
Method: PUT
Request body: a Publication object
Response body: none
Status: 204 on success, 404 if pubID doesn't exist

Delete a publication

Endpoint: /publication/pubID
Method: DELETE
Request body: none
Status: 204 on success, 404 if pubID doesn't exist
Comments: Also deletes all associated Sections and their Rules.

Set publication permissions

Endpoint: /publication/pubID/permissions
Method: PUT
Request body: an array of Permission objects
Response body: none
Status: 204 on success, 404 if pubID doesn't exist

Set publication sections

Endpoint: /publication/pubID/sections
Method: PUT
Request body: an array of Section objects
Response body: none
Status: 204 on success, 404 if pubID doesn't exist

2. Sections

Add new section to a publication

Endpoint: /publication/pubID/sections
Method: POST
Request body: {
   "publication": pubID,
   "title": "title",
   "type": "TEXT"|"ENDNOTE"|"FOOTNOTE"|"INDEX"|"TABLE_OF_CONTENTS",
   "decoration": array of Rule objects
   "layout": array of Rule objects
   "outlines": array of Outline IDs
   "template": "HTML template"
}
Response location: /section/sectID
Response body: none
Status: 201 on success, 409 if title is already being used in this publication.

Set Section details

Endpoint: /section/sectID
Method: PUT
Request body: Section object
Status: 204 on success, 404 if sectID doesn't exist

Delete a Section

Endpoint: /section/sectID
Method: DELETE
Status: 204 on success, 404 if sectID doesn't exist
Comment: Also deletes all associated Rules.

3. Generating PDFs

Create a PDF

Endpoint: /pdfs
Method: POST
Request body: XHTML+CSS to be converted into a PDF
Response location: /pdf/pdfID
Response body: none
Status: 201 on success
Comment: Uses the supplied XHTML+CSS to generate a PDF document. The document will be stored in the database and can be retrieved using the location returned in the response headers.

Get a PDF

Endpoint: /pdf/pdfIDs
Method: GET
Response body: PDF data for the given document
Comment: Returns a previously-generated PDF document.


[[include T-PENProxyAPI (not found)]]


Endpoint Permissions

This document describes the access permissions which are required to use the various Tradamus endpoints. The endpoints themselves are more full described in Tradamus Server API.

There are five ranked levels of access: NONE, VIEWER, CONTRIBUTOR, EDITOR, and OWNER. If a user has a particular level of access to a resource, they also implicitly have all the lower levels of access.

level access
NONE None
VIEWER Read-only access.
CONTRIBUTOR Can add new annotations but these will be unvetted.
EDITOR Can add fully-vetted annotations. Can vet annotations for CONTRIBUTORs.
OWNER Can assign permissions.

These levels are relative to a given resource. A particular user could have OWNER access to one edition while having no access at all to other editions.

Permissions can currently be set at three different points: the edition, the transcription, and the manifest. When verifying permissions, they are checked at the edition level first; if the user has sufficient permissions to access the edition, permissions are then checked at the transcription or manifest level. Accordingly, transcription and manifestt permissions can only be used to make access more restrictive.

Also new is the notion of annotations being vetted or unvetted. When a user with CONTRIBUTOR access adds an annotation, it is only visible to themselves and to users with EDITOR access. Once an EDITOR has approved an annotation, it becomes visible to all users with VIEWER access.

1. Users

Add new user

Endpoint: /users
Method: POST
Access: No restrictions.

Invite new user

Endpoint: /users
Method: POST
Access: EDITOR on edition to which user is being invited.

Get user details

Endpoint: /user/userID
Method: GET
Access: No restrictions.

Get user details by email

Endpoint: /user?mail=emailAddress
Method: GET
Access: No restrictions.

Modify user details

Endpoint: /user/userID
Method: PUT
Access: Only userID can modify their own details.

Reset user password

Endpoint: /user?reset=emailAddress
Method: POST
Access: No restrictions.

2. Login

Log in to Tradamus

Endpoint: /login
Method: POST
Access: No restrictions.

Check login status

Endpoint: /login
Method: GET
Access: The call always returns the status of the current user.

3. Editions

Add new edition

Endpoint: /editions
Method: POST
Access: No restrictions. The current user will be granted OWNER access to the newly-created edition.

List editions

Endpoint: /editions
Method: GET
Access: The call will only return editions for which the current user has VIEWER permissions.

Get edition details

Endpoint: /edition/edID
Method: GET
Access: VIEWER on the edition.

Set edition details

Endpoint: /edition/edID
Method: PUT
Access: EDITOR on the edition.

Add an edition metadatum

Endpoint: /edition/edID/metadata
Method: POST
Access: CONTRIBUTOR on the edition.

Set edition metadata

Endpoint: /edition/edID/metadata
Method: PUT
Access: CONTRIBUTOR on the edition. If access level is just CONTRIBUTOR, the call will fail with a 403 if it attempts to modify any metadata which belong to another user.

Get edition decisions

Endpoint: /edition/edID/decisions
Method: GET
Access: VIEWER on the edition.

Set edition decisions

Endpoint: /edition/edID/decisions
Method: PUT
Access: CONTRIBUTOR on the edition. If access level is just CONTRIBUTOR, the call will fail with a 403 if it attempts to modify any decisions which belong to another user.

Set edition permissions

Endpoint: /edition/edID/permissions
Method: PUT
Access: OWNER on the edition.

Delete an edition

Endpoint: /edition/edID
Method: DELETE
Access: OWNER on the edition.

4. Witnesses

Create a new witness

Endpoint: /witnesses
Method: POST
Access: EDITOR on the edition.

Get witness details

Endpoint: /witness/witID
Method: GET
Access: VIEWER on the edition.

Set witness details

Endpoint: /witness/witID
Method: PUT
Access: EDITOR on the edition.

Add a witness metadatum

Endpoint: /witness/witID/metadata
Method: POST
Access: CONTRIBUTOR on the edition.

Set witness metadata

Endpoint: /witness/witID/metadata
Method: PUT
Access: CONTRIBUTOR on the edition. If access level is just CONTRIBUTOR, the call will fail with a 403 if it attempts to modify any metadata which belong to another user.

Delete a witness

Endpoint: /witness/witID
Method: DELETE
Access: EDITOR on the edition.

Recursively get all witness annotations

Endpoint: /witness/witID/annotations
Method: GET
Access: VIEWER on the edition. The results will be filtered if access is more restricted at the transcription or manifest levels.

5. Transcriptions

Get transcription details

Endpoint: /transcription/transcrID
Method: GET
Access: VIEWER on the transcription.

Set transcription permissions

Endpoint: /transcription/transcrID/permissions
Method: PUT
Access: OWNER on the transcription.

6. Pages

Get page details

Endpoint: /page/pageID
Method: GET
Access: VIEWER on the transcription.

Set page details

Endpoint: /page/pageID
Method: PUT
Access: EDITOR on the transcription.

Add a page annotation

Endpoint: /page/pgID/annotations
Method: POST
Access: CONTRIBUTOR on the transcription.

Get page annotations

Endpoint: /page/pgID/annotations
Method: GET
Access: VIEWER on the transcription.

Set page annotations

Endpoint: /page/pageID/annotations
Method: PUT
Access: CONTRIBUTOR on the transcription. If access level is just CONTRIBUTOR, the call will fail with a 403 if it attempts to modify any annotations which belong to another user.

Get page lines

Endpoint: /page/pgID/lines
Method: GET
Access: VIEWER on the transcription.

Set page lines

Endpoint: /page/pageID/lines
Method: PUT
Access: CONTRIBUTOR on the transcription. If access level is just CONTRIBUTOR, the call will fail with a 403 if it attempts to modify any lines which belong to another user.

7. Manifests

Get manifest details

Endpoint: /manifest/manID
Method: GET
Access: VIEWER on the manifest.

Set manifest permissions

Endpoint: /manifest/manID/permissions
Method: PUT
Access: OWNER on the manifest.

8. Canvasses

Get canvas details

Endpoint: /canvas/canvID
Method: GET
Access: VIEWER on the manifest.

Set canvas details

Endpoint: /canvas/canvID
Method: PUT
Access: EDITOR on the manifest.

Add a canvas annotation

Endpoint: /canvas/canvID/annotations
Method: POST
Access: CONTRIBUTOR on the manifest.

Get canvas annotations

Endpoint: /canvas/canvID/annotations
Method: GET
Access: VIEWER on the manifest.

Set canvas annotations

Endpoint: /canvas/canvID/annotations
Method: PUT
Access: CONTRIBUTOR on the manifest. If access level is just CONTRIBUTOR, the call will fail with a 403 if it attempts to modify any annotations which belong to another user.

Get canvas lines

Endpoint: /canvas/canvID/lines
Method: GET
Access: VIEWER on the manifest.

Set canvas lines

Endpoint: /canvas/canvID/lines
Method: PUT
Access: CONTRIBUTOR on the manifest. If access level is just CONTRIBUTOR, the call will fail with a 403 if it attempts to modify any lines which belong to another user.

9. Annotations

Get annotation details

Endpoint: /annotation/annID
Method: GET
Access: VIEWER on the transcription or the manifest. In particular, if an annotation is anchored to both the page and the canvas, it is sufficient to have VIEWER access on one of the transcription or the manifest.

Set annotation details

Endpoint: /annotation/annID
Method: PUT
Access: CONTRIBUTOR on the transcription or the manifest. If access level is just CONTRIBUTOR, the call will fail with a 403 if it attempts to modify an annotation which belongs to another user.

Delete an annotation

Endpoint: /annotation/annID
Method: DELETE
Access: CONTRIBUTOR on the transcription or the manifest. If the access level is just CONTRIBUTOR, the call can only delete an annotation belonging to the current user.

10. Collation

Full-edition collation

Endpoint: /collation/edID
Method: GET
Access: Only transcriptions with VIEWER access will be included in the collation.

Sub-collation

Endpoint: /collation
Method: GET
Access: Only transcriptions with VIEWER access will be included in the collation.

11. Config

Endpoint: /config
Method: GET
Access: No restrictions.

12. Activity Log

Endpoint: /activity
Method: GET
Access: To be determined.


Help Documents

These pages reflect the desired help/marketing documentation for Tradamus. The basic structure of a help document, insofar as it is relevant, is

  • Lead statement—concise
  • Basic explanation—short paragraph or passage with statement of common practice, technical gesturing, and Tradamus philosophical or functional anchors.
  • Aside—bullet list of common types, locations, referenced standards, etc.
  • Example (hidden)—a reveal-able example with real code structures or highly technical statements
  • Best practice—our own statement of how the most compliant user would use this within Tradamus with some justification
  • Related topics—linkable help topics that are related

Topics


JavaScript Guidelines

Files

A JavaScript file should start with a copyright header of this form (same as Java files):

/*

 * Copyright 2011-2014 Saint Louis University. Licensed under the
 * Educational Community License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may
 * obtain a copy of the License at
 *
 * http://www.osedu.org/licenses/ECL-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an "AS IS"
 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

While many JavaScript files may be needed during development, these should be consolidated and minified where appropriate. In single page applications, all local code should be delivered in one call, in plugin or diverse applications, a more modular approach may be reasonable.

Libraries

Libraries may fall into a variety of categories, but in every case a hosted version is preferred with a local backup if necessary. When possible, a minified version should be used.

External Libraries

When choosing an external library several conditions must be met:

  1. The file is tested and established: any developer putting the responsibility of functionality onto third-party code must be prepared to defend the need and maintainability of the choice
  2. Most of the library is needed: including an entire library for a minor piece of functionality puts too much of a burden on the end user and may affect maintainability if it is later dropped from the core development
  3. There are no licensing conflicts: while rarely a problem, some 'public' libraries are released with specific terms that will not allow the free incorporation into our projects

Internal Libraries

It is often the case that we will want to reuse important pieces of code. While it is important that developers design their code with the general case in mind it is imperative that the second developer to notice the reusable nature of the code and build out the library at that time. If time does not allow for the general case to be retroactively implemented right away, the work should be scheduled.

As library use continues, provisions should be made for generic hosting of these shared libraries.

Snippets

Any time a snippet or piece of another's code is included in CDH code, it must be cited clearly and used with permission

When an entire library is not needed or a piece of existing code needs to be re-purposed without being extracted to a separate file, a well-cited snippet may be appropriate. The beginning and end of this inclusion is important, since the snippet should be regarded as read-only with configuration and over-riding changes made outside of the borrowed code.

Preferred Libraries

Some JavaScript libraries have already been used and proven in CDH projects. Whenever possible, the most up-to-date version of the library should be used at the time of release.

  • jQuery (jquery.com) - Popular and widely used library which focuses on imperative development, especially in DOM selection and manipulation. jQuery excels in cross-browser support for common functions and graphic manipulation. AJAX support with callbacks built in for success, failure, and completion.
  • jQueryUI - extends jQuery to include a lot of popular interactions and widgets. This library allows for a host of themes as well which, while not ideal in a custom project, may assist in horizontal or throwaway prototyping.
  • AngularJS (https://angularjs.org) - Honest MVC structure out of Google focuses on declarative development and separates data manipulation from display well. Allows for the easy development of reusable directives or custom elements and attributes and very compact, readable HTML code.
  • AngularUI (http://angular-ui.github.io/) - extends AngularJS with community submitted interactions and custom directives and modules. Care should be taken that anything used is properly vetted as this collection is community moderated.

General Syntax and Conventions

https://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml
Use the Google style guide as a foul pole for most work. As we develop exceptions to these rules, we can include them here.

Variables

In every case, attaching a variable to the global scope is irresponsible. Creating a global namespace object to pile variables under is often evidence of poor structure, but still preferable to true globals.

Variable names are camel-case, starting with a lower-case letter.

Where part of a name is an abbreviation, it is all upper-case.
e.g. editionID, not editionId; getURL, not getUrl

Member variables get spelled out in full.
e.g. currentEdition, not curEdition

Local variables and parameters can (and should) use shorter names.
e.g. edID for a local variable holding an edition ID

Constants & Enums

Use of static final variables as constants is encouraged.

Constant names and enum values are all upper-case, with components separated by underscores.
e.g. CONFIRMATION_PENDING

Comments

Yes. JSDoc comments in particular.

During project development, there may be the need for bookmark comments. These should be limited to those that NetBeans can create action items from such as TODO and FIXME. Process comments may be used to erect a skeleton for pending code, but obvious comments (e.g., "Increment and repeat") should be removed before public release.

Keep in mind that some of these comments will be visited in versioning or accidentally released in the final code, so while everything may not be professional, it should at least be kept unoffensive and impersonal.

Logging and Messages

For debugging, it may be helpful at times to put in lines for console.log(), but there is rarely a time when these lines should survive the final code cleanup. For advanced user information, throwing an error may be a more accurate action.

If a message is frequently needed for the user in a modal or onscreen, consider generalizing the messaging and avoid the use of alert()s, prompt()s, and confirm()s in the final product.


Publication Printing Conventions

Section Types

Each section (as defined in the Publication) must be classified as one of the following:

  1. TEXT
    • This becomes the text body of the Edition, which is the content of the serialized decision annotations resulting from the collation process.
    • Sections with only one witness or material are rendered as transcribed, so may be text blocks like introductions, example transcriptions, inline commentary notes, or other injected editorial content.
  2. ENDNOTE
    • Annotations contained within this section are revealed through an apparatus which follows the body text.
    • These sections may be placed in any order and are not necessarily singular and at the end of the Edition.
    • Annotations may be filtered by type or tag, so that different sections may be stacked for different purposes (for example, variants and sources)
    • References to annotations in the TEXT sections will be indicated by a numeric sequencer with an optional prefix or suffix string.
    • Sorting only by occurrence.
    • Generic notes are simply a numeric reference and the content of the annotation.
  3. INDEX
    • Annotations presented in a list, without reference to the text, sorted alphanumerically or by occurrence in the outlines included.
  4. TABLE_OF_CONTENTS
    • A list of labels of all the sections, in order, linked as appropriate
  5. COLLATION_TABLE
    • A simple visualization of collation decisions, with notes
    • Horizontal headers are the sigla of all included witnesses
    • Vertical rows are the motes where there is either annotation or disagreement
    • Cells contain a character of agreement(✓), a character of omission(-), or the variant text
TEXT A B C NOTES
motus motus et
Zeno zeno I don't care about capitalization myself, but I thought I'd record it here.
enim -

Customizations

Different types of sections will allow specific configurations. All sections have source outlines, an index, and a label.

  1. TEXT
    • style and layout applied based on annotations type or tag
  2. ENDNOTE
    • Filter to hide/show based on annotations type or tag
    • Special treatment for variants (tr-decision type annotations)
      • '#. anno.content] commentingAnno.content action. mote.content mote.sigla, action. mote.content mote.sigla
      • Like: 34. motus] add. motus et B
      • commentingAnno.content is only exactly as entered
      • Actions are add., om., inv. or omitted
      • Multiple motesets are comma-delimited "action. content sigla" units
    • Add a prefix or suffix to the default numeric sequential reference
  3. INDEX
    • Filter to hide/show based on annotations type or tag
    • Sort alphanumerically or by occurrence
  4. TABLE_OF_CONTENTS
    • Not available for print

But on the Website

These sections will render differently than the restrictions of print allow.

  • TEXT is the body text and will be central to the Edition display
  • ENDNOTE will render as marginal apparatus and appear whenever the section being viewed contains references contained within them
  • INDEX are references that are hidden until requested, but become available as popover views
  • TABLE_OF_CONTENTS non-optional navigation always available to move between sections
  • Changing Base-text and finding specific annotations also always available (in our default template)

Permissions and Roles

  1. Review Edition - Only see final changes. Browse into sources. Hidden from all non-editorial comments, unvetted changes, or prepublished edits.
  2. Proof - Only suggest changes to existing annotations. All updates enter as unvetted.
  3. Read Work In Progress - Also view unpublished areas with ongoing edits. Preview notes and comments.
  4. Contribute - Create suggestions, comments, additions, but no direct changes. Updates all enter as unvetted.
  5. Participate - Add, delete, or update without review on all work within an Edition.
  6. Edit - Vet changes and corrections. Update metadata, membership, permissions. Add, update, remove whole Witnesses, Transcriptions.
  7. Own - Delete/Suspend Edition. Update sharing. Agree to IPR etc. releases.
  8. Creator - Possibly a permanent, hidden credit for historical record. Same as Owner unless abdicated.

Tradamus Coding Guidelines

Java Guidelines

Files

A Java file should start with a copyright header of this form:

/*

 * Copyright 2011-2014 Saint Louis University. Licensed under the
 *    Educational Community License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may
 * obtain a copy of the License at
 *
 * http://www.osedu.org/licenses/ECL-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an "AS IS"
 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

The copyright notice is followed by the package declaration. This is followed by the import statements, which are followed by the class declaration.

Packages

All code goes into sub-packages of edu.slu.tradamus. Multiple levels of packaging beyond the first are discouraged.

Imports appear after the copyright notice. Java JDK imports appear first, followed by imports from third-party libraries, followed by imports from other Tradamus packages. Within each group, imports are ordered alphabetically.

Classes

Class names are camel-case, starting with a capital letter.

The class declaration should be preceded by a JavaDoc comment describing the class, along with an @author annotation.

Within the class declaration the following is the recommended order:

  1. private variables

  2. constructors

  3. methods which operate on the object as a whole, ordered alphabetically

  4. methods which operate on another entity, ordered alphabetically by entity
    e.g. deleteChildren() and loadChildren() appear before getEdition()

  5. static variables, including static final constants

  6. nested classes

Methods

Method names are camel-case, starting with a lower-case letter.

The first component of a method name should be a verb. If the method primarily acts on the object itself, that is sufficient. If the method acts on another entity or on a portion of the object, that should be indicated as part of the method name.
e.g. load() loads this object, but loadChildren() loads this object's children

Variables

Variable names are camel-case, starting with a lower-case letter.

Where part of a name is an abbreviation, it is all upper-case.
e.g. editionID, not editionId; getURL, not getUrl

Member variables get spelled out in full.
e.g. currentEdition, not curEdition

Local variables and parameters can (and should) use shorter names.
e.g. edID for a local variable holding an edition ID

Constants & Enums

Use of static final variables as constants is encouraged.

Constant names and enum values are all upper-case, with components separated by underscores.
e.g. CONFIRMATION_PENDING

Exceptions

Avoid empty catch blocks. If you have an exception which will never be thrown, an empty catch block is allowed, but the exception should be called "ignored" to indicate that you know what you're doing.
e.g.

:::java
   } catch (JsonProcessingException ignored) {
      // Just writing a Map out as a JSON string.
   }

In general, exceptions should be caught at a level where they can meaningfully be reported to the end-user. In Tradamus, they are typically caught in the servlet's doGet() or doPost() method, where HttpServletResponse.sendError() can be called with an appropriate message.

Comments

Yes. JavaDoc comments in particular.

Logging

Use of System.out is to be avoided.

Tradamus uses java.lang.Logging. Where a class needs a logger, it should be declared as follows:
private static final Logger LOG = Logger.getLogger(MyClass.class.getName());

SQL Guidelines

Tables

Table name is the plural form of the entity being stored, in lower case.
e.g. projects, not project

If the table name consists of multiple words, they should be separated by underscores.
e.g. group_members

Keys

Tables generally have an auto-increment primary key called id of type int(11).

Foreign keys are generally linked using the id field of the foreign table, and have the name of the linked entity.
e.g. in the witnesses table, the edition to which the witness belongs is stored in the edition column

Where possible, use constraints to manage foreign key relationships.
e.g. canvasses are linked to pages as follows:
CONSTRAINT `canvas_page` FOREIGN KEY (`page`) REFERENCES `pages` (`id`) ON DELETE SET NULL

Child entities should take advantage of the ON DELETE CASCADE feature to make it easier to clean up.
e.g. each image is the child of a canvas, so the images table has this constraint:
CONSTRAINT `image_canvas` FOREIGN KEY (`canvas`) REFERENCES `canvasses` (`id`) ON DELETE CASCADE

Columns

Column names are in lower case, separated by underscores.
e.g. target_type

Where appropriate, use of enums is encouraged.

Web-app Guidelines

The general approach is resource-based. Each endpoint corresponds to a resource which is being manipulated:

GET /entity/entID retrieves the given entity
POST /entities creates a new entity
POST /entity/entID/children creates a new child
PUT /entity/entID updates the given entity, or creates it if it doesn't already exist
DELETE /entity/entID deletes an entity



Related

Wiki: Home
Wiki: TradamusCodingGuidelines
Wiki: ignore help index

MongoDB Logo MongoDB