Skip to content

Commit

Permalink
Merge pull request #8 from pik-software/few_models
Browse files Browse the repository at this point in the history
Few models
  • Loading branch information
Lev Borodin authored Jun 7, 2019
2 parents 62522b9 + f92ad1f commit a29bed9
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 25 deletions.
14 changes: 13 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Changelog

## [v1.1] - 2018-06-07
### Added
- In url config you can set **app_labels** instead a model or app_label, model_name.
Ex: app_labels = ['project.Model', 'project.Model2']

### Changed
- Now in url config you can set only app_label without model_name. Ex: app_label='project.Model'

### Deprecated
- model argument in url config will be removed in v1.2

## [v1.0] - 2018-05-30
### Added
- Uid, name, created, bucket_name fields to files json
Expand All @@ -16,4 +27,5 @@
### Removed
- Removed file_info function from storage

[1.0.0]: https://github.com/pik-software/apiqa-storage/compare/v0.6...v1.0
[v1.1]: https://github.com/pik-software/apiqa-storage/compare/v1.0...v1.1
[v1.0]: https://github.com/pik-software/apiqa-storage/compare/v0.6...v1.0
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ urlpatterns = [ # noqa
path(
'attachments/',
include('apiqa_storage.urls'),
kwargs={'app_label': 'app', 'model_name': 'UserFile'},
kwargs={'app_label': 'app.UserFile'},
),
]
```
Expand All @@ -72,11 +72,17 @@ urlpatterns = [ # noqa
path(
'attachments/',
include('apiqa_storage.staff_urls'),
kwargs={'app_label': 'app', 'model_name': 'UserFile'},
kwargs={'app_label': 'app.UserFile'},
),
]
```

* Insted app_label you can set app_labels in urlpatterns

```python
kwargs={'app_labels': ['app.UserFile', 'app.StaffFile']}
```

* Add required minio settings. Create bucket on minio!
[django minio storage usage](https://django-minio-storage.readthedocs.io/en/latest/usage/)

Expand Down
13 changes: 8 additions & 5 deletions apiqa_storage/file_response.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
import logging
from typing import Type

from django.core.files import File
from django.db import models
from django.http import FileResponse
from django.shortcuts import get_object_or_404

from apiqa_storage.minio_storage import storage

logger = logging.getLogger(__name__)


def get_file_response(model, file_uid: str, user=None):
def get_file_response(model: Type[models.Model], file_uid: str, user=None):
user_filter = {'user': user} if user else {}

obj = get_object_or_404(
model,
obj = model.objects.filter(
attachments__contains=[{'uid': str(file_uid)}],
**user_filter,
)
).first()

if obj is None:
return None

attachments = [
file for file in obj.attachments if file['uid'] == str(file_uid)
Expand Down
35 changes: 27 additions & 8 deletions apiqa_storage/view.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
from typing import Type

from django.apps import apps
from django.http import Http404
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated

Expand All @@ -11,18 +14,34 @@
def attachment_view(
request,
file_uid,
model: AttachFilesMixin = None,
model: Type[AttachFilesMixin] = None,
app_label: str = None,
model_name: str = None,
from_user=False
app_labels: list = None,
from_user: bool = False,
):
if app_label and model_name:
user = request.user if from_user else None

if app_labels and isinstance(app_labels, list):
for app_label in app_labels:
if isinstance(app_label, str):
model = apps.get_model(app_label)
else:
raise TypeError("models must be list of str")

file_resp = get_file_response(model, file_uid, user)
if file_resp is not None:
return file_resp
raise Http404("File not found")

if app_label:
model = apps.get_model(app_label, model_name)

if not model:
raise ValueError('Set app_label and model_name on view kwargs')
raise ValueError('Set app_label\\model_name or app_labels on view kwargs')

file_resp = get_file_response(model, file_uid, user)
if file_resp is not None:
return file_resp

if from_user:
return get_file_response(model, file_uid, request.user)
else:
return get_file_response(model, file_uid)
raise Http404("File not found")
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

setup(
name='apiqa-storage',
version='1.0',
version='1.1',
description='Apiqa user storage backend for django projects',
# https://packaging.python.org/specifications/core-metadata/#description-optional
long_description=LONG_DESCRIPTION,
Expand Down
10 changes: 7 additions & 3 deletions test_project/urls.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
from django.contrib import admin
from django.urls import path, include, re_path
from django.urls import path, include
from rest_framework.routers import DefaultRouter

from tests_storage.models import UserAttachFile
from tests_storage.views import StaffViewSet

router = DefaultRouter()
Expand All @@ -12,12 +11,17 @@
path(
'attachments/',
include('apiqa_storage.urls'),
kwargs={'model': UserAttachFile},
kwargs={'app_label': 'tests_storage.UserAttachFile'},
),
path(
'attachments_staff/',
include('apiqa_storage.staff_urls'),
kwargs={'app_label': 'tests_storage', 'model_name': 'UserAttachFile'},
),
path(
'all_attachments/',
include(('apiqa_storage.staff_urls', 'test_project')),
kwargs={'app_labels': ['tests_storage.UserAttachFile', 'tests_storage.MyAttachFile']},
),
path('admin/', admin.site.urls),
] + router.urls
8 changes: 3 additions & 5 deletions tests/test_file_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,13 @@ def test_get_file_response(storage):
data, meta = create_file(storage)

resp = get_file_response(MyAttachFile, meta['uid'])
assert resp is not None
assert resp.getvalue() == data
assert resp['Content-Length'] == str(len(data))
assert resp['Content-Type'] == 'image/jpeg'
assert meta['name'] in resp['Content-Disposition']


@pytest.mark.django_db
def test_get_file_response_not_found(storage):
create_file(storage)

with pytest.raises(Http404):
get_file_response(MyAttachFile, 'undefined')
def test_get_file_response_not_found():
assert get_file_response(MyAttachFile, 'undefined') is None
17 changes: 17 additions & 0 deletions tests/test_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,20 @@ def test_get_attachments_from_another_bucket(client: APIClient, storage):
res = client.get(url)
assert res.status_code == status.HTTP_200_OK
assert res.getvalue() == data


@pytest.mark.django_db
def test_get_attachment_from_few_models(client: APIClient, storage):
owner_user = UserFactory.create()
data, meta = create_file(storage)

url = reverse('test_project:attachments_staff', kwargs={
'file_uid': meta['uid']
})

client.force_login(owner_user)
with patch('apiqa_storage.serializers.storage', storage):
res = client.get(url)

assert res.status_code == status.HTTP_200_OK
assert res.getvalue() == data

0 comments on commit a29bed9

Please sign in to comment.