Draft 2015-06-05
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.
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.
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.
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.
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.
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.
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
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. |
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.
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
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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 |
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
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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 titlesiglum string for siglumEndpoint: /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:
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
Endpoint: /outline/outlID
Method: GET
Request body: none
Response body: an Outline
Status: 200 on success.
Endpoint: /outline/outlID
Method: PUT
Request body: an Outline
Response body: none
Status: 200 on success.
Endpoint: /outline/outlID
Method: DELETE
Request body: none
Response body: none
Status: 204 on success.
Comments:
Deletes the single outline identified by outlID.
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
An integer serving as the primary key of a table.
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").
{
"id": ID,
"title": string,
"creator": User ID,
"permissions": array of long-form Permissions,
"witnesses": array of short-form Witnesses,
"outlines": array of Outline IDs
}
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
}
{
"id": ID,
"content": string,
"type": "tr-decision",
"motes": array of Annotations having "type":"tr-mote"
}
{
"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
}
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
}
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
}
Returned in Edition.witnesses.
{
"id": ID,
"title": string,
"siglum" string
}
Draft 2015-06-22
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.
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.
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.
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.
Endpoint: /publication/pubID
Method: PUT
Request body: a Publication object
Response body: none
Status: 204 on success, 404 if pubID doesn't exist
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.
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
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
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.
Endpoint: /section/sectID
Method: PUT
Request body: Section object
Status: 204 on success, 404 if sectID doesn't exist
Endpoint: /section/sectID
Method: DELETE
Status: 204 on success, 404 if sectID doesn't exist
Comment: Also deletes all associated Rules.
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.
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)]]
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.
Endpoint: /users
Method: POST
Access: No restrictions.
Endpoint: /users
Method: POST
Access: EDITOR on edition to which user is being invited.
Endpoint: /user/userID
Method: GET
Access: No restrictions.
Endpoint: /user?mail=emailAddress
Method: GET
Access: No restrictions.
Endpoint: /user/userID
Method: PUT
Access: Only userID can modify their own details.
Endpoint: /user?reset=emailAddress
Method: POST
Access: No restrictions.
Endpoint: /login
Method: POST
Access: No restrictions.
Endpoint: /login
Method: GET
Access: The call always returns the status of the current user.
Endpoint: /editions
Method: POST
Access: No restrictions. The current user will be granted OWNER access to the newly-created edition.
Endpoint: /editions
Method: GET
Access: The call will only return editions for which the current user has VIEWER permissions.
Endpoint: /edition/edID
Method: GET
Access: VIEWER on the edition.
Endpoint: /edition/edID
Method: PUT
Access: EDITOR on the edition.
Endpoint: /edition/edID/metadata
Method: POST
Access: CONTRIBUTOR on the edition.
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.
Endpoint: /edition/edID/decisions
Method: GET
Access: VIEWER on the edition.
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.
Endpoint: /edition/edID/permissions
Method: PUT
Access: OWNER on the edition.
Endpoint: /edition/edID
Method: DELETE
Access: OWNER on the edition.
Endpoint: /witnesses
Method: POST
Access: EDITOR on the edition.
Endpoint: /witness/witID
Method: GET
Access: VIEWER on the edition.
Endpoint: /witness/witID
Method: PUT
Access: EDITOR on the edition.
Endpoint: /witness/witID/metadata
Method: POST
Access: CONTRIBUTOR on the edition.
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.
Endpoint: /witness/witID
Method: DELETE
Access: EDITOR on the edition.
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.
Endpoint: /transcription/transcrID
Method: GET
Access: VIEWER on the transcription.
Endpoint: /transcription/transcrID/permissions
Method: PUT
Access: OWNER on the transcription.
Endpoint: /page/pageID
Method: GET
Access: VIEWER on the transcription.
Endpoint: /page/pageID
Method: PUT
Access: EDITOR on the transcription.
Endpoint: /page/pgID/annotations
Method: POST
Access: CONTRIBUTOR on the transcription.
Endpoint: /page/pgID/annotations
Method: GET
Access: VIEWER on the transcription.
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.
Endpoint: /page/pgID/lines
Method: GET
Access: VIEWER on the transcription.
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.
Endpoint: /manifest/manID
Method: GET
Access: VIEWER on the manifest.
Endpoint: /manifest/manID/permissions
Method: PUT
Access: OWNER on the manifest.
Endpoint: /canvas/canvID
Method: GET
Access: VIEWER on the manifest.
Endpoint: /canvas/canvID
Method: PUT
Access: EDITOR on the manifest.
Endpoint: /canvas/canvID/annotations
Method: POST
Access: CONTRIBUTOR on the manifest.
Endpoint: /canvas/canvID/annotations
Method: GET
Access: VIEWER on the manifest.
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.
Endpoint: /canvas/canvID/lines
Method: GET
Access: VIEWER on the manifest.
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.
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.
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.
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.
Endpoint: /collation/edID
Method: GET
Access: Only transcriptions with VIEWER access will be included in the collation.
Endpoint: /collation
Method: GET
Access: Only transcriptions with VIEWER access will be included in the collation.
Endpoint: /config
Method: GET
Access: No restrictions.
Endpoint: /activity
Method: GET
Access: To be determined.
These pages reflect the desired help/marketing documentation for Tradamus. The basic structure of a help document, insofar as it is relevant, is
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 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.
When choosing an external library several conditions must be met:
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.
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.
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.
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.
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
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
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.
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.
Each section (as defined in the Publication) must be classified as one of the following:
| 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 | ✓ | - | ✓ |
Different types of sections will allow specific configurations. All sections have source outlines, an index, and a label.
tr-decision type annotations)These sections will render differently than the restrictions of print allow.
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.
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.
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:
private variables
constructors
methods which operate on the object as a whole, ordered alphabetically
methods which operate on another entity, ordered alphabetically by entity
e.g. deleteChildren() and loadChildren() appear before getEdition()
static variables, including static final constants
nested classes
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
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
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
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.
Yes. JavaDoc comments in particular.
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());
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
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
Column names are in lower case, separated by underscores.
e.g. target_type
Where appropriate, use of enums is encouraged.
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
Wiki: Home
Wiki: TradamusCodingGuidelines
Wiki: ignore help index