stash
This commit is contained in:
parent
25cef95711
commit
7d7730354e
8 changed files with 381 additions and 39 deletions
|
|
@ -6,7 +6,7 @@ from rest_framework.permissions import IsAuthenticated
|
|||
from rest_framework.response import Response
|
||||
|
||||
from authentication.models import ToolshedUser, KnownIdentity
|
||||
from authentication.signature_auth import SignatureAuthentication
|
||||
from authentication.signature_auth import SignatureAuthentication, split_userhandle_or_throw
|
||||
from files.models import File
|
||||
from toolshed.models import InventoryItem, StorageLocation, WorkflowInstance
|
||||
from toolshed.serializers import InventoryItemSerializer, StorageLocationSerializer, WorkflowInstanceSerializer
|
||||
|
|
@ -76,6 +76,37 @@ def search_inventory_items(request):
|
|||
return Response({'error': 'No query provided.'}, status=400)
|
||||
|
||||
|
||||
@api_view(['GET'])
|
||||
@authentication_classes([SignatureAuthentication])
|
||||
@permission_classes([IsAuthenticated])
|
||||
def get_shared_item(request, handle, id):
|
||||
"""Fetch a single item by its owner's handle (username@domain) and local id, e.g. for the
|
||||
/i/<handle>/<id> item URL (see docs/design-in-progress/items-labels.md) or the
|
||||
/inventory/shared/<handle>/<id> in-app view. Unlike InventoryItemViewSet, which only ever
|
||||
returns the requester's own items, this looks the item up by owner instead of by requester,
|
||||
so it's the only endpoint that can serve a friend's item - subject to the same
|
||||
friends-or-self and availability_policy checks getUserProfile/_accessible_files already
|
||||
use elsewhere."""
|
||||
try:
|
||||
username, domain = split_userhandle_or_throw(handle)
|
||||
except ValueError:
|
||||
return Response(status=400)
|
||||
try:
|
||||
owner = ToolshedUser.objects.get(username=username, domain=domain)
|
||||
except ToolshedUser.DoesNotExist:
|
||||
return Response(status=404)
|
||||
if owner not in request.user.friends_or_self():
|
||||
return Response(status=403)
|
||||
try:
|
||||
item = owner.inventory_items.get(id=id)
|
||||
except InventoryItem.DoesNotExist:
|
||||
return Response(status=404)
|
||||
is_owner = request.user.user.filter(pk=owner.pk).exists()
|
||||
if item.availability_policy == 'private' and not is_owner:
|
||||
return Response(status=403)
|
||||
return Response(InventoryItemSerializer(item).data)
|
||||
|
||||
|
||||
class StorageLocationViewSet(viewsets.ModelViewSet):
|
||||
serializer_class = StorageLocationSerializer
|
||||
authentication_classes = [SignatureAuthentication]
|
||||
|
|
@ -136,4 +167,5 @@ router.register(r'workflows', WorkflowInstanceViewSet, basename='workflows')
|
|||
|
||||
urlpatterns = router.urls + [
|
||||
path('search/', search_inventory_items, name='search_inventory_items'),
|
||||
path('inventory_items/<str:handle>/<int:id>/', get_shared_item, name='shared_inventory_item'),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -213,6 +213,47 @@ class InventoryApiTestCase(UserTestMixin, InventoryTestMixin, ToolshedTestCase):
|
|||
self.assertEqual(reply.status_code, 200)
|
||||
self.assertEqual(len(reply.json()), 0)
|
||||
|
||||
def test_get_shared_item_as_friend(self):
|
||||
reply = client.get('/api/inventory_items/testuser1@example.com/' + str(self.f['item1'].id) + '/',
|
||||
self.f['local_user2'])
|
||||
self.assertEqual(reply.status_code, 200)
|
||||
self.assertEqual(reply.json()['name'], 'test1')
|
||||
self.assertEqual(reply.json()['owner'], 'testuser1@example.com')
|
||||
|
||||
def test_get_shared_item_as_owner(self):
|
||||
reply = client.get('/api/inventory_items/testuser1@example.com/' + str(self.f['item1'].id) + '/',
|
||||
self.f['local_user1'])
|
||||
self.assertEqual(reply.status_code, 200)
|
||||
self.assertEqual(reply.json()['name'], 'test1')
|
||||
|
||||
def test_get_shared_item_not_friend(self):
|
||||
reply = client.get('/api/inventory_items/testuser1@example.com/' + str(self.f['item1'].id) + '/',
|
||||
self.f['ext_user1'])
|
||||
self.assertEqual(reply.status_code, 403)
|
||||
|
||||
def test_get_shared_item_private(self):
|
||||
private_item = InventoryItem.objects.create(
|
||||
owner=self.f['local_user1'], owned_quantity=1, name='secret', availability_policy='private')
|
||||
reply = client.get('/api/inventory_items/testuser1@example.com/' + str(private_item.id) + '/',
|
||||
self.f['local_user2'])
|
||||
self.assertEqual(reply.status_code, 403)
|
||||
reply = client.get('/api/inventory_items/testuser1@example.com/' + str(private_item.id) + '/',
|
||||
self.f['local_user1'])
|
||||
self.assertEqual(reply.status_code, 200)
|
||||
|
||||
def test_get_shared_item_unknown_handle(self):
|
||||
reply = client.get('/api/inventory_items/nobody@example.com/' + str(self.f['item1'].id) + '/',
|
||||
self.f['local_user2'])
|
||||
self.assertEqual(reply.status_code, 404)
|
||||
|
||||
def test_get_shared_item_unknown_id(self):
|
||||
reply = client.get('/api/inventory_items/testuser1@example.com/99999/', self.f['local_user2'])
|
||||
self.assertEqual(reply.status_code, 404)
|
||||
|
||||
def test_get_shared_item_bad_handle(self):
|
||||
reply = client.get('/api/inventory_items/testuser1/' + str(self.f['item1'].id) + '/', self.f['local_user2'])
|
||||
self.assertEqual(reply.status_code, 400)
|
||||
|
||||
|
||||
class TestInventoryItemWithFileApiTestCase(UserTestMixin, FilesTestMixin, InventoryTestMixin, ToolshedTestCase):
|
||||
def setUp(self):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue