keep book popularity in model
[wolnelektury.git] / src / social / utils.py
1 # -*- coding: utf-8 -*-
2 # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
3 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
4 #
5 from collections import defaultdict
6 from django.contrib.contenttypes.models import ContentType
7 from django.db.models import Q
8 from django.utils.functional import lazy
9 from catalogue.models import Book, Tag
10 from catalogue import utils
11 from catalogue.tasks import touch_tag
12 from social.models import Cite
13
14
15 def likes(user, work, request=None):
16     if not user.is_authenticated():
17         return False
18
19     if request is None:
20         return work.tags.filter(category='set', user=user).exists()
21
22     if not hasattr(request, 'social_likes'):
23         # tuple: unchecked, checked, liked
24         request.social_likes = defaultdict(lambda: (set(), set(), set()))
25
26     ct = ContentType.objects.get_for_model(type(work))
27     likes_t = request.social_likes[ct.pk]
28     if work.pk in likes_t[1]:
29         return work.pk in likes_t[2]
30     else:
31         likes_t[0].add(work.pk)
32
33         def _likes():
34             if likes_t[0]:
35                 ids = tuple(likes_t[0])
36                 likes_t[0].clear()
37                 likes_t[2].update(Tag.intermediary_table_model.objects.filter(
38                     content_type_id=ct.pk, tag__user_id=user.pk,
39                     object_id__in=ids
40                 ).distinct().values_list('object_id', flat=True))
41                 likes_t[1].update(ids)
42             return work.pk in likes_t[2]
43         return lazy(_likes, bool)()
44
45
46 def get_set(user, name):
47     """Returns a tag for use by the user. Creates it, if necessary."""
48     try:
49         tag = Tag.objects.get(category='set', user=user, name=name)
50     except Tag.DoesNotExist:
51         tag = Tag.objects.create(
52             category='set', user=user, name=name, slug=utils.get_random_hash(name), sort_key=name.lower())
53     return tag
54
55
56 def set_sets(user, work, sets):
57     """Set tags used for given work by a given user."""
58
59     old_sets = list(work.tags.filter(category='set', user=user))
60
61     work.tags = sets + list(
62             work.tags.filter(~Q(category='set') | ~Q(user=user)))
63
64     for shelf in [shelf for shelf in old_sets if shelf not in sets]:
65         touch_tag(shelf)
66     for shelf in [shelf for shelf in sets if shelf not in old_sets]:
67         touch_tag(shelf)
68
69     # delete empty tags
70     Tag.objects.filter(category='set', user=user, items=None).delete()
71
72     if isinstance(work, Book):
73         work.update_popularity()
74
75
76 def cites_for_tags(tags):
77     """Returns a QuerySet with all Cites for books with given tags."""
78     return Cite.objects.filter(book__in=Book.tagged.with_all(tags))