from django.shortcuts import redirect from django.urls import reverse from django.views.generic import TemplateView from django.contrib.auth.mixins import LoginRequiredMixin from django.db.models import Q, Count, OuterRef, Sum from django.db.models.functions import Coalesce from django.http import HttpResponse, Http404, StreamingHttpResponse from rest_framework.viewsets import GenericViewSet from rest_framework import mixins from rest_framework.response import Response from rest_framework.decorators import action import anyio from app.utils import StreamingZipFileResponse from user.models import User from .models import Torrent, File, SharedUser from .serializers import TorrentSerializer, FileSerializer from .utils import torrent_proceed, torrent_share class HomeView(LoginRequiredMixin, TemplateView): template_name = "torrent/home.html" def pping(request): return HttpResponse(str(dict(request.session))) async def download_file(request, file_id): user = await request.auser() qs = File.objects.filter( Q(torrent__user=user) | Q(torrent__shared_users=user) | Q(torrent__user__friends=user) | Q(torrent__shared_users__friends=user), torrent__transmission_data__progress__gte=100, pk=file_id ).distinct() try: file = await qs.aget() except File.DoesNotExist: raise Http404() else: if int(request.GET.get("dl_hotfix", 0)) == 1: async def read_file(): async with await anyio.open_file(file.abs_pathname, "rb") as f: while chunk := await f.read(128 * 1024): yield chunk response = StreamingHttpResponse(read_file()) response["Content-Length"] = file.size response["Content-Type"] = "application/octet-stream" response["Content-Disposition"] = file.disposition return response else: response = HttpResponse() response["X-Accel-Redirect"] = file.accel_redirect response["Content-Type"] = file.mime_types response["Content-Disposition"] = file.disposition return response async def flux_file(request, file_id): user = await request.auser() qs = File.objects.filter( Q(torrent__user=user) | Q(torrent__shared_users=user) | Q(torrent__user__friends=user) | Q(torrent__shared_users__friends=user), torrent__transmission_data__progress__gte=100, pk=file_id ).distinct() try: file = await qs.aget() except File.DoesNotExist: raise Http404() else: response = HttpResponse() response["X-Accel-Redirect"] = file.accel_redirect response["X-Accel-Buffering"] = "no" response["Content-Type"] = file.mime_types response["Content-Disposition"] = file.disposition return response async def download_torrent(request, torrent_id): # py version user = await request.auser() qs = Torrent.objects.filter( Q(user=user) | Q(shared_users=user) | Q(user__friends=user) | Q(shared_users__friends=user), transmission_data__progress__gte=100, pk=torrent_id ).annotate(count_files=Count("files")).distinct() torrent = await qs.aget() if await torrent.alen_files == 1: file = await torrent.files.afirst() return redirect(reverse("torrent:download_file", kwargs={ "file_id": file.pk })) response = StreamingZipFileResponse( filename="test.zip", file_list=[ (file.abs_pathname, file.rel_name) async for file in torrent.files.all() ], is_async=True ) return response class TorrentViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, GenericViewSet): queryset = Torrent.objects.all().annotate(count_files=Count("files")) serializer_class = TorrentSerializer def get_queryset(self): qs = super().get_queryset() qs.filter( Q(user=self.request.user) | Q(shared_users=self.request.user) | Q(user__friends=self.request.user) | Q(shared_users__friends=self.request.user) ) # Récupération des torrents de l'utilisateur et de ceux partagé à celui-ci (ordonné par ordre de partage ou par date d'ajout du torrent) user_id = self.request.query_params.get("user", None) if user_id: qs = qs.filter(Q(user_id=user_id) | Q(shared_users=user_id)) else: user_id = self.request.user.id sub = SharedUser.objects.filter(torrent_id=OuterRef("pk"), user_id=user_id).values("date_created") qs = qs.annotate(last_date=Coalesce(sub, "date_created")).order_by("-last_date") search = self.request.query_params.get("search", None) if search: qs = qs.filter(name__icontains=search) return qs def create(self, request, *args, **kwargs): file = request.data["file"] file_mode = request.data.get("file_mode", "file_object") r = torrent_proceed(self.request.user, file, file_mode) if r["torrent"]: r["torrent"] = self.get_serializer_class()(r["torrent"]).data return Response(r) def perform_destroy(self, instance): instance: Torrent if instance.user == self.request.user: return super().perform_destroy(instance) else: if instance.shared_users.filter(id=self.request.user.id).exists(): instance.shared_users.remove(self.request.user) @action(methods=["post"], detail=True) def share(self, request, pk): user_id = self.request.data.get("user_id") torrent = self.get_object() is_share_success = torrent_share(torrent=torrent, current_user=self.request.user, target_user_id=user_id) return Response({"success": is_share_success}) @action(methods=["get"], detail=False) def user_stats(self, request): Torrent.objects.filter(user=self.request.user).aggregate(total_size=Sum("size")) class FileViewSet(mixins.RetrieveModelMixin, mixins.ListModelMixin, GenericViewSet): queryset = File.objects.all() serializer_class = FileSerializer filterset_fields = ["torrent"] def get_queryset(self): qs = super().get_queryset() return qs