from django.contrib.auth.decorators import login_required from django.core.cache import cache from django.core.paginator import Paginator from django.db.models import Count from django.http import Http404 from django.shortcuts import get_object_or_404, redirect, render from django.urls import reverse from django.utils import timezone from django.utils.translation import gettext as _ from django.views.decorators.clickjacking import xframe_options_exempt from django.views.decorators.http import require_http_methods from common.utils import ( CustomPaginator, PageLinksGenerator, get_uuid_or_404, user_identity_required, ) from journal.models import ( Collection, Comment, Mark, Review, ShelfManager, ShelfMember, ShelfType, q_piece_in_home_feed_of_user, q_piece_visible_to_user, ) from takahe.utils import Takahe from users.views import announcements from .forms import * from .models import * from .search.views import * from .views_edit import * NUM_COMMENTS_ON_ITEM_PAGE = 10 def retrieve_by_uuid(request, item_uid): item = get_object_or_404(Item, uid=item_uid) return redirect(item.url) def retrieve_redirect(request, item_path, item_uuid): return redirect(f"/{item_path}/{item_uuid}", permanent=True) @require_http_methods(["GET"]) @xframe_options_exempt def embed(request, item_path, item_uuid): item = Item.get_by_url(item_uuid) if item is None: raise Http404(_("Item not found")) if item.merged_to_item: return redirect(item.merged_to_item.url) if item.is_deleted: raise Http404(_("Item no longer exists")) focus_item = None if request.GET.get("focus"): focus_item = get_object_or_404( Item, uid=get_uuid_or_404(request.GET.get("focus")) ) return render( request, "embed_" + item.class_name + ".html", {"item": item, "focus_item": focus_item}, ) @require_http_methods(["GET", "HEAD"]) @user_identity_required def retrieve(request, item_path, item_uuid): # item = get_object_or_404(Item, uid=get_uuid_or_404(item_uuid)) item = Item.get_by_url(item_uuid) if item is None: raise Http404(_("Item not found")) item_url = f"/{item_path}/{item_uuid}" if item.url != item_url: return redirect(item.url) skipcheck = request.GET.get("skipcheck", False) and request.user.is_authenticated if not skipcheck and item.merged_to_item: return redirect(item.merged_to_item.url) if not skipcheck and item.is_deleted: raise Http404(_("Item no longer exists")) if request.headers.get("Accept", "").endswith("json"): return redirect(item.api_url) focus_item = None if request.GET.get("focus"): focus_item = get_object_or_404( Item, uid=get_uuid_or_404(request.GET.get("focus")) ) mark = None review = None my_collections = [] collection_list = [] child_item_comments = [] shelf_actions = ShelfManager.get_actions_for_category(item.category) shelf_statuses = ShelfManager.get_statuses_for_category(item.category) if request.user.is_authenticated: visible = q_piece_visible_to_user(request.user) mark = Mark(request.user.identity, item) child_item_comments = Comment.objects.filter( owner=request.user.identity, item__in=item.child_items.all() ) review = mark.review my_collections = item.collections.all().filter(owner=request.user.identity) collection_list = ( item.collections.all() .exclude(owner=request.user.identity) .filter(visible) .annotate(like_counts=Count("likes")) .order_by("-like_counts") ) else: collection_list = ( item.collections.all() .filter(visibility=0) .annotate(like_counts=Count("likes")) .order_by("-like_counts") ) return render( request, item.class_name + ".html", { "item": item, "focus_item": focus_item, "mark": mark, "review": review, "child_item_comments": child_item_comments, "my_collections": my_collections, "collection_list": collection_list, "shelf_actions": shelf_actions, "shelf_statuses": shelf_statuses, }, ) def episode_data(request, item_uuid): item = get_object_or_404(Podcast, uid=get_uuid_or_404(item_uuid)) qs = item.episodes.all().order_by("-pub_date") if request.GET.get("last"): qs = qs.filter(pub_date__lt=request.GET.get("last")) return render( request, "podcast_episode_data.html", {"item": item, "episodes": qs[:5]} ) @login_required def mark_list(request, item_path, item_uuid, following_only=False): item = get_object_or_404(Item, uid=get_uuid_or_404(item_uuid)) queryset = ShelfMember.objects.filter(item=item).order_by("-created_time") if following_only: queryset = queryset.filter(q_piece_in_home_feed_of_user(request.user)) else: queryset = queryset.filter(q_piece_visible_to_user(request.user)) paginator = CustomPaginator(queryset, request) page_number = request.GET.get("page", default=1) marks = paginator.get_page(page_number) pagination = PageLinksGenerator(page_number, paginator.num_pages, request.GET) return render( request, "item_mark_list.html", { "marks": marks, "item": item, "followeing_only": following_only, "pagination": pagination, }, ) def review_list(request, item_path, item_uuid): item = get_object_or_404(Item, uid=get_uuid_or_404(item_uuid)) queryset = Review.objects.filter(item=item).order_by("-created_time") queryset = queryset.filter(q_piece_visible_to_user(request.user)) paginator = CustomPaginator(queryset, request) page_number = request.GET.get("page", default=1) reviews = paginator.get_page(page_number) pagination = PageLinksGenerator(page_number, paginator.num_pages, request.GET) return render( request, "item_review_list.html", { "reviews": reviews, "item": item, "pagination": pagination, }, ) def comments(request, item_path, item_uuid): item = get_object_or_404(Item, uid=get_uuid_or_404(item_uuid)) ids = item.child_item_ids + [item.pk] + item.sibling_item_ids queryset = Comment.objects.filter(item_id__in=ids).order_by("-created_time") queryset = queryset.filter(q_piece_visible_to_user(request.user)) before_time = request.GET.get("last") if before_time: queryset = queryset.filter(created_time__lte=before_time) return render( request, "_item_comments.html", { "item": item, "comments": queryset[: NUM_COMMENTS_ON_ITEM_PAGE + 1], }, ) def comments_by_episode(request, item_path, item_uuid): item = get_object_or_404(Item, uid=get_uuid_or_404(item_uuid)) episode_uuid = request.GET.get("episode_uuid") if episode_uuid: episode = TVEpisode.get_by_url(episode_uuid) ids = [episode.pk] if episode else [] else: ids = item.child_item_ids queryset = Comment.objects.filter(item_id__in=ids).order_by("-created_time") queryset = queryset.filter(q_piece_visible_to_user(request.user)) before_time = request.GET.get("last") if before_time: queryset = queryset.filter(created_time__lte=before_time) return render( request, "_item_comments_by_episode.html", { "item": item, "episode_uuid": episode_uuid, "comments": queryset[: NUM_COMMENTS_ON_ITEM_PAGE + 1], }, ) def reviews(request, item_path, item_uuid): item = get_object_or_404(Item, uid=get_uuid_or_404(item_uuid)) ids = item.child_item_ids + [item.pk] + item.sibling_item_ids queryset = Review.objects.filter(item_id__in=ids).order_by("-created_time") queryset = queryset.filter(q_piece_visible_to_user(request.user)) before_time = request.GET.get("last") if before_time: queryset = queryset.filter(created_time__lte=before_time) return render( request, "_item_reviews.html", { "item": item, "reviews": queryset[: NUM_COMMENTS_ON_ITEM_PAGE + 1], }, ) @require_http_methods(["GET", "HEAD"]) def discover(request): cache_key = "public_gallery" gallery_list = cache.get(cache_key, []) # rotate every 6 minutes rot = timezone.now().minute // 6 for gallery in gallery_list: i = rot * len(gallery["items"]) // 10 gallery["items"] = gallery["items"][i:] + gallery["items"][:i] if request.user.is_authenticated: if not request.user.registration_complete: return redirect(reverse("users:register")) layout = request.user.preference.discover_layout identity = request.user.identity announcements = [] if settings.DISCOVER_SHOW_POPULAR_POSTS: post_ids = cache.get("popular_posts", []) popular_posts = Takahe.get_posts(post_ids).order_by("-published") else: popular_posts = Takahe.get_public_posts(settings.DISCOVER_SHOW_LOCAL_ONLY)[ :20 ] else: identity = None layout = [] announcements = Takahe.get_announcements() popular_posts = [] collection_ids = cache.get("featured_collections", []) if collection_ids: i = rot * len(collection_ids) // 10 collection_ids = collection_ids[i:] + collection_ids[:i] featured_collections = Collection.objects.filter(pk__in=collection_ids) else: featured_collections = [] popular_tags = cache.get("popular_tags", []) return render( request, "discover.html", { "identity": identity, "all_announcements": announcements, "gallery_list": gallery_list, "featured_collections": featured_collections, "popular_tags": popular_tags, "popular_posts": popular_posts, "layout": layout, }, )