-
Notifications
You must be signed in to change notification settings - Fork 30
How we implement groups functionality
Annotation Studio allows users to view both documents and annotations through membership in groups.
We implement the group feature in three elements:
- Annotator. We add several fields to the annotator data schema.
- Annotation Studio. User and Document objects can both be associated with any number of tags, each representing a group.
- MIT Annotation Data Store supports queries that limit results to annotations to matching values in their groups fields.
###Annotator
Here is our modified annotation data model. Note the two additions to the schema: groups
and subgroups
:
{
"id": "xyz",
"quote": "outward-bound",
"text": "",
"uri": "http://annotationstudio.mit.edu/documents/billy-budd",
"user": "[email protected]",
"username": "HyperStudio",
"uuid": "1B9D142B",
"subgroups": ["test"],
"groups": ["21L.705", "test"],
"permissions": {
"delete": ["[email protected]"],
"update": ["[email protected]"],
"admin": ["[email protected]"],
"read": []
},
"tags": [],
"ranges": [{
"start": "/div[1]/p[6]",
"startOffset": 604,
"end": "/div[1]/p[6]",
"endOffset": 617,
}],
"updated": "2013-09-16T19:45:39.267Z",
"created": "2013-09-16T19:45:13.012Z",
"annotator_schema_version": "1.0"
}
Those group values are stored per-user, and are added automatically to all of each user's annotations.
###Annotation Studio
In Annotation Studio, we have a tags
table
ans_dev=# select * from tags;
id | name
----+----------------------------
1 | Partners
2 | Hyperstudio
3 | Instructors
4 | Developers
5 | Melville
6 | Darwin
and a taggings
mapping table
ans_dev=# select id, tag_id, taggable_id, taggable_type, context from taggings;
id | tag_id | taggable_id | taggable_type | context
-----+--------+-------------+---------------+--------------
523 | 73 | 172 | User | rep_subgroup
525 | 44 | 87 | Document | rep_group
526 | 45 | 87 | Document | rep_group
527 | 75 | 87 | Document | rep_group
528 | 71 | 174 | User | rep_group
529 | 75 | 174 | User | rep_group
530 | 76 | 174 | User | rep_subgroup
531 | 77 | 174 | User | rep_subgroup
532 | 71 | 171 | User | rep_group
534 | 76 | 175 | User | rep_subgroup
This is the structure set up by the excellent acts_as_taggable gem, which is incorporated as part of our Repertoire Groups gem. Repertoire Groups also provides user roles (like administrator, editor, etc). Tags can be associated with User objects and with Document objects, and can in turn be subgrouped into contexts, in our case, rep_group, and rep_subgroup.
ans_dev=# select id, tag_id, taggable_id, taggable_type, context from taggings; id | tag_id | taggable_id | taggable_type | context -----+--------+-------------+---------------+-------------- 523 | 73 | 172 | User | rep_subgroup 525 | 44 | 87 | Document | rep_group 526 | 45 | 87 | Document | rep_group 527 | 75 | 87 | Document | rep_group 528 | 71 | 174 | User | rep_group 529 | 75 | 174 | User | rep_group 530 | 76 | 174 | User | rep_subgroup 531 | 77 | 174 | User | rep_subgroup 532 | 71 | 171 | User | rep_group 534 | 76 | 175 | User | rep_subgroup
###MIT Annotation Data Store
Finally, on the Data Store, which stores all annotations, in addition to storing annotations, we support queries against those groups and subgroups values.
app.get('/api/search', tokenOK, function (req, res) {
var query;
//...other query options...
switch (req.query.mode) {
case 'user':
query.where('user').equals(req.query.user);
break;
case 'group':
query.where('subgroups').in(req.query.subgroups);
break;
case 'class':
query.where('groups').in(req.query.groups);
break;
case 'admin':
// Admins can see everything, so don't limit
// results by group and subgroup values in query
break;
}
//...query execution...
}