         readGroups:
           _id: groupId
 
+# TODO: Should we use try/except around the code so that if there is any exception we stop handlers?
+# TODO: Deduplicate code: it is similar to two functions in publication.coffee
+publishUsingPermissions = (publish, selector, options) ->
+  # There are moments when two observes are observing mostly similar list
+  # of annotations ids so it could happen that one is changing or removing
+  # annotation just while the other one is adding, so we are making sure
+  # using currentAnnotations variable that we have a consistent view of the
+  # annotations we published
+  currentAnnotations = {}
+  handleAnnotations = null
+
+  publishAnnotations = (newIsAdmin, newGroups) =>
+    newGroups ||= []
+
+    initializing = true
+    initializedAnnotations = []
+
+    oldHandleAnnotations = handleAnnotations
+    handleAnnotations = Annotation.documents.find(selector(newIsAdmin, newGroups), options).observeChanges
+      added: (id, fields) =>
+        initializedAnnotations.push id if initializing
+
+        return if currentAnnotations[id]
+        currentAnnotations[id] = true
+
+        publish.added 'Annotations', id, fields
+
+      changed: (id, fields) =>
+        return if not currentAnnotations[id]
+
+        publish.changed 'Annotations', id, fields
+
+      removed: (id) =>
+        return if not currentAnnotations[id]
+        delete currentAnnotations[id]
+
+        publish.removed 'Annotations', id
+
+    initializing = false
+
+    # We stop the handle after we established the new handle,
+    # so that any possible changes hapenning in the meantime
+    # were still processed by the old handle
+    oldHandleAnnotations.stop() if oldHandleAnnotations
+
+    # And then we remove those which are not published anymore
+    for id in _.difference _.keys(currentAnnotations), initializedAnnotations
+      delete currentAnnotations[id]
+      publish.removed 'Annotations', id
+
+  currentPersonId = null # Just for asserts
+
+  if publish.personId
+    handlePersons = Person.documents.find(
+      _id: publish.personId
+    ,
+      fields:
+        # _id field is implicitly added
+        isAdmin: 1
+        inGroups: 1
+      transform: null # We are only interested in data
+    ).observe
+      added: (person) =>
+        # There should be only one person with the id at every given moment
+        assert.equal currentPersonId, null
+
+        currentPersonId = person._id
+        publishAnnotations person.isAdmin, _.pluck(person.inGroups, '_id')
+
+      changed: (newPerson, oldPerson) =>
+        # Person should already be added
+        assert.equal currentPersonId, newPerson._id
+
+        publishAnnotations newPerson.isAdmin, _.pluck(newPerson.inGroups, '_id')
+
+      removed: (oldPerson) =>
+        # We cannot remove the person if we never added the person before
+        assert.equal currentPersonId, oldPerson._id
+
+        currentPersonId = null
+        publishAnnotations false, []
+
+  # If we get to here and currentPersonId was not set when initializing,
+  # we call publishAnnotations with empty list so that possibly something
+  # is published. If later on person is added, publishAnnotations will be
+  # simply called again.
+  publishAnnotations false, [] unless currentPersonId
+
+  publish.ready()
+
+  publish.onStop =>
+    handlePersons.stop() if handlePersons
+    handleAnnotations.stop() if handleAnnotations
+
 Meteor.publish 'annotations-by-id', (id) ->
   check id, String
 
   return unless id
 
-  Annotation.documents.find
-    _id: id
+  publishUsingPermissions @, (isAdmin, groups) =>
+    if isAdmin
+      _id: id
+    else
+      _id: id
+      $or: [
+        access: Annotation.ACCESS.PUBLIC
+      ,
+        access: Annotation.ACCESS.PRIVATE
+        'readUsers._id': @personId
+      ,
+        access: Annotation.ACCESS.PRIVATE
+        'readGroups._id':
+          $in: groups
+      ]
   ,
     Annotation.PUBLIC_FIELDS()
 


  return unless publicationId

  Annotation.documents.find
    'publication._id': publicationId
  ,
    Annotation.PUBLIC_FIELDS()

Annotation.Meta.collection.allow
  insert: (userId, doc) ->
    # TODO: Check whether inserted document conforms to schema
    # TODO: Check that author really has access to the annotation

    return false unless userId

