import uuid import logging from django.shortcuts import render, get_object_or_404, redirect from django.contrib.auth.decorators import login_required, permission_required from django.utils.translation import gettext_lazy as _ from django.http import ( HttpResponseBadRequest, HttpResponseServerError, HttpResponse, HttpResponseRedirect, HttpResponseNotFound, ) from django.contrib.auth.decorators import login_required, permission_required from django.core.exceptions import ObjectDoesNotExist, PermissionDenied from django.db import IntegrityError, transaction from django.db.models import Count from django.utils import timezone from django.core.paginator import Paginator from polymorphic.base import django from catalog.common.models import ExternalResource, ItemCategory from catalog.common.sites import AbstractSite, SiteManager from mastodon import mastodon_request_included from mastodon.models import MastodonApplication from mastodon.api import share_mark, share_review from .models import * from django.conf import settings from django.utils.baseconv import base62 from journal.models import Mark, ShelfMember, Review from journal.models import ( query_visible, query_following, update_journal_for_merged_item, ) from common.utils import PageLinksGenerator from common.config import PAGE_LINK_NUMBER from journal.models import ShelfTypeNames import django_rq from rq.job import Job from .search.external import ExternalSources from .forms import * from .search.views import * from pprint import pprint _logger = logging.getLogger(__name__) NUM_REVIEWS_ON_ITEM_PAGE = 5 NUM_REVIEWS_ON_LIST_PAGE = 20 def retrieve_by_uuid(request, item_uid): item = get_object_or_404(Item, uid=item_uid) return redirect(item.url) def retrieve(request, item_path, item_uuid): if request.method == "GET": item = get_object_or_404(Item, uid=base62.decode(item_uuid)) 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_staff if not skipcheck and item.merged_to_item: return redirect(item.merged_to_item.url) if not skipcheck and item.is_deleted: return HttpResponseNotFound("item not found") mark = None review = None mark_list = None review_list = None collection_list = [] shelf_types = [ (n[1], n[2]) for n in iter(ShelfTypeNames) if n[0] == item.category ] if request.user.is_authenticated: visible = query_visible(request.user) mark = Mark(request.user, item) review = mark.review collection_list = ( item.collections.all() .filter(visible) .annotate(like_counts=Count("likes")) .order_by("-like_counts") ) mark_query = ( ShelfMember.objects.filter(item=item) .filter(visible) .order_by("-created_time") ) mark_list = [ member.mark for member in mark_query[:NUM_REVIEWS_ON_ITEM_PAGE] ] review_list = ( Review.objects.filter(item=item) .filter(visible) .order_by("-created_time")[:NUM_REVIEWS_ON_ITEM_PAGE] ) return render( request, item.class_name + ".html", { "item": item, "mark": mark, "review": review, "mark_list": mark_list, "review_list": review_list, "collection_list": collection_list, "shelf_types": shelf_types, }, ) else: return HttpResponseBadRequest() @login_required def create(request, item_model): if request.method == "GET": form_cls = CatalogForms[item_model] form = form_cls() return render( request, "catalog_edit.html", { "form": form, }, ) elif request.method == "POST": form_cls = CatalogForms[item_model] form = form_cls(request.POST, request.FILES) if form.is_valid(): form.instance.last_editor = request.user form.instance.edited_time = timezone.now() form.instance.save() return redirect(form.instance.url) else: pprint(form.errors) return HttpResponseBadRequest(form.errors) else: return HttpResponseBadRequest() @login_required def edit(request, item_path, item_uuid): if request.method == "GET": item = get_object_or_404(Item, uid=base62.decode(item_uuid)) form_cls = CatalogForms[item.__class__.__name__] form = form_cls(instance=item) if item.external_resources.all().count() > 0: form.fields["primary_lookup_id_type"].disabled = True form.fields["primary_lookup_id_value"].disabled = True return render(request, "catalog_edit.html", {"form": form, "item": item}) elif request.method == "POST": item = get_object_or_404(Item, uid=base62.decode(item_uuid)) form_cls = CatalogForms[item.__class__.__name__] form = form_cls(request.POST, request.FILES, instance=item) if item.external_resources.all().count() > 0: form.fields["primary_lookup_id_type"].disabled = True form.fields["primary_lookup_id_value"].disabled = True if form.is_valid(): form.instance.last_editor = request.user form.instance.edited_time = timezone.now() form.instance.save() return redirect(form.instance.url) else: pprint(form.errors) return HttpResponseBadRequest(form.errors) else: return HttpResponseBadRequest() @login_required def delete(request, item_path, item_uuid): if request.method != "POST": return HttpResponseBadRequest() if not request.user.is_staff: raise PermissionDenied() item = get_object_or_404(Item, uid=base62.decode(item_uuid)) for res in item.external_resources.all(): res.item = None res.save() item.delete() return ( redirect(item.url + "?skipcheck=1") if request.user.is_staff else redirect("/") ) @login_required def recast(request, item_path, item_uuid): if request.method != "POST": return HttpResponseBadRequest() if not request.user.is_staff: raise PermissionDenied() item = get_object_or_404(Item, uid=base62.decode(item_uuid)) cls = request.POST.get("class") model = TVShow if cls == "tvshow" else (Movie if cls == "movie" else None) if not model: return HttpResponseBadRequest("invalid class") new_item = item.recast_to(model) return redirect(new_item.url) @login_required def unlink(request): if request.method != "POST": return HttpResponseBadRequest() if not request.user.is_staff: raise PermissionDenied() res_id = request.POST.get("id") if not res_id: return HttpResponseBadRequest() resource = get_object_or_404(ExternalResource, id=res_id) resource.item = None resource.save() return HttpResponseRedirect(request.META.get("HTTP_REFERER")) @login_required def merge(request, item_path, item_uuid): if request.method != "POST": return HttpResponseBadRequest() if not request.user.is_staff: raise PermissionDenied() item = get_object_or_404(Item, uid=base62.decode(item_uuid)) new_item = Item.get_by_url(request.POST.get("new_item_url")) if not new_item or new_item.is_deleted or new_item.merged_to_item_id: return HttpResponseBadRequest(b"invalid new item") _logger.warn(f"{request.user} merges {item} to {new_item}") item.merge_to(new_item) update_journal_for_merged_item(item_uuid) return redirect(new_item.url) @login_required def mark_list(request, item_path, item_uuid, following_only=False): item = get_object_or_404(Item, uid=base62.decode(item_uuid)) if not item: return HttpResponseNotFound(b"item not found") queryset = ShelfMember.objects.filter(item=item).order_by("-created_time") if following_only: queryset = queryset.filter(query_following(request.user)) else: queryset = queryset.filter(query_visible(request.user)) paginator = Paginator(queryset, NUM_REVIEWS_ON_LIST_PAGE) page_number = request.GET.get("page", default=1) marks = paginator.get_page(page_number) marks.pagination = PageLinksGenerator( PAGE_LINK_NUMBER, page_number, paginator.num_pages ) return render( request, "item_mark_list.html", { "marks": marks, "item": item, }, ) def review_list(request, item_path, item_uuid): item = get_object_or_404(Item, uid=base62.decode(item_uuid)) if not item: return HttpResponseNotFound(b"item not found") queryset = Review.objects.filter(item=item).order_by("-created_time") queryset = queryset.filter(query_visible(request.user)) paginator = Paginator(queryset, NUM_REVIEWS_ON_LIST_PAGE) page_number = request.GET.get("page", default=1) reviews = paginator.get_page(page_number) reviews.pagination = PageLinksGenerator( PAGE_LINK_NUMBER, page_number, paginator.num_pages ) return render( request, "item_review_list.html", { "reviews": reviews, "item": item, }, )