models.py 3.08 KB
Newer Older
1 2 3
from django.db import models
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
4
from django.core.exceptions import ValidationError
5
from django.utils.html import strip_tags
6 7
import json

8 9
from xmodule_django.models import CourseKeyField

Arthur Barrett committed
10

11 12
class Note(models.Model):
    user = models.ForeignKey(User, db_index=True)
13
    course_id = CourseKeyField(max_length=255, db_index=True)
14
    uri = models.CharField(max_length=255, db_index=True)
15 16
    text = models.TextField(default="")
    quote = models.TextField(default="")
17
    range_start = models.CharField(max_length=2048)  # xpath string
18
    range_start_offset = models.IntegerField()
19
    range_end = models.CharField(max_length=2048)  # xpath string
20
    range_end_offset = models.IntegerField()
Arthur Barrett committed
21
    tags = models.TextField(default="")  # comma-separated string
22 23
    created = models.DateTimeField(auto_now_add=True, null=True, db_index=True)
    updated = models.DateTimeField(auto_now=True, db_index=True)
24 25

    def clean(self, json_body):
e0d committed
26
        """
27
        Cleans the note object or raises a ValidationError.
e0d committed
28
        """
29 30 31 32
        if json_body is None:
            raise ValidationError('Note must have a body.')

        body = json.loads(json_body)
33
        if not isinstance(body, dict):
34 35
            raise ValidationError('Note body must be a dictionary.')

36 37 38 39 40 41
        # NOTE: all three of these fields should be considered user input
        # and may be output back to the user, so we need to sanitize them.
        # These fields should only contain _plain text_.
        self.uri = strip_tags(body.get('uri', ''))
        self.text = strip_tags(body.get('text', ''))
        self.quote = strip_tags(body.get('quote', ''))
42 43 44 45 46 47 48 49 50 51 52

        ranges = body.get('ranges')
        if ranges is None or len(ranges) != 1:
            raise ValidationError('Note must contain exactly one range.')

        self.range_start = ranges[0]['start']
        self.range_start_offset = ranges[0]['startOffset']
        self.range_end = ranges[0]['end']
        self.range_end_offset = ranges[0]['endOffset']

        self.tags = ""
53
        tags = [strip_tags(tag) for tag in body.get('tags', [])]
54 55
        if len(tags) > 0:
            self.tags = ",".join(tags)
56 57

    def get_absolute_url(self):
e0d committed
58
        """
e0d committed
59
        Returns the absolute url for the note object.
e0d committed
60
        """
61 62
        # pylint: disable=no-member
        kwargs = {'course_id': self.course_id.to_deprecated_string(), 'note_id': str(self.pk)}
63 64 65
        return reverse('notes_api_note', kwargs=kwargs)

    def as_dict(self):
e0d committed
66
        """
67
        Returns the note object as a dictionary.
e0d committed
68
        """
69
        return {
70 71
            'id': self.pk,
            'user_id': self.user.pk,
72 73 74 75 76 77 78 79 80
            'uri': self.uri,
            'text': self.text,
            'quote': self.quote,
            'ranges': [{
                'start': self.range_start,
                'startOffset': self.range_start_offset,
                'end': self.range_end,
                'endOffset': self.range_end_offset
            }],
81 82 83
            'tags': self.tags.split(","),
            'created': str(self.created),
            'updated': str(self.updated)
Arthur Barrett committed
84
        }