Legacy BodyTrack server APIs
Table of Contents
WARNING
Overview
The following are server APIs from BodyTrack which can be used to implement a continuous time view in Fluxtream. These are currently proxied by handlers in BodyTrackController.java to a local BodyTrack server running on port 3000.
The URLs are relative to the root of the BodyTrack server, and within a top-level /bodytrack hierarchy on the Fluxtream server. For instance, if you want to get the views for user 3, the local BodyTrack server URL is http://localhost:3000/users/3/views, and the local Fluxtream URL would be http://localhost:8080/bodytrack/users/3/views.
If you are running a BodyTrack instance locally under mongrel (the single-threaded Ruby on Rails test server) on port 3000 this should just work. If you want to use a remote BodyTrack server and have a login on that server, you can forward the port with the following command:
ssh -L3000:localhost:3000 <username>@<bodytrack server>
Note: The following is a partial mirror of the original BodyTrack Web API 1.0 document which is on the private BodyTrack project wiki. For more details or access, please contact Anne Wright.
Login and session management
Log in to server and create a session
/login.json
Log into BodyTrack with the specified login name and password. Both POST params are required:
- login The login name of the user, as they would normally enter it when logging in at the BodyTrack site
- password The user's clear text password
Example:
curl --cookie-jar btsession http://localhost:3000/login.json -d login=frog -d password=frog
On success, returns:
{"name":"Frog Jones","user_id":3,"login":"frog"}
On failure, returns:
{"fail":"Invalid login parameters"}
Note:
Name is used only for display, not login, and would typically be the user's first and last name, or whatever they chose to enter.
Check session login status
/login_status.json
Example:
curl -b btsession http://localhost:3000/login_status.json
If user is logged in, returns:
{"name":"Frog Jones","user_id":3,"login":"frog"}
If user is not logged in, returns:
{"fail":"No user currently logged in"}
Logout
/logout.json
Example:
curl -b btsession http://localhost:3000/logout.json
Returns:
{"success":"User not logged in"}
Data access
Fetch tile
/tiles/UID/DeviceNickname.ChannelName/Level.Offset.json
Data aggregation bin size: 2levelTime duration of data tile: 512(2level)E.g:Tiles at level 0 are 512 seconds long and aggregate data in bins of 1 secondTiles at level 1 are 1024 seconds long and aggregate data in bins of 2 secondsNote that negative levels are valid; the system is designed to work with double-precision floating point timestamps, with effective resolution of 1 ns for contemporary timesTiles at level -1 are 256 seconds long and aggregate data in bins of 0.5 seconds
start time = offset(512(2level))E.g.:
level=0 offset=0 starts at Jan 1, 1970 00:00:00 UTClevel=0 offset=1 starts at Jan 1, 1970 00:08:20 UTCNotes:level=0 offset=-1 starts at Dec 31, 1969 23:51:40 UTC
- Negative offsets are valid and represent times before Jan 1, 1970- A 64-bit signed integer is sufficient for storing offset, while a 32-bit integer is not.
Photo Tiles
/photos/UID/DeviceNickname.ChannelName/Level.Offset.json
Returns:
[{"nsfw":false,"id":12,"begin_d":1340960972,"begin":"2012-06-29T05:09:32.000-04:00","dev_id":"picasa","dev_nickname":"Picasa","channel_name":"photo","url":"https://lh4.googleusercontent.com/-ERAmKTI3Wes/UDZB_kNvb7I/AAAAAAAAAKI/X3eD3YuQ5_Q/IMG_1845.JPG","tags":[],"thumbnails":[{"url":"https://lh4.googleusercontent.com/-ERAmKTI3Wes/UDZB_kNvb7I/AAAAAAAAAKI/X3eD3YuQ5_Q/s72/IMG_1845.JPG","width":72,"height":54},{"url":"https://lh4.googleusercontent.com/-ERAmKTI3Wes/UDZB_kNvb7I/AAAAAAAAAKI/X3eD3YuQ5_Q/s144/IMG_1845.JPG","width":144,"height":108},{"url":"https://lh4.googleusercontent.com/-ERAmKTI3Wes/UDZB_kNvb7I/AAAAAAAAAKI/X3eD3YuQ5_Q/s288/IMG_1845.JPG","width":288,"height":216}],"count":2},{"nsfw":false,"id":7,"begin_d":1340961674,"begin":"2012-06-29T05:21:14.000-04:00","dev_id":"picasa","dev_nickname":"Picasa","channel_name":"photo","url":"https://lh3.googleusercontent.com/-zpYMZPVA2Z0/UDZB0Zl3AFI/AAAAAAAAAJU/Ut4CmFAxSd0/IMG_1856.JPG","tags":[],"thumbnails":[{"url":"https://lh3.googleusercontent.com/-zpYMZPVA2Z0/UDZB0Zl3AFI/AAAAAAAAAJU/Ut4CmFAxSd0/s72/IMG_1856.JPG","width":54,"height":72},{"url":"https://lh3.googleusercontent.com/-zpYMZPVA2Z0/UDZB0Zl3AFI/AAAAAAAAAJU/Ut4CmFAxSd0/s144/IMG_1856.JPG","width":108,"height":144},{"url":"https://lh3.googleusercontent.com/-zpYMZPVA2Z0/UDZB0Zl3AFI/AAAAAAAAAJU/Ut4CmFAxSd0/s288/IMG_1856.JPG","width":216,"height":288}],"count":1},{"nsfw":false,"id":5,"begin_d":1340963181,"begin":"2012-06-29T05:46:21.000-04:00","dev_id":"picasa","dev_nickname":"Picasa","channel_name":"photo","url":"https://lh5.googleusercontent.com/-2V6WBDfbB7Y/UDZB0kLEQeI/AAAAAAAAAJc/J021laIZ4x0/IMG_1858.JPG","tags":[],"thumbnails":[{"url":"https://lh5.googleusercontent.com/-2V6WBDfbB7Y/UDZB0kLEQeI/AAAAAAAAAJc/J021laIZ4x0/s72/IMG_1858.JPG","width":54,"height":72},{"url":"https://lh5.googleusercontent.com/-2V6WBDfbB7Y/UDZB0kLEQeI/AAAAAAAAAJc/J021laIZ4x0/s144/IMG_1858.JPG","width":108,"height":144},{"url":"https://lh5.googleusercontent.com/-2V6WBDfbB7Y/UDZB0kLEQeI/AAAAAAAAAJc/J021laIZ4x0/s288/IMG_1858.JPG","width":216,"height":288}],"count":1}]
/photos/UID/Level.Offset.json
- dev_nickname=<name> Limit the photos returned to only be the ones from the specified data source name. Otherwise returns photos from any data source.
- tags = <String> Used for filtering requested photos by tags. This is a comma-separated list of tags.
- tag-match = <String> Used for specifying the tag matching strategy. Supported values are "any", "all", "none", and "untagged". Function of the values is as follows:
- any - returns photos having at least one of the tags specified in the tags parameter
- all - returns photos having all of the tags specified in the tags parameter
- none - returns photos having none of the tags specified in the tags parameter
- untagged - returns photos which have no tags
- nsfw If present and not zero, this specifies that NSFW photos should be included in the response as well. Otherwise, NSFW photos are not included in the response JSON.
- min_interval=secs Minimum time interval in floating point seconds between returned items. If not specified the effectivemin_interval defaults to 1/20th of the tile width.
Returns:
[{"nsfw":false,"datafile_id":null,"comment":"","begin":"2009-06-17T19:07:53-04:00","photo_file_size":2222524,"created_at":"2010-10-11T12:22:07-04:00","updated_at":"2010-11-20T08:16:59-05:00","photo_file_name":"DSCN3801.JPG","import_id":null,"photo_content_type":"image/jpeg","end_d":1245280073.0,"dev_nickname":null,"datahash":null,"tags":[],"id":1571,"end":"2009-06-17T19:07:53-04:00","dev_id":null,"dat_fields":null,"begin_d":1245280073.0,"count":2,"type":"Logphoto","user_id":1,"photo_updated_at":"2010-10-11T16:22:03-04:00"}]
/photos/UID/DeviceNickname.ChannelName/UnixTimeInSecs/Count
- isBefore = <boolean> Specifies whether to fetch photos before or after the given time
- tags = <String> Used for filtering requested photos by tags. This is a comma-separated list of tags.
- tag-match = <String> Used for specifying the tag matching strategy. Supported values are "any", "all", "none", and "untagged". Function of the values is as follows:
- any - returns photos having at least one of the tags specified in the tags parameter
- all - returns photos having all of the tags specified in the tags parameter
- none - returns photos having none of the tags specified in the tags parameter
- untagged - returns photos which have no tags
[{"nsfw":false,"id":57,"description":"Bridge","comment":"Roberto Clemente bridge","begin_d":1347194160,"begin":"2012-09-09T08:36:00.000-04:00","end_d":1347194160,"end":"2012-09-09T08:36:00.000-04:00","dev_id":"flickr","dev_nickname":"Flickr","object_type_name":"photo","channel_name":"photo","url":"http://farm9.static.flickr.com/8462/7981218440_6770ea380e_z.jpg","tags":[],"thumbnails":[],"count":1}]
Fluxtream Capture Photos
/photo/PhotoStoreId
Returns: A photo if the photo store ID references an image belonging to the current user (or one of the user's coachees). Otherwise, JSON is returned with an appropriate message body and HTTP Status Code. Example failure cases:
HTTP 403 Forbidden{"result":"KO","message":"User [1] is not authorized to view photo [3.FluxtreamCapture.photo.2012347.1355321332000_1ac240d22be5b76400d1ee8b75b2441566782017002665044f3af781143b7c61]"}
HTTP 404 Not Found{"result":"KO","message":"Photo [bogus] requested by user [1] not found"}
HTTP 500 Internal Server Error{"result":"KO","message":"Exception while trying to get photo [1.FluxtreamCapture.photo.2012347.1355321332000_1ac240d22be5b76400d1ee8b75b2441566782017002665044f3af781143b7c61]"}
/photoThumbnail/UID/PhotoId/ThumbnailIndex
Returns: A photo thumbnail if the photo ID references an image belonging to the current user (or one of the user's coachees). Otherwise, JSON is returned with an appropriate message body and HTTP Status Code. Example failure cases:
HTTP 403 Forbidden{"result":"KO","message":"User [1] is not authorized to view photo [3/260/1]"}
HTTP 404 Not Found{"result":"KO","message":"Photo [bogus] requested by user [1] not found"}
HTTP 500 Internal Server Error{"result":"KO","message":"Exception while trying to get photo [3/260/1]"}
Views
/users/UID/views
Returns a JSON map containing all the views for a given user. The top level map has a single key called "views" whose value is an array of view maps.
Each view map contains the following fields:
- name String specifying the name of the view
- last_used Date/time of the most recent time that that view was used
Example:
http://localhost:3000/users/3/views
{"views":[{"name":"zeo-armband1","last_used":"2012-03-22T11:41:13-04:00"},{"name":"bill-zeo","last_used":"2012-03-20T06:17:55-04:00"}]}
/users/UID/views/get?name=view_name
Get a JSON map reflecting the state of the requested view
Example:
http://localhost:3000/users/3/views/get?name=zeo-armband1
{"name":"zeo-armband1","v2":{"x_axis":{"min":1330502665.3873513,"max":1332509318.7292342},"y_axes":[{"device_name":"Zeo","channel_name":"Sleep_Graph","min":-0.4,"max":4.4,"style":{"styles":[{"type":"zeo","show":true},{"type":"value","show":false,"fillColor":"rgb(255, 0, 0)","marginWidth":5,"verticalOffset":7,"numberFormat":"###,##0.0##"}],"highlight":{"styles":[{"type":"value","show":false,"fillColor":"rgb(255, 0, 0)","marginWidth":5,"verticalOffset":7,"numberFormat":"###,##0.0##"}],"lineWidth":1},"comments":{"show":true,"styles":[{"type":"point","show":true,"lineWidth":1,"radius":3,"color":"rgb(255, 0, 0)","fill":true,"fillColor":"rgb(255, 0, 0)"}],"verticalMargin":4}},"channel_height":67},{"device_name":"Armband","channel_name":"mets","min":-6.309992592693319,"max":18.023606795840728,"style":{"comments":{"show":true,"styles":[{"type":"point","show":true,"lineWidth":1,"radius":3,"color":"rgb(0, 153, 255)","fill":true,"fillColor":"rgb(0, 153, 255)"}],"verticalMargin":4},"styles":[{"type":"line","show":true,"color":"rgb(0, 153, 255)","lineWidth":1},{"type":"lollipop","show":false,"lineWidth":1,"radius":0,"color":"rgb(0, 153, 255)","fill":false},{"type":"point","show":false,"lineWidth":1,"radius":2,"color":"rgb(0, 153, 255)","fill":true,"fillColor":"rgb(0, 153, 255)"},{"type":"value","show":false,"fillColor":"rgb(0, 153, 255)","marginWidth":5,"verticalOffset":7,"numberFormat":"###,##0.0##"}],"highlight":{"styles":[{"type":"value","show":false,"fillColor":"rgb(0, 153, 255)","marginWidth":5,"verticalOffset":7,"numberFormat":"###,##0.0##"}],"lineWidth":2}},"min_time":1292907660,"max_time":1321992960,"channel_height":67},{"device_name":"Armband","channel_name":"lying","min":-0.7389829126760572,"max":1.3868902873239444,"style":{"comments":{"show":true,"styles":[{"type":"point","show":true,"lineWidth":1,"radius":3,"color":"rgb(255, 0, 255)","fill":true,"fillColor":"rgb(255, 0, 255)"}],"verticalMargin":4},"styles":[{"type":"line","show":true,"color":"rgb(255, 0, 255)","lineWidth":1},{"type":"lollipop","show":false,"lineWidth":1,"radius":0,"color":"rgb(255, 0, 255)","fill":false},{"type":"point","show":false,"lineWidth":1,"radius":2,"color":"rgb(255, 0, 255)","fill":true,"fillColor":"rgb(255, 0, 255)"},{"type":"value","show":false,"fillColor":"rgb(255, 0, 255)","marginWidth":5,"verticalOffset":7,"numberFormat":"###,##0.0##"}],"highlight":{"styles":[{"type":"value","show":false,"fillColor":"rgb(255, 0, 255)","marginWidth":5,"verticalOffset":7,"numberFormat":"###,##0.0##"}],"lineWidth":2}},"min_time":1292864400,"max_time":1321992960,"channel_height":67}],"show_add_pane":true}}
/users/UID/views/set
Post with the following required fields to set the state of a given view:
- name The name of the view to set. If name matches an existing view the server updates that view to store the JSON supplied in the data field. Otherwise the server created a new view for name containing the JSON supplied in the data field.
- data A block of JSON data to store for this view.
See views get example above for sample values of the name and data parameters (data JSON should be like the return value from get).
Data Sources
/users/UID/sources
Returns a JSON encoded hash containing a key for each data source
Example: http://localhost:3000/users/3/sources
{
"sources":[
{
"grapherUrl":"/#timeline/source/Armband",
"name":"Armband",
"id":2,
"lastSync":"Mar 22, 2012 12:46 EDT",
"type":"body_media",
"latestData":"Mar 21, 2012 08:41 EDT",
"channels":[
"mets",
"lying"
]
},
...
]
}
/users/UID/sources/list
Returns a JSON encoded hash of the data sources, channels, styles, and range data for a given user.
Example: http://localhost:3000/users/3/sources/list
{"sources":[
{
"name":"All",
"type":"push",
"channels":[
{
"name":"comments",
"builtin_default_style":{},
"type":"comments",
"style":{}
},
{
"name":"photos",
"builtin_default_style":{},
"max":0.995803209351,
"type":"photos",
"min":0.634126389122,
"style":{}
}
]
},
{
"name":"Armband",
"channels":[
{
"name":"activityLevel",
"builtin_default_style":{
"comments":{
"show":true
},
"styles":[{
"type":"line",
"lineWidth":1
}]
},
"max":3,
"min_time":1292907660,
"min":1,
"style":{
"comments":{
"show":true
},
"styles":[
{
"type":"line",
"lineWidth":1
}
]
},
"max_time":1332333660
},
]
},
]
}
/users/UID/sources/default_graph_specs?name=source_name
Returns a JSON encoded hash of the data sources, channels, styles, and range data for a given source for a given user. Requiresname parameter to specify which source to return data for.
Example: http://localhost:3000/users/3/sources/default_graph_specs&name=Armband
Logrec Metadata
/users/UID/logrecs/LOGREC_ID/get
{"nsfw":false,"datafile_id":null,"comment":"","begin":"2011-01-23T11:32:43-08:00","photo_file_size":797510,"created_at":"2011-03-22T09:28:38-07:00","updated_at":"2011-03-22T09:28:38-07:00","photo_file_name":"IMG_20110123_143243.jpg","import_id":null,"photo_content_type":"image/jpeg","end_d":1295811163.0,"dev_nickname":null,"datahash":null,"tags":["a","b","c"],"id":38562,"end":"2011-01-23T11:32:43-08:00","dev_id":null,"dat_fields":null,"begin_d":1295811163.0,"type":"Logphoto","user_id":1,"photo_updated_at":"2011-03-22T13:28:36-07:00"}
/users/UID/logrecs/LOGREC_ID/set
- comment=<string> Set the comment field to the provided string
- tags=<list of tags separated by commas> Set the tags for the logrec. Behaves the same as /users/UID/tags/LOGREC_ID/set?tags=<value> other than having a different return value.
- nsfw=<value> If specified, alters the value of the NSFW flag on the logrec and modifies tag list appropriately to either include an "nsfw" tag if value is true, or remove any existing "nsfw" tags if value is false.
{"nsfw":false,"datafile_id":null,"comment":"new comment","begin":"2011-01-23T11:32:43-08:00","photo_file_size":797510,"created_at":"2011-03-22T09:28:38-07:00","updated_at":"2011-03-22T09:28:38-07:00","photo_file_name":"IMG_20110123_143243.jpg","import_id":null,"photo_content_type":"image/jpeg","end_d":1295811163.0,"dev_nickname":null,"datahash":null,"tags":["a","b","c"],"id":38562,"end":"2011-01-23T11:32:43-08:00","dev_id":null,"dat_fields":null,"begin_d":1295811163.0,"type":"Logphoto","user_id":1,"photo_updated_at":"2011-03-22T13:28:36-07:00"}
Facet Metadata
/metadata/UID/ConnectorName.ObjectTypeName/FACET_ID/get
Returns the metadata (currently only the tags and comment) for the facet specified by the given connector name, object type name, and facet ID. The array of tags contains the tags in alphabetical order.
Example: curl -u test:testtest http://localhost:8080/api/bodytrack/metadata/1/FluxtreamCapture.photo/56/get
{"comment":"this is the comment","tags":["bar","foo"]}
/metadata/UID/ConnectorName.ObjectTypeName/FACET_ID/set
Sets the metadata (currently only the tags and/or comment for the facet specified by the given connector name, object type name, and facet ID. At least one of the following parameters is required:
- comment=<string>
- tags=<list of tags separated by commas>
This method will only modify fields which are specified. That is, if the client only specifies the comment field, then the existing tags will remain unchanged. Likewise, if the client only specifies the tags field, then the existing comment will remain unchanged. If neither comment nor tags is specified, nothing happens, but an error is returned (see below) and the HTTP Status Code will be a 400.
Example: curl -u test:testtest --data "comment=this+is+the+comment&tags=foo,bar" http://localhost:8080/api/bodytrack/metadata/1/FluxtreamCapture.photo/56/set
{"result":"OK","message":"Metadata updated successfully!","payload":{"comment":"this is the comment","tags":["bar","foo"]}}
Example: curl -u test:testtest --data "foo=bar" http://localhost:8080/api/bodytrack/metadata/1/FluxtreamCapture.photo/56/set
{"result":"KO","message":"Nothing changed since comment and tags were both null"}
Tags
/users/{UID}/tags
Returns a JSON object containing atags
field whose value is array of tag strings. The array of tags contains the tags in alphabetical order. Example: {"tags": ["tag1", "tag2", "tag3"]}
/users/UID/tags/LOGREC_ID/set
/users/UID/tags/LOGREC_ID/get
Log Items
Get a JSON encoded array of log items for a given user with the following parameters:
Required:
- count Maximum number of items to be returned.
- time Starting time in floating point unixtime. By default this is the starting time for the query and items are returned in order of ascending [time, id], but if 'descending' flag is present and not =false then this is the ending time for the query and items are returned in order of descending [time, id]. Items at exactly this time are by default included, but will be excluded if 'exclusive' flag is present and not =false
Optional:
- id May be used along with time to add specificity in the case where multiple items occur at the same time.
- type =<list of types separated by commas> By default log items of all types are returned, but can specify a subset of types by using this parameter. Possible values are comments, photos, or observations. If multiple types are specified, separate with commas.
- exclusive By default an item exactly matching either time or [time,id] (if specified) is included in the results. If theexclusive flag is present and is not =false then such an item is excluded from the results.
- descending By default items are included in order of ascending [time,id] starting from either time or [time,id] (if specified). If the descending flag is present and is not =false then items are returned in order of descending [time,id] ending at time or [time,id].
- any_tags or all_tags =<list of tags separated by commas> By default all available log items matching the former parameters are returned. Specifying either any_tags or all_tags (only one is allowed) further limits results to only matching additional tagging criteria. any_tags means that an item should be returned if it is tagged with one or more of the specified tags. all_tags means that an item should be returned if it is tagged with all of the specified tags. In both cases items are not penalized for having additional unspecified tags as well.
- show_nsfw By default NSFW items are not returned. If the show_nsfw flag is present and is not =false then NSFW items will be included in the results.
Channel Specs
/users/UID/channels/DeviceNickname.ChannelName/set
Modifies selected fields in a given channel spec. Returns empty on success, and {"error":<error string>} on failure.
- user_default_style=<json map for the "style" field for this channel>, subkeys are typically "comments" and "styles"
- y_range=<json map for the "y_range" field for this channel>, subkeys are "min_val" and "max_val", both in the same units as the values for the given channel
- channel_height=<default height of channel in grapher in pixels>
Data upload
Data sources, devices and channels
A data source can either represent a physical device, like a cell phone or a chest strap, or any other source of data, such as from an observation capture app, Fluxtream, etc. Each data source in the system for a given user has a unique name and may contain one or more channels. For historical reasons, the name of the data source to upload to is generally referred to as dev_nickname.
A data channel within a device also has a name, but that name must only be unique within the device.
Source and channel names must include only alphanumeric characters (A-Z, a-z, 0-9) plus underscores. If the names contain other characters they will be converted by the server to underscores.
Formatting of time
All time fields is represented as double-precision floating point time in seconds since Jan 1, 1970 in UTC, not counting leap second (standard UNIX-style time). Decimal seconds are allowed. Times before 1/1/70 are representable by negative numbers.
Storing data
/api/bodytrack/upload?dev_nickname=<name>&channel_names=<channel_names>&data=<data>
POSTs data for a given source to a given user's account. Uses basic auth for both authentication to determine which user the data is being uploaded to. Required parameters are:
- dev_nickname Name of the data source to upload the data to (alphanumeric + underscores, unique to a given user)
- channel_names JSON encoded array of channel names.
Example: ["temperature", "humidity"] data JSON encoded array of arrays of time samples, in the same order as channel names. Time is always the first column (and not mentioned in the channel names above).
Example: [[1234152345.2, 45.9, 95.02], [1234152355.3, 45.8, 95.10]]
The following optional fields may also be used:
- channel_specs JSON encoded key/value pairs mapping between channel_names and specifications relating to the processing or display of that channel. All sub-parameters are optional. If not specified, any channel specs previously provided for this data source will be used. All channel names can only contain alphanumerics and underscores. If they do not comply, they will be converted on the way in.
Subparameters:
units: A string describing the units to display to the user for this channel. Examples are: "bpm", "deg F", "m/s", etc.
Example: { "HR": { "units": "bpm" }, "Alt": { "units": "m"}}
Example: curl -i -u test:testtest http://fluxtream.org/api/bodytrack/upload -d dev_nickname=test -d channel_names='["a","b"]' -d data='[[1332754616,1,10], [1332754617,-1,20]]'
Returns:
{"max_datetime":null,"min_time":1332754616,"failed_records":0,"channel_specs":{"a":{"max_value":1,"min_value":-1,"min_time":1332754616,"channel_bounds":{"max_value":1,"min_value":-1,"min_time":1332754616,"max_time":1332754617},"imported_bounds":{"max_value":1,"min_value":-1,"min_time":1332754616,"max_time":1332754617},"max_time":1332754617},"b":{"max_value":20,"min_value":10,"min_time":1332754616,"channel_bounds":{"max_value":20,"min_value":10,"min_time":1332754616,"max_time":1332754617},"imported_bounds":{"max_value":20,"min_value":10,"min_time":1332754616,"max_time":1332754617},"max_time":1332754617}},"logrec_id":85284,"successful_records":1,"min_datetime":null,"max_time":1332754617}
Storing comments
/api/bodytrack/upload?comment=<comment>
POSTs a comment to a given user's account. Uses basic auth for both authentication to determine which user the data is being uploaded to. Required parameters are:
- comment String to be stored as a comment for the specified user
The following optional fields may also be used:
- dev_nickname Name of the data source to upload the comment to (alphanumeric + underscores, unique to a given user). If specified, this comment will show up in the comments channel for the specified data source name. If not specified, this comment will show up only in the comments channel for the special data source called "All", which aggregates comments from all data sources.
- ignore_duplicate If this parameter is present and not set to zero then the server will ignore the current upload and respond with "duplicate" if it is an exact duplicate of a logrec in the system in terms of user_id, dev_nickname, start and end times, and type. If this flag is not set the current default behavior is to accept all JSON uploads without checking for duplicates since duplicate checking is expensive in the current system.
- timerange JSON map containing begin and end times in floating point unixtime format. If not provided, the time of the upload will be used for both the begin and end times instead.
Example: {"begin" : 1296264403.33352, "end" : 1296748288.93101}
Example: curl -i -u test:testtest http://fluxtream.org/api/bodytrack/upload?comment=hi
Returns:
awesome: {}
Storing photos
/api/bodytrack/upload?photo=<image in binary>
POSTs a photo to a given user's account. Uses basic auth for both authentication to determine which user the data is being uploaded to. Required parameters are:
- photo Binary encoded photo with type image/jpeg
The following optional fields may also be used:
- dev_nickname Name of the data source to upload the comment to (alphanumeric + underscores, unique to a given user). If specified, this photo will show up in the photos channel for the specified data source name. If not specified, this comment will show up only in the photos channel for the special data source called "All", which aggregates photos from all data sources.
- ignore_duplicate If this parameter is present and not set to zero then the server will ignore the current upload and respond with "duplicate" if it is an exact duplicate of a logrec in the system in terms of user_id, dev_nickname, start and end times, and type. If this flag is not set the current default behavior is to accept all JSON uploads without checking for duplicates since duplicate checking is expensive in the current system.
- timerange JSON map containing begin and end times in floating point unixtime format. If not provided, the time contained in the EXIF for the photo will be used. If no usable EXIF is present, the time of upload will be used for both the begin and end times instead. NOTE: If GPS data is present it will use that timestamp, which is fully specified as to time zone. If GPS data is not present, the EXIF timestamp is used but it is ambiguous about timezone. The current behavior is that the photo will end up in an unspecified time zone. This needs to be fixed
Example: {"begin" : 1296264403.33352, "end" : 1296748288.93101}
Example: curl -i -u test:testtest http://fluxtream.org/api/bodytrack/upload -F 'dev_nickname=My_Camera' -F 'photo=@test.jpg;type=image/jpeg'
Returns:
awesome: {}
Storing Fluxtream Capture photos
/photoUpload?connector_name=CONNECTOR_NAME
Accepts a photo uploaded via multipart/form-data to the authenticated user's account for the specified connector. Currently only supports the Fluxtream Capture connector (specified as "fluxtream_capture" in the query string). The multipart form body must contain two parts:
- photo: the photo's bytes
- metadata: JSON containing required photo metadata. Currently the only required field is "capture_time_secs_utc" which is a double that specifies the time the photo was taken in UTC seconds. Optional fields are "tags" (a string containing a comma-delimited list of tags) and "comment" (a string). Note that comments and tags are only honored when a photo is uploaded for the first time (a create). Photos uploaded again are considered an update and the tags and comments are ignored. Clients needing to modify a Fluxtream Capture photo's tags/comments should use the metadata set API method instead. Examples:
{"capture_time_secs_utc":1355314332.000}
{"capture_time_secs_utc":1355314332.000, "tags":"snack,fruit,strawberries", "comment":"Snacked on strawberries from my garden."}
The user need not explicitly add the Fluxtream Capture connector to his/her account prior to upload (and there's actually no way to do so). Instead, the connector is added automatically upon first upload. Valid photo formats are JPEG, PNG, and GIF.
See the Fluxtream Capture Photo Architecture docs for more info.
Example: curl -v -u username:password --form 'metadata={"capture_time_secs_utc":1355314332.000}' --form photo=@orientation_4.jpg http://localhost:8080/api/bodytrack/photoUpload?connector_name=fluxtream_capture;
Returns: JSON describing whether the upload was successful. The HTTP status code will be 200 upon success, and non-200 upon failure. Here are several examples:
HTTP 200 OK
{"result":"OK","message":"photo created sucessfully!","payload":{"operation":"created","id":42, "key":"1.FluxtreamCapture.photo.2012348.1355414332000_9c2303170b4601917c59449cdecaecaa0ccbd40b6cf26406f07316261da7fe53"}}
HTTP 200 OK
{"result":"OK","message":"photo updated sucessfully!","payload":{"operation":"updated","id":42,"key":"1.FluxtreamCapture.photo.2012347.1355311332000_0dae72b9ee44a61c1a6efe24814cb713026d58fb5af92f91e88cd2a2bf24d41c"}}
HTTP 400 Bad Request
{"result":"KO","message":"Upload failed because the connector [bogus_connector] is unknown"}
HTTP 400 Bad Request
{"result":"KO","message":"Upload failed because photo uploads are currently only allowed for the Fluxtream Capture connector"}
HTTP 400 Bad Request
{"result":"KO","message":"Upload failed because both the \u0027photo\u0027 and \u0027metadata\u0027 parts are required and must be non-null"}
HTTP 400 Bad Request
{"result":"KO","message":"Upload failed because the Multipart was null"}
HTTP 400 Bad Request
{"result":"KO","message":"InvalidDataException while trying to save the photo"}
HTTP 415 Unsupported Media Type
{"result":"KO","message":"UnsupportedImageFormatException while trying to save the photo"}
HTTP 500 Internal Server Error
{"result":"KO","message":"StorageException while trying to save the photo"}
HTTP 500 Internal Server Error
{"result":"KO","message":"Upload failed due to an unexpected exception"}