This commit is contained in:
2025-04-18 17:33:48 +02:00
parent 26fb8b1678
commit 57346dd811
10 changed files with 757 additions and 19 deletions

View File

@@ -1,3 +1,67 @@
from django.test import TestCase
from django.urls import reverse
from rest_framework.test import APITestCase, APIClient
from rest_framework import status
# Create your tests here.
from .routers import router
class RouterTestCase(TestCase):
def test_router_urls(self):
"""Test that the router generates the expected URL patterns"""
url_patterns = router.urls
# Check that all expected viewsets are registered
expected_basenames = ['user', 'torrent', 'file', 'friend-request']
registered_basenames = [url.name.split('-')[0] for url in url_patterns if '-list' in url.name]
for basename in expected_basenames:
self.assertIn(basename, registered_basenames)
# Check that list and detail URLs are generated for each viewset
for basename in expected_basenames:
list_url_name = f"{basename}-list"
detail_url_name = f"{basename}-detail"
self.assertTrue(any(url.name == list_url_name for url in url_patterns))
self.assertTrue(any(url.name == detail_url_name for url in url_patterns))
class APIEndpointsTestCase(APITestCase):
def setUp(self):
from user.models import User
# Create a test user
self.user = User.objects.create_user(
username='testuser',
email='test@example.com',
password='testpassword'
)
# Authenticate the client
self.client = APIClient()
self.client.force_authenticate(user=self.user)
def test_user_endpoint(self):
"""Test that the users endpoint is accessible"""
url = reverse('user-list')
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_torrent_endpoint(self):
"""Test that the torrents endpoint is accessible"""
url = reverse('torrent-list')
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_file_endpoint(self):
"""Test that the files endpoint is accessible"""
url = reverse('file-list')
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_friend_request_endpoint(self):
"""Test that the friend requests endpoint is accessible"""
url = reverse('friendrequest-list')
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)

View File

@@ -15,7 +15,7 @@
<v-divider/>
<UserStats :stats="user_stats"/>
<v-divider/>
{{dm_status}}
<!-- {{dm_status}}-->
<DM v-if="dm_activated" :dm_files="dm_files" :dm_status="dm_status" :dm_download_location="dm_download_location"/>
</v-navigation-drawer>
<v-navigation-drawer v-model="right_drawer" location="right" temporary>
@@ -157,6 +157,7 @@ export default {
this.dm_status = data;
})
this.$qt.on("upload_torrent", data => {
console.log(typeof data);
this.uploadTorrentB64(data);
})
this.$qt.on("files_updated", data => {
@@ -220,7 +221,8 @@ export default {
},
async uploadTorrentB64(b64_torrent){
let form = new FormData();
form.append("torrent", b64_torrent);
form.append("file", b64_torrent);
form.append("file_mode", "base64");
let response = await fetch("/api/torrents/", {
method: "POST",
headers: {

View File

@@ -6,12 +6,19 @@
</v-dialog>
<v-list-item
:prepend-icon="dm_status.pause ? 'mdi-play' : 'mdi-pause'"
@click="$qt.callMethod('set_pause', !dm_status.pause)"
@click="setPause(!dm_status.pause)"
:disabled="!start_available"
>
<template v-slot:title>
{{ dm_status.pause ? 'Start':'Pause' }}
</template>
</v-list-item>
<v-list-item
prepend-icon="mdi-delete-sweep"
:disabled="!dm_status.pause"
@click="$qt.callMethod('del_files', Object.keys(dm_files))"
title="Clear"
/>
<v-list-item prepend-icon="mdi-speedometer">
<template v-slot:title>
{{fs_speed_format(dm_status.speed)}}/s
@@ -42,7 +49,7 @@ import {fs_format, fs_speed_format} from "@/plugins/utils.js";
export default {
methods: {fs_format, fs_speed_format},
props: {
dm_files: {
required: true,
@@ -60,6 +67,20 @@ export default {
data(){
return {
details_enabled: false,
start_available: true
}
},
methods: {
fs_format, fs_speed_format,
setPause(pause){
this.start_available = false
this.$qt.callMethod('set_pause', pause);
if(pause){
setTimeout(() => {this.start_available = true;}, 1000);
}else{
this.start_available = true;
}
}
},
computed: {

View File

@@ -14,8 +14,8 @@
{{ file.rel_path }}
</template>
<template v-slot:subtitle>
<v-progress-linear
:model-value="file.stats.percent" height="12" color="blue">
<v-progress-linear :model-value="file.stats.percent" height="14" color="blue">
{{file.stats.percent.toFixed(1)}}% ({{fs_speed_format(file.stats.speed)}}/s)
</v-progress-linear>
</template>
</v-list-item>
@@ -97,9 +97,10 @@ export default {
for(const [file_id, file] of Object.entries(this.dm_files)){
if(file.downloaded){
finished[file_id] = file;
}else if(file_id in this.dm_status.downloading){
}else if(this.dm_status.downloading.includes(file_id)){
downloading[file_id] = file;
if(file_id in this.dm_status["downloader_stats"]){
downloading[file_id]["stats"] = this.dm_status["downloader_stats"][file_id];
}else{
downloading[file_id]["stats"] = {

View File

@@ -1,3 +1,328 @@
from django.test import TestCase
from django.urls import reverse
from rest_framework.test import APITestCase, APIClient
from rest_framework import status
from django.conf import settings
from unittest.mock import patch, MagicMock
# Create your tests here.
from .models import Torrent, SharedUser, File
from user.models import User
from .views import TorrentViewSet, FileViewSet
from .utils import Transmission, torrent_proceed, torrent_share
class TorrentModelTestCase(TestCase):
def setUp(self):
self.user = User.objects.create_user(
username='testuser',
email='test@example.com',
password='testpassword'
)
self.torrent = Torrent.objects.create(
id='abc123',
name='Test Torrent',
user=self.user,
size=1000,
transmission_data={}
)
self.shared_user = User.objects.create_user(
username='shareduser',
email='shared@example.com',
password='sharedpassword'
)
self.file = File.objects.create(
torrent=self.torrent,
rel_name='test_file.txt',
size=100
)
def test_len_files(self):
"""Test the len_files property returns the correct count of files"""
self.assertEqual(self.torrent.len_files, 1)
# Add another file and test again
File.objects.create(
torrent=self.torrent,
rel_name='another_file.txt',
size=200
)
# Clear cached_property
if hasattr(self.torrent, '_len_files'):
delattr(self.torrent, '_len_files')
self.assertEqual(self.torrent.len_files, 2)
def test_related_users(self):
"""Test the related_users property returns the correct list of users"""
# Initially only the owner
self.assertEqual(self.torrent.related_users, [self.user.id])
# Add a shared user
self.torrent.shared_users.add(self.shared_user)
# Clear cached_property
if hasattr(self.torrent, '_related_users'):
delattr(self.torrent, '_related_users')
# Should include both users now
self.assertIn(self.user.id, self.torrent.related_users)
self.assertIn(self.shared_user.id, self.torrent.related_users)
class FileModelTestCase(TestCase):
def setUp(self):
self.user = User.objects.create_user(
username='testuser',
email='test@example.com',
password='testpassword'
)
self.torrent = Torrent.objects.create(
id='abc123',
name='Test Torrent',
user=self.user,
size=1000,
transmission_data={}
)
self.file = File.objects.create(
torrent=self.torrent,
rel_name='test/path/file.mp4',
size=100
)
def test_pathname(self):
"""Test the pathname property returns the correct path"""
self.assertEqual(str(self.file.pathname), 'test/path/file.mp4')
def test_filename(self):
"""Test the filename property returns the correct filename"""
self.assertEqual(self.file.filename, 'file.mp4')
def test_abs_pathname(self):
"""Test the abs_pathname property returns the correct absolute path"""
expected_path = settings.DOWNLOAD_BASE_DIR / self.file.pathname
self.assertEqual(self.file.abs_pathname, expected_path)
def test_is_video(self):
"""Test the is_video property correctly identifies video files"""
self.assertTrue(self.file.is_video) # mp4 should be identified as video
# Test non-video file
non_video_file = File.objects.create(
torrent=self.torrent,
rel_name='test/path/document.pdf',
size=50
)
self.assertFalse(non_video_file.is_video)
class SharedUserModelTestCase(TestCase):
def setUp(self):
self.owner = User.objects.create_user(
username='owner',
email='owner@example.com',
password='ownerpassword'
)
self.shared_user = User.objects.create_user(
username='shareduser',
email='shared@example.com',
password='sharedpassword'
)
self.torrent = Torrent.objects.create(
id='abc123',
name='Test Torrent',
user=self.owner,
size=1000,
transmission_data={}
)
def test_shared_user_creation(self):
"""Test creating a shared user relationship"""
shared = SharedUser.objects.create(
user=self.shared_user,
torrent=self.torrent
)
self.assertEqual(shared.user, self.shared_user)
self.assertEqual(shared.torrent, self.torrent)
# Verify the relationship is reflected in the torrent's shared_users
self.assertIn(self.shared_user, self.torrent.shared_users.all())
class TorrentViewSetTestCase(APITestCase):
def setUp(self):
self.user = User.objects.create_user(
username='testuser',
email='test@example.com',
password='testpassword'
)
self.client = APIClient()
self.client.force_authenticate(user=self.user)
self.torrent = Torrent.objects.create(
id='abc123',
name='Test Torrent',
user=self.user,
size=1000,
transmission_data={}
)
self.file = File.objects.create(
torrent=self.torrent,
rel_name='test_file.txt',
size=100
)
def test_list_torrents(self):
"""Test listing torrents"""
url = reverse('torrent-list')
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data), 1)
self.assertEqual(response.data[0]['id'], self.torrent.id)
def test_retrieve_torrent(self):
"""Test retrieving a specific torrent"""
url = reverse('torrent-detail', args=[self.torrent.id])
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['id'], self.torrent.id)
self.assertEqual(response.data['name'], 'Test Torrent')
@patch('torrent.views.torrent_share')
def test_share_torrent(self, mock_torrent_share):
"""Test sharing a torrent with another user"""
mock_torrent_share.return_value = True
shared_user = User.objects.create_user(
username='shareduser',
email='shared@example.com',
password='sharedpassword'
)
url = reverse('torrent-share', args=[self.torrent.id])
response = self.client.post(url, {'user_id': shared_user.id})
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertTrue(response.data['success'])
mock_torrent_share.assert_called_once()
class FileViewSetTestCase(APITestCase):
def setUp(self):
self.user = User.objects.create_user(
username='testuser',
email='test@example.com',
password='testpassword'
)
self.client = APIClient()
self.client.force_authenticate(user=self.user)
self.torrent = Torrent.objects.create(
id='abc123',
name='Test Torrent',
user=self.user,
size=1000,
transmission_data={}
)
self.file = File.objects.create(
torrent=self.torrent,
rel_name='test_file.txt',
size=100
)
def test_list_files(self):
"""Test listing files"""
url = reverse('file-list')
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_retrieve_file(self):
"""Test retrieving a specific file"""
url = reverse('file-detail', args=[self.file.id])
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['id'], str(self.file.id))
self.assertEqual(response.data['rel_name'], 'test_file.txt')
class TransmissionUtilsTestCase(TestCase):
@patch('torrent.utils.Client')
def test_transmission_init(self, mock_client):
"""Test Transmission class initialization"""
transmission = Transmission()
mock_client.assert_called_once_with(**settings.TRANSMISSION)
@patch('torrent.utils.Client')
def test_add_torrent(self, mock_client):
"""Test adding a torrent"""
mock_instance = mock_client.return_value
mock_instance.add_torrent.return_value = MagicMock()
transmission = Transmission()
file_obj = MagicMock()
result = transmission.add_torrent(file_obj)
mock_instance.add_torrent.assert_called_once_with(file_obj)
self.assertEqual(result, mock_instance.add_torrent.return_value)
@patch('torrent.utils.Client')
def test_get_data(self, mock_client):
"""Test getting torrent data"""
mock_instance = mock_client.return_value
mock_torrent = MagicMock()
mock_torrent.progress = 50
mock_torrent.fields = {'name': 'Test', 'size': 1000}
mock_instance.get_torrent.return_value = mock_torrent
transmission = Transmission()
result = transmission.get_data('hash123')
mock_instance.get_torrent.assert_called_once_with('hash123', transmission.trpc_args)
self.assertEqual(result['progress'], 50)
self.assertEqual(result['name'], 'Test')
self.assertEqual(result['size'], 1000)
class TorrentProceedTestCase(TestCase):
def setUp(self):
self.user = User.objects.create_user(
username='testuser',
email='test@example.com',
password='testpassword',
max_size=10000
)
@patch('torrent.utils.transmission_handler')
def test_torrent_proceed_size_exceed(self, mock_transmission):
"""Test torrent_proceed when user size is exceeded"""
# Set user's used size to exceed max_size
self.user.max_size = 100
Torrent.objects.create(
id='abc123',
name='Test Torrent',
user=self.user,
size=200, # Exceeds max_size
transmission_data={}
)
file_obj = MagicMock()
result = torrent_proceed(self.user, file_obj)
self.assertEqual(result['status'], 'error')
self.assertEqual(result['message'], 'Size exceed')
mock_transmission.add_torrent.assert_not_called()
@patch('torrent.utils.transmission_handler')
def test_torrent_proceed_transmission_error(self, mock_transmission):
"""Test torrent_proceed when transmission raises an error"""
from transmission_rpc.error import TransmissionError
mock_transmission.add_torrent.side_effect = TransmissionError('Test error')
file_obj = MagicMock()
result = torrent_proceed(self.user, file_obj)
self.assertEqual(result['status'], 'error')
self.assertEqual(result['message'], 'Transmission Error')

View File

@@ -1,6 +1,9 @@
from django.conf import settings
import traceback
import base64
import io
from transmission_rpc import Client
from transmission_rpc.error import TransmissionError
@@ -18,8 +21,15 @@ class Transmission:
def __init__(self):
self.client = Client(**settings.TRANSMISSION)
def add_torrent(self, file):
return self.client.add_torrent(file)
def add_torrent(self, file, file_mode="file_object"):
match file_mode:
case "file_object":
return self.client.add_torrent(file)
case "base64":
file_content = base64.b64decode(file)
file_obj = io.BytesIO(file_content)
return self.client.add_torrent(file_obj)
return None
def get_data(self, hash_string):
data = self.client.get_torrent(hash_string, self.trpc_args)
@@ -45,7 +55,7 @@ class Transmission:
transmission_handler = Transmission()
def torrent_proceed(user, file):
def torrent_proceed(user, file, file_mode="file_object"):
r = {
"torrent": None,
"status": "error",
@@ -58,7 +68,7 @@ def torrent_proceed(user, file):
return r
try:
torrent_uploaded = transmission_handler.add_torrent(file)
torrent_uploaded = transmission_handler.add_torrent(file, file_mode=file_mode)
except TransmissionError:
print(traceback.format_exc())
r["message"] = "Transmission Error"
@@ -74,7 +84,7 @@ def torrent_proceed(user, file):
if torrent.user == user:
r["message"] = "Already exist"
return r
elif torrent.shared_users.filter(user=user).exists():
elif torrent.shared_users.filter(id=user.id).exists():
r["message"] = "Already shared"
return r
else:

View File

@@ -2,7 +2,7 @@ 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
from django.db.models import Q, Count, OuterRef, Sum
from django.db.models.functions import Coalesce
from django.http import HttpResponse, Http404, StreamingHttpResponse
@@ -152,7 +152,9 @@ class TorrentViewSet(mixins.CreateModelMixin,
def create(self, request, *args, **kwargs):
file = request.data["file"]
r = torrent_proceed(self.request.user, 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)

View File

@@ -1,3 +1,316 @@
from django.test import TestCase
from django.urls import reverse
from rest_framework.test import APITestCase, APIClient
from rest_framework import status
from unittest.mock import patch, MagicMock
# Create your tests here.
from .models import User, FriendRequest, Invitation, UsernameUserManager
from torrent.models import Torrent
from .views import UserViewSet, FriendRequestViewSet
class UserModelTestCase(TestCase):
def setUp(self):
self.user = User.objects.create_user(
username='testuser',
email='test@example.com',
password='testpassword',
max_size=1000000
)
self.friend = User.objects.create_user(
username='frienduser',
email='friend@example.com',
password='friendpassword'
)
def test_size_used_property(self):
"""Test the size_used property returns the correct total size of user's torrents"""
# Initially no torrents, so size should be 0
self.assertEqual(self.user.size_used, 0)
# Create a torrent for the user
Torrent.objects.create(
id='abc123',
name='Test Torrent',
user=self.user,
size=5000,
transmission_data={}
)
# Create another torrent
Torrent.objects.create(
id='def456',
name='Another Torrent',
user=self.user,
size=3000,
transmission_data={}
)
# Clear cached_property if it exists
if hasattr(self.user, 'total_size'):
delattr(self.user, 'total_size')
# Size used should be the sum of torrent sizes
self.assertEqual(self.user.size_used, 8000)
def test_min_infos_property(self):
"""Test the min_infos property returns the correct user info"""
expected_info = {
'username': 'testuser',
'id': self.user.id
}
self.assertEqual(self.user.min_infos, expected_info)
class UsernameUserManagerTestCase(TestCase):
def test_create_user(self):
"""Test creating a regular user"""
user = User.objects.create_user(
username='newuser',
email='new@example.com',
password='newpassword'
)
self.assertFalse(user.is_staff)
self.assertFalse(user.is_superuser)
self.assertEqual(user.username, 'newuser')
self.assertEqual(user.email, 'new@example.com')
self.assertTrue(user.check_password('newpassword'))
def test_create_superuser(self):
"""Test creating a superuser"""
admin = User.objects.create_superuser(
username='admin',
email='admin@example.com',
password='adminpassword'
)
self.assertTrue(admin.is_staff)
self.assertTrue(admin.is_superuser)
self.assertEqual(admin.username, 'admin')
self.assertEqual(admin.email, 'admin@example.com')
def test_create_user_without_username(self):
"""Test creating a user without username raises error"""
with self.assertRaises(ValueError):
User.objects.create_user(
username='',
email='test@example.com',
password='testpassword'
)
def test_create_user_without_email(self):
"""Test creating a user without email raises error"""
with self.assertRaises(ValueError):
User.objects.create_user(
username='testuser',
email='',
password='testpassword'
)
class FriendRequestModelTestCase(TestCase):
def setUp(self):
self.sender = User.objects.create_user(
username='sender',
email='sender@example.com',
password='senderpassword'
)
self.receiver = User.objects.create_user(
username='receiver',
email='receiver@example.com',
password='receiverpassword'
)
def test_friend_request_creation(self):
"""Test creating a friend request"""
friend_request = FriendRequest.objects.create(
sender=self.sender,
receiver=self.receiver
)
self.assertEqual(friend_request.sender, self.sender)
self.assertEqual(friend_request.receiver, self.receiver)
def test_unique_together_constraint(self):
"""Test that the unique_together constraint works"""
FriendRequest.objects.create(
sender=self.sender,
receiver=self.receiver
)
# Creating another request with the same sender and receiver should raise an error
with self.assertRaises(Exception):
FriendRequest.objects.create(
sender=self.sender,
receiver=self.receiver
)
class InvitationModelTestCase(TestCase):
def setUp(self):
self.creator = User.objects.create_user(
username='creator',
email='creator@example.com',
password='creatorpassword'
)
def test_invitation_creation(self):
"""Test creating an invitation"""
invitation = Invitation.objects.create(
created_by=self.creator
)
self.assertEqual(invitation.created_by, self.creator)
self.assertIsNotNone(invitation.token)
self.assertIsNone(invitation.user)
def test_invitation_assignment(self):
"""Test assigning an invitation to a user"""
invitation = Invitation.objects.create(
created_by=self.creator
)
new_user = User.objects.create_user(
username='newuser',
email='new@example.com',
password='newpassword'
)
invitation.user = new_user
invitation.save()
# Refresh from database
invitation.refresh_from_db()
self.assertEqual(invitation.user, new_user)
class UserViewSetTestCase(APITestCase):
def setUp(self):
self.user = User.objects.create_user(
username='testuser',
email='test@example.com',
password='testpassword'
)
self.friend = User.objects.create_user(
username='frienduser',
email='friend@example.com',
password='friendpassword'
)
self.client = APIClient()
self.client.force_authenticate(user=self.user)
def test_list_users(self):
"""Test listing users"""
url = reverse('user-list')
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data), 2) # Should include both users
def test_retrieve_user(self):
"""Test retrieving a specific user"""
url = reverse('user-detail', args=[self.friend.id])
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['username'], 'frienduser')
def test_add_friend_request(self):
"""Test adding a friend request"""
url = reverse('user-add-friend-request', args=[self.friend.username])
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertTrue(response.data['success'])
self.assertEqual(response.data['message'], 'Request sent')
# Verify the friend request was created
self.assertTrue(FriendRequest.objects.filter(
sender=self.user,
receiver=self.friend
).exists())
def test_add_friend_request_nonexistent_user(self):
"""Test adding a friend request to a nonexistent user"""
url = reverse('user-add-friend-request', args=['nonexistentuser'])
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertFalse(response.data['success'])
self.assertEqual(response.data['message'], "User 'nonexistentuser' doesn't exist")
def test_remove_friend(self):
"""Test removing a friend"""
# First add as friend
self.user.friends.add(self.friend)
url = reverse('user-remove-friend', args=[self.friend.id])
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertTrue(response.data['success'])
# Verify the friend was removed
self.assertFalse(self.user.friends.filter(id=self.friend.id).exists())
@patch('user.views.shutil.disk_usage')
def test_user_stats(self, mock_disk_usage):
"""Test getting user stats"""
# Mock disk_usage return value
mock_disk_usage.return_value = MagicMock(
total=1000000,
used=500000,
free=500000
)
# Create torrents for the user
Torrent.objects.create(
id='abc123',
name='Test Torrent',
user=self.user,
size=5000,
transmission_data={}
)
url = reverse('user-user-stats')
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
# Check that the response contains the expected fields
self.assertIn('torrents_size', response.data)
self.assertIn('torrents_len', response.data)
self.assertIn('user_max_size', response.data)
self.assertIn('disk_total', response.data)
self.assertIn('disk_used', response.data)
self.assertIn('disk_free', response.data)
class FriendRequestViewSetTestCase(APITestCase):
def setUp(self):
self.user = User.objects.create_user(
username='testuser',
email='test@example.com',
password='testpassword'
)
self.sender = User.objects.create_user(
username='sender',
email='sender@example.com',
password='senderpassword'
)
self.client = APIClient()
self.client.force_authenticate(user=self.user)
# Create a friend request
self.friend_request = FriendRequest.objects.create(
sender=self.sender,
receiver=self.user
)
def test_list_friend_requests(self):
"""Test listing friend requests"""
url = reverse('friendrequest-list')
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data), 1)
self.assertEqual(response.data[0]['sender']['username'], 'sender')
def test_delete_friend_request(self):
"""Test deleting a friend request"""
url = reverse('friendrequest-detail', args=[self.friend_request.id])
response = self.client.delete(url)
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
# Verify the friend request was deleted
self.assertFalse(FriendRequest.objects.filter(id=self.friend_request.id).exists())

View File

@@ -98,7 +98,7 @@ class UserViewSet(mixins.RetrieveModelMixin,
stats = User.objects.filter(id=request.user.id).aggregate(
total_size=Sum("torrents__size"),
total_torrent=Count("torrents"),
total_shared_torrent=Count("torrents_shares")
total_shared_torrent=Count("torrents_shares", distinct=True),
)
disk_usage = shutil.disk_usage("/")

View File

@@ -1,6 +1,6 @@
services:
redis:
image: redis:alpine
image: valkey/valkey:alpine
restart: unless-stopped
web: