Prevent userlist duplicates
[wolnelektury.git] / src / social / utils.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 collections import defaultdict
5 from random import randint
6
7 from django.contrib.contenttypes.models import ContentType
8 from django.db.models import Q
9 from django.utils.functional import lazy
10 from catalogue.models import Book
11 from social.models import Cite
12 from social import models
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 models.UserList.likes(user, work)
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                 ls = models.UserList.get_favorites_list(user)
38                 if ls is None:
39                     return False
40                 likes_t[2].update(
41                     ls.userlistitem_set.filter(deleted=False).filter(
42                         book_id__in=ids).values_list('book_id', flat=True))
43                 likes_t[1].update(ids)
44             return work.pk in likes_t[2]
45         return lazy(_likes, bool)()
46
47
48 def cites_for_tags(tags):
49     """Returns a QuerySet with all Cites for books with given tags."""
50     return Cite.objects.filter(book__in=Book.tagged.with_all(tags))
51
52
53 # tag_ids is never used
54 def choose_cite(book_id=None, tag_ids=None):
55     """Choose a cite for main page, for book or for set of tags."""
56     if book_id is not None:
57         cites = Cite.objects.filter(Q(book=book_id) | Q(book__ancestor=book_id))
58     elif tag_ids is not None:
59         tags = Tag.objects.filter(pk__in=tag_ids)
60         cites = cites_for_tags(tags)
61     else:
62         cites = Cite.objects.all()
63     stickies = cites.filter(sticky=True)
64     count = len(stickies)
65     if count:
66         cites = stickies
67     else:
68         count = len(cites)
69     if count:
70         cite = cites[randint(0, count - 1)]
71     else:
72         cite = None
73     return cite
74
75
76 def get_or_choose_cite(request, book_id=None, tag_ids=None):
77     try:
78         assert request.user.is_staff
79         assert 'banner' in request.GET
80         return Cite.objects.get(pk=request.GET['banner'])
81     except (AssertionError, Cite.DoesNotExist):
82         return choose_cite(book_id, tag_ids)