1 # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
 
   2 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
 
   4 from collections import defaultdict
 
   5 from random import randint
 
   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, Tag
 
  11 from catalogue import utils
 
  12 from catalogue.tasks import touch_tag
 
  13 from social.models import Cite
 
  16 def likes(user, work, request=None):
 
  17     if not user.is_authenticated:
 
  21         return work.tags.filter(category='set', user=user).exists()
 
  23     if not hasattr(request, 'social_likes'):
 
  24         # tuple: unchecked, checked, liked
 
  25         request.social_likes = defaultdict(lambda: (set(), set(), set()))
 
  27     ct = ContentType.objects.get_for_model(type(work))
 
  28     likes_t = request.social_likes[ct.pk]
 
  29     if work.pk in likes_t[1]:
 
  30         return work.pk in likes_t[2]
 
  32         likes_t[0].add(work.pk)
 
  36                 ids = tuple(likes_t[0])
 
  38                 likes_t[2].update(Tag.intermediary_table_model.objects.filter(
 
  39                     content_type_id=ct.pk, tag__user_id=user.pk,
 
  41                 ).distinct().values_list('object_id', flat=True))
 
  42                 likes_t[1].update(ids)
 
  43             return work.pk in likes_t[2]
 
  44         return lazy(_likes, bool)()
 
  47 def get_set(user, name):
 
  48     """Returns a tag for use by the user. Creates it, if necessary."""
 
  50         tag = Tag.objects.get(category='set', user=user, name=name)
 
  51     except Tag.DoesNotExist:
 
  52         tag = Tag.objects.create(
 
  53             category='set', user=user, name=name, slug=utils.get_random_hash(name), sort_key=name.lower())
 
  54     except Tag.MultipleObjectsReturned:
 
  55         # fix duplicated noname shelf
 
  56         tags = list(Tag.objects.filter(category='set', user=user, name=name))
 
  58         for other_tag in tags[1:]:
 
  59             for item in other_tag.items.all():
 
  60                 Tag.objects.remove_tag(item, other_tag)
 
  61                 Tag.objects.add_tag(item, tag)
 
  66 def set_sets(user, work, sets):
 
  67     """Set tags used for given work by a given user."""
 
  69     old_sets = list(work.tags.filter(category='set', user=user))
 
  71     work.tags = sets + list(
 
  72             work.tags.filter(~Q(category='set') | ~Q(user=user)))
 
  74     for shelf in [shelf for shelf in old_sets if shelf not in sets]:
 
  76     for shelf in [shelf for shelf in sets if shelf not in old_sets]:
 
  80     Tag.objects.filter(category='set', user=user, items=None).delete()
 
  82     if isinstance(work, Book):
 
  83         work.update_popularity()
 
  86 def cites_for_tags(tags):
 
  87     """Returns a QuerySet with all Cites for books with given tags."""
 
  88     return Cite.objects.filter(book__in=Book.tagged.with_all(tags))
 
  91 # tag_ids is never used
 
  92 def choose_cite(book_id=None, tag_ids=None):
 
  93     """Choose a cite for main page, for book or for set of tags."""
 
  94     if book_id is not None:
 
  95         cites = Cite.objects.filter(Q(book=book_id) | Q(book__ancestor=book_id))
 
  96     elif tag_ids is not None:
 
  97         tags = Tag.objects.filter(pk__in=tag_ids)
 
  98         cites = cites_for_tags(tags)
 
 100         cites = Cite.objects.all()
 
 101     stickies = cites.filter(sticky=True)
 
 102     count = len(stickies)
 
 108         cite = cites[randint(0, count - 1)]
 
 114 def get_or_choose_cite(request, book_id=None, tag_ids=None):
 
 116         assert request.user.is_staff
 
 117         assert 'banner' in request.GET
 
 118         return Cite.objects.get(pk=request.GET['banner'])
 
 119     except (AssertionError, Cite.DoesNotExist):
 
 120         return choose_cite(book_id, tag_ids)