1 # This file is part of Wolne Lektury, licensed under GNU Affero GPLv3 or later.
2 # Copyright © Fundacja Wolne Lektury. See NOTICE for more information.
4 from datetime import timedelta
6 from django.conf import settings
7 from django.contrib.auth.models import User
8 from django.contrib.contenttypes.models import ContentType
9 from django.db import models
10 from django.db.models.signals import pre_delete
11 from django.utils import timezone
12 from catalogue.models import Book, Tag
15 class Deleted(models.Model):
16 object_id = models.IntegerField()
17 slug = models.SlugField('slug', max_length=120, blank=True, db_index=True)
18 content_type = models.ForeignKey(ContentType, models.CASCADE)
19 category = models.CharField(max_length=64, null=True, blank=True, db_index=True)
20 created_at = models.DateTimeField(editable=False, db_index=True)
21 deleted_at = models.DateTimeField(auto_now_add=True, db_index=True)
24 unique_together = (('content_type', 'object_id'),)
27 def _pre_delete_handler(sender, instance, **kwargs):
28 """ save deleted objects for change history purposes """
30 if sender in (Book, Tag):
32 if instance.category in ('book', 'set'):
34 category = instance.category
37 content_type = ContentType.objects.get_for_model(sender)
38 Deleted.objects.create(
39 content_type=content_type,
40 object_id=instance.id,
41 created_at=instance.created_at,
45 pre_delete.connect(_pre_delete_handler)
48 class BookUserData(models.Model):
49 book = models.ForeignKey(Book, models.CASCADE)
50 user = models.ForeignKey(User, models.CASCADE)
51 complete = models.BooleanField(default=False)
52 last_changed = models.DateTimeField(auto_now=True)
55 unique_together = [('user', 'book')]
59 return 'complete' if self.complete else 'reading'
62 def update(cls, book, user, state):
63 instance, created = cls.objects.get_or_create(book=book, user=user)
64 instance.complete = state == 'complete'
73 ('pending', 'Pending approval'),
74 ('accepted', 'Accepted'),
75 ('canceled', 'Canceled'),
79 class Nonce(models.Model):
80 token_key = models.CharField(max_length=KEY_SIZE)
81 consumer_key = models.CharField(max_length=KEY_SIZE)
82 key = models.CharField(max_length=255)
85 return "Nonce %s for %s" % (self.key, self.consumer_key)
88 class Consumer(models.Model):
89 name = models.CharField(max_length=255)
90 description = models.TextField()
91 key = models.CharField(max_length=KEY_SIZE)
92 secret = models.CharField(max_length=SECRET_SIZE)
93 status = models.CharField(max_length=16, choices=CONSUMER_STATES, default='pending')
94 user = models.ForeignKey(
95 settings.AUTH_USER_MODEL, models.CASCADE,
96 null=True, blank=True, related_name='consumers'
100 return "Consumer %s with key %s" % (self.name, self.key)
103 class Token(models.Model):
108 (REQUEST, 'Request'),
113 key = models.CharField(max_length=KEY_SIZE)
114 secret = models.CharField(max_length=SECRET_SIZE)
115 token_type = models.IntegerField(choices=TOKEN_TYPES)
116 timestamp = models.IntegerField()
117 is_approved = models.BooleanField(default=False)
118 user = models.ForeignKey(
119 settings.AUTH_USER_MODEL, models.CASCADE,
120 null=True, blank=True, related_name='tokens'
122 consumer = models.ForeignKey(Consumer, models.CASCADE, null=True, blank=True)
125 return "%s Token %s for %s" % (self.get_token_type_display(), self.key, self.consumer)
128 class SessionTransferToken(models.Model):
129 token = models.UUIDField(default=uuid.uuid4, primary_key=True, editable=False)
130 user = models.ForeignKey(
131 settings.AUTH_USER_MODEL, models.CASCADE)
132 created_at = models.DateTimeField(auto_now_add=True)
133 expires_at = models.DateTimeField()
134 used = models.BooleanField(default=False)
137 def create_for_user(cls, user, lifetime_seconds=30):
138 return cls.objects.create(
140 expires_at=timezone.now() + timedelta(seconds=lifetime_seconds)
146 if timezone.now() > self.expires_at: