Code Documentation

Annotation

An implementation of the Annotation store API for Annotator.js.

Models

class annotator_store.models.AnnotationQuerySet(model=None, query=None, using=None, hints=None)[source]

Custom QuerySet for Annotation

visible_to(user)[source]

Return annotations the specified user is allowed to view. Objects are found based on view_annotation permission and

annotations; users can access only their own annotations or those where permissions have been granted to a group they belong to.

Note

Due to the use of guardian.shortcuts.get_objects_for_user(), it is recommended to use this method first; it does combine the existing queryset query, but it does not chain as querysets normally do.

visible_to_group(group)[source]

Return annotations the specified group is allowed to view. Objects are found based on view_annotation permission and per-object permissions.

Note

Due to the use of guardian.shortcuts.get_objects_for_user(), it is recommended to use this method first; it does combine the existing queryset query, but it does not chain as querysets normally do.

last_created_time()[source]

Creation time of the most recently created annotation. If queryset is empty, returns None.

last_updated_time()[source]

Update time of the most recently created annotation. If queryset is empty, returns None.

class annotator_store.models.AnnotationManager[source]

Custom Manager for Annotation. Returns AnnotationQuerySet as default queryset, and exposes visible_to() for convenience.

visible_to(user)[source]

Convenience access to AnnotationQuerySet.visible_to()

visible_to_group(group)[source]

Convenience access to AnnotationQuerySet.visible_to_group()

class annotator_store.models.BaseAnnotation(*args, **kwargs)[source]

Django database model to store Annotator.js annotation data, based on the annotation format documentation.

UUID_REGEX = '[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}'

regex for recognizing valid UUID, for use in site urls

schema_version = 'v1.0'

annotation schema version: default v1.0

id

unique id for the annotation; uses uuid.uuid4()

created

datetime annotation was created; automatically set when added

updated

datetime annotation was last updated; automatically updated on save

text

content of the annotation

quote

the annotated text

uri

URI of the annotated document

user

user who owns the annotation when serialized, id of annotation owner OR an object with an ‘id’ property

extra_data

any additional data included in the annotation not parsed into specific model fields; this includes ranges, permissions, annotation data, etc

common_fields = ['text', 'quote', 'uri', 'user']

fields in the db model that are provided by annotation json when creating or updating an annotation

internal_fields = ['updated', 'created', 'id', 'user', 'annotator_schema_version']

internal fields that are not set from values provided by annotation json when creating or updating

get_absolute_url()[source]

URL to view this annotation within the annotation API.

text_preview()[source]

Short preview of annotation text content

URI as a clickable link

related_pages

convenience access to list of related pages in extra data

classmethod create_from_request(request)[source]

Initialize a new Annotation based on data from a django.http.HttpRequest.

Expects request body content to be JSON; sets annotation user based on the request user.

update_from_request(request)[source]

Update attributes from data in a django.http.HttpRequest. Expects request body content to be JSON. Currently does not modify user.

handle_extra_data(data, request)[source]

Handle any “extra” data that is not part of the stock annotation data model. Use this method to customize the logic for creating and updating annotations from request data.

NOTE: request is passed in to support permissions handling when object-level permissions are enabled.

info()[source]

Return a collections.OrderedDict of fields to be included in serialized JSON version of the current annotation.

class annotator_store.models.AnnotationWithPermissions(*args, **kwargs)[source]

Mix-in annotation class to provide object-level permissions handling via django-guardian

permission_to_codename = {'read': 'view_annotation', 'admin': 'admin_annotation', 'update': 'change_annotation', 'delete': 'delete_annotation'}

map annotator permissions to django annotation permission codenames

codename_to_permission = {'change_annotation': 'update', 'delete_annotation': 'delete', 'view_annotation': 'read', 'admin_annotation': 'admin'}

lookup annotation permission mode by django permission codename

info()[source]

Update default annotation info to include permissions

save(*args, **kwargs)[source]

Extend default save method to ensure annotation user has access to edit and update their own annotation.

handle_extra_data(data, request)[source]

Handle any “extra” data that is not part of the stock annotation data model. Use this method to customize the logic for updating an annotation from request data.

user_permissions()[source]

Queryset of guardian.model.UserObjectPermission objects associated with this annotation.

group_permissions()[source]

Queryset of guardian.model.GroupObjectPermission objects associated with this annotation.

assign_permission(permission, entity)[source]

Wrapper around guardian.shortcuts.assign_perm(). Gives the specified permission to the specified user or group on the current object.

db_permissions(permissions)[source]

Convert annotation permission data into actionable django permissions using guardian per-object permissions.

permissions_dict()[source]

Convert stored guardian per-object permissions into annotation permission dictionary format

user_has_perm(user, permission)[source]

Check if a user has a specific permission on this object.

class annotator_store.models.AnnotationGroup(*args, **kwargs)[source]

Annotation Group; extends django.contrib.auth.models.Group.

Intended to facilitate group permissions on annotations.

notes

optional notes field

created

datetime annotation was created; automatically set when added

updated

datetime annotation was last updated; automatically updated on save

class annotator_store.models.Annotation(id, created, updated, text, quote, uri, user, extra_data)[source]

Views

class annotator_store.views.AnnotationIndex(**kwargs)[source]

Annotator store API index view, with information and links for API urls.

class annotator_store.views.Annotations(**kwargs)[source]

API annotations view.

On GET, lists annotations. On AJAX POST with json data in request body, creates a new annotation.

Users must be logged in to create new annotations, and can only view their own annotations.

get(request)[source]

List viewable annotations as JSON.

post(*args, **kwargs)[source]

Create a new annotation via AJAX.

class annotator_store.views.AnnotationView(**kwargs)[source]

Views for displaying, updating, and removing a single Annotation. All views require that the user be logged in and own the annotation being viewed, updated, or deleted.

get(request, id)[source]

Display the JSON information for the requested annotation.

put(request, id)[source]

Update the annotation via JSON data posted by AJAX.

delete(request, id)[source]

Remove the annotation. On success, returns a 204 No Content response as per the annotator store API documentation.

class annotator_store.views.AnnotationSearch(**kwargs)[source]

Search annotations and display as JSON. Results are restricted to annotations the users has permission to view (currently only annotations owned by the user for everyone other than superusers).

The following search fields are currently supported:
  • uri (exact match)
  • text (case-insensitive partial match)
  • quote (case-insensitive partial match)
  • user (exact match on username)
  • keyword: case-insensitive partial match on text, quote, or with extra data (e.g., to match tags)

Search results can be limited by specifying limit or offset parameters.

Utils

annotator_store.utils.absolutize_url(local_url)[source]

Convert a local url to an absolute url, with scheme and server name, based on the current configured Site.

Parameters:local_url – local url to be absolutized, e.g. something generated by reverse()
annotator_store.utils.user_passes_test_ajax_403(test_func, login_url=None, redirect_field_name='next')[source]

Variation on django.contrib.auth.decorators.user_passes_test(). If the user is already logged in but has insufficient privileges, returns a 403 Forbidden response because redirecting to log in is not useful. If request is ajax user is not authenticated, returns a 401 because redirecting an ajax request to login is also not useful.

Partially adapted from/inspired by eulcommon implementation. http://eulcommon.readthedocs.io/en/0.17.0/djangoextras.html#module-eulcommon.djangoextras.auth

annotator_store.utils.permission_required(perm, login_url=None)[source]

Version of django.contrib.auth.decorators.permission_required() that uses user_passes_test_with_ajax_403() for better http response codes and ajax handling.