2 from django.apps import apps
3 from django.db import models
4 from django.utils.timezone import now
5 from social.syncable import Syncable
8 class Bookmark(Syncable, models.Model):
9 uuid = models.UUIDField(unique=True, default=uuid.uuid4, editable=False)
10 user = models.ForeignKey('auth.User', models.CASCADE)
11 book = models.ForeignKey('catalogue.Book', models.CASCADE)
12 anchor = models.CharField(max_length=100, blank=True)
13 created_at = models.DateTimeField(auto_now_add=True)
14 note = models.TextField(blank=True)
15 updated_at = models.DateTimeField(auto_now=True)
16 reported_timestamp = models.DateTimeField(default=now)
17 deleted = models.BooleanField(default=False)
27 def create_from_data(cls, user, data):
28 if data.get('location'):
29 return cls.get_by_location(user, data['location'], create=True)
30 elif data.get('book') and data.get('anchor'):
31 return cls.objects.create(user=user, book=data['book'], anchor=data['anchor'])
35 return self.updated_at.timestamp()
38 return f'{self.book.slug}/{self.anchor}'
41 def get_by_location(cls, user, location, create=False):
42 Book = apps.get_model('catalogue', 'Book')
44 slug, anchor = location.split('/')
47 instance = cls.objects.filter(
52 if instance is None and create:
54 book = Book.objects.get(slug=slug)
55 except Book.DoesNotExist:
57 instance = cls.objects.create(
64 def get_for_json(self):
67 'anchor': self.anchor,
69 'created_at': self.created_at,
73 class Quote(models.Model):
74 uuid = models.UUIDField(unique=True, default=uuid.uuid4, editable=False)
75 user = models.ForeignKey('auth.User', models.CASCADE)
76 book = models.ForeignKey('catalogue.Book', models.CASCADE)
77 created_at = models.DateTimeField(auto_now_add=True)
78 start_elem = models.CharField(max_length=100, blank=True)
79 end_elem = models.CharField(max_length=100, blank=True)
80 start_offset = models.IntegerField(null=True, blank=True)
81 end_offset = models.IntegerField(null=True, blank=True)
82 text = models.TextField(blank=True)
87 def get_for_json(self):
90 'startElem': self.start_elem,
91 'endElem': self.end_elem,
92 'startOffset': self.start_offset,
93 'startOffset': self.end_offset,
94 'created_at': self.created_at,
97 def from_path(elem, path):
99 if e.text: yield (e, 'text')
101 if child.attrib.get('id') != 'toc':
104 yield (child, 'tail')
107 elem = list(child_nodes(elem))[n]