fix
[wolnelektury.git] / src / api / models.py
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.
3 #
4 from django.conf import settings
5 from django.contrib.auth.models import User
6 from django.contrib.contenttypes.models import ContentType
7 from django.db import models
8 from django.db.models.signals import pre_delete
9
10 from catalogue.models import Book, Tag
11
12
13 class Deleted(models.Model):
14     object_id = models.IntegerField()
15     slug = models.SlugField('slug', max_length=120, blank=True, db_index=True)
16     content_type = models.ForeignKey(ContentType, models.CASCADE)
17     category = models.CharField(max_length=64, null=True, blank=True, db_index=True)
18     created_at = models.DateTimeField(editable=False, db_index=True)
19     deleted_at = models.DateTimeField(auto_now_add=True, db_index=True)
20
21     class Meta:
22         unique_together = (('content_type', 'object_id'),)
23
24
25 def _pre_delete_handler(sender, instance, **kwargs):
26     """ save deleted objects for change history purposes """
27
28     if sender in (Book, Tag):
29         if sender == Tag:
30             if instance.category in ('book', 'set'):
31                 return
32             category = instance.category
33         else:
34             category = None
35         content_type = ContentType.objects.get_for_model(sender)
36         Deleted.objects.create(
37             content_type=content_type,
38             object_id=instance.id,
39             created_at=instance.created_at,
40             category=category,
41             slug=instance.slug
42         )
43 pre_delete.connect(_pre_delete_handler)
44
45
46 class BookUserData(models.Model):
47     book = models.ForeignKey(Book, models.CASCADE)
48     user = models.ForeignKey(User, models.CASCADE)
49     complete = models.BooleanField(default=False)
50     last_changed = models.DateTimeField(auto_now=True)
51
52     class Meta:
53         unique_together = [('user', 'book')]
54
55     @property
56     def state(self):
57         return 'complete' if self.complete else 'reading'
58
59     @classmethod
60     def update(cls, book, user, state):
61         instance, created = cls.objects.get_or_create(book=book, user=user)
62         instance.complete = state == 'complete'
63         instance.save()
64         return instance
65
66
67 KEY_SIZE = 18
68 SECRET_SIZE = 32
69
70 CONSUMER_STATES = (
71     ('pending', 'Pending approval'),
72     ('accepted', 'Accepted'),
73     ('canceled', 'Canceled'),
74 )
75
76
77 class Nonce(models.Model):
78     token_key = models.CharField(max_length=KEY_SIZE)
79     consumer_key = models.CharField(max_length=KEY_SIZE)
80     key = models.CharField(max_length=255)
81
82     def __str__(self):
83         return "Nonce %s for %s" % (self.key, self.consumer_key)
84
85
86 class Consumer(models.Model):
87     name = models.CharField(max_length=255)
88     description = models.TextField()
89     key = models.CharField(max_length=KEY_SIZE)
90     secret = models.CharField(max_length=SECRET_SIZE)
91     status = models.CharField(max_length=16, choices=CONSUMER_STATES, default='pending')
92     user = models.ForeignKey(
93         settings.AUTH_USER_MODEL, models.CASCADE,
94         null=True, blank=True, related_name='consumers'
95     )
96
97     def __str__(self):
98         return "Consumer %s with key %s" % (self.name, self.key)
99
100
101 class Token(models.Model):
102     REQUEST = 1
103     ACCESS = 2
104     TOKEN_TYPES = ((REQUEST, 'Request'), (ACCESS, 'Access'))
105
106     key = models.CharField(max_length=KEY_SIZE)
107     secret = models.CharField(max_length=SECRET_SIZE)
108     token_type = models.IntegerField(choices=TOKEN_TYPES)
109     timestamp = models.IntegerField()
110     is_approved = models.BooleanField(default=False)
111     user = models.ForeignKey(
112         settings.AUTH_USER_MODEL, models.CASCADE,
113         null=True, blank=True, related_name='tokens'
114     )
115     consumer = models.ForeignKey(Consumer, models.CASCADE)
116
117     def __str__(self):
118         return "%s Token %s for %s" % (self.get_token_type_display(), self.key, self.consumer)