Skip to content

Commit

Permalink
Merge pull request #354 from ita-social-projects/#174addingImages
Browse files Browse the repository at this point in the history
#174adding images
  • Loading branch information
BelousSofiya authored Dec 9, 2023
2 parents 7ffc320 + bda06f0 commit a3c7a8d
Show file tree
Hide file tree
Showing 11 changed files with 176 additions and 2 deletions.
7 changes: 7 additions & 0 deletions configs/nginx/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ server {
proxy_redirect off;
}

location /media/ {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_pass http://api-dev:8000/media/;
proxy_redirect off;
}

# Django API
location /api/ {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
Expand Down
1 change: 1 addition & 0 deletions forum/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"administration",
"search",
"drf_spectacular",
"images",
]

MIDDLEWARE = [
Expand Down
5 changes: 4 additions & 1 deletion forum/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
from django.contrib import admin
from django.urls import include, path
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
path("admin/", admin.site.urls),
Expand All @@ -26,10 +28,11 @@
include("administration.urls", namespace="administration"),
),
path("api/", include("search.urls", namespace="search")),
path("api/", include("images.urls", namespace="images")),
path("api/schema/", SpectacularAPIView.as_view(), name="schema"),
path(
"api/schema/docs/",
SpectacularSwaggerView.as_view(url_name="schema"),
name="schema_docs",
),
]
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Empty file added images/__init__.py
Empty file.
8 changes: 8 additions & 0 deletions images/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from rest_framework import serializers
from profiles.models import Profile


class BannerSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = ("banner_image",)
Empty file added images/tests/__init__.py
Empty file.
129 changes: 129 additions & 0 deletions images/tests/test_banner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
from rest_framework import status
from rest_framework.test import APITestCase

import os
from io import BytesIO
from PIL import Image

from authentication.factories import UserFactory
from profiles.factories import (
ProfileStartupFactory,
ProfileCompanyFactory,
)

from utils.dump_response import dump # noqa


class TestBannerChange(APITestCase):
@staticmethod
def _generate_image(ext, size=(100, 100)):
"""for mocking png and jpeg files"""
file = BytesIO()
image = Image.new("RGB", size=size)
formatext = ext.upper()
image.save(file, formatext)
file.name = f"test.{formatext}"
file.seek(0)
return file

def setUp(self) -> None:
self.right_image = self._generate_image("jpeg", (100, 100))
self.wrong_image = self._generate_image("png", (7000, 7000))

self.user = UserFactory(email="[email protected]")
self.company_dnipro = ProfileStartupFactory.create(
person=self.user,
name="Dnipro",
banner_image=f"banners/{self.right_image.name}",
)

self.company_kyiv = ProfileCompanyFactory(name="Kyivbud")

def tearDown(self) -> None:
if os.path.exists(self.right_image.name):
os.remove(self.right_image.name)
if os.path.exists(self.wrong_image.name):
os.remove(self.wrong_image.name)

def test_get_empty_banner_unauthorized(self):
response = self.client.get(path=f"/api/banner/{self.company_kyiv.id}/")
self.assertEqual(200, response.status_code)
self.assertEqual({"banner_image": None}, response.json())

def test_get_banner_unauthorized(self):
response = self.client.get(
path=f"/api/banner/{self.company_dnipro.id}/"
)
self.assertEqual(200, response.status_code)
self.assertEqual(
{
"banner_image": f"http://testserver/media/banners/{self.right_image.name}"
},
response.json(),
)

def test_get_banner_authorized(self):
self.client.force_authenticate(self.user)
response = self.client.get(
path=f"/api/banner/{self.company_dnipro.id}/"
)
self.assertEqual(200, response.status_code)
self.assertEqual(
{
"banner_image": f"http://testserver/media/banners/{self.right_image.name}"
},
response.json(),
)

def test_get_empty_banner_authorized(self):
self.client.force_authenticate(self.user)
response = self.client.get(path=f"/api/banner/{self.company_kyiv.id}/")
self.assertEqual(200, response.status_code)
self.assertEqual({"banner_image": None}, response.json())

def test_put_banner_unauthorized(self):
response = self.client.put(
path=f"/api/banner/{self.company_dnipro.id}/",
data={"banner_image": self.right_image},
)
self.assertEqual(401, response.status_code)
self.assertEqual(
{"detail": "Authentication credentials were not provided."},
response.json(),
)

def test_put_banner_authorized_not_owner(self):
self.client.force_authenticate(self.user)
response = self.client.put(
path=f"/api/banner/{self.company_kyiv.id}/",
data={"banner_image": self.right_image},
)
self.assertEqual(403, response.status_code)
self.assertEqual(
{"detail": "You do not have permission to perform this action."},
response.json(),
)

def test_put_banner_authorized_owner_right_image(self):
self.client.force_authenticate(self.user)
response = self.client.put(
path=f"/api/banner/{self.company_dnipro.id}/",
data={"banner_image": self.right_image},
)
self.assertEqual(200, response.status_code)

def test_put_banner_authorized_owner_wrong_image(self):
self.client.force_authenticate(self.user)
response = self.client.put(
path=f"/api/banner/{self.company_dnipro.id}/",
data={"banner_image": self.wrong_image},
)
self.assertEqual(400, response.status_code)
self.assertEqual(
{
"banner_image": [
"Image size exceeds the maximum allowed (50MB)."
]
},
response.json(),
)
8 changes: 8 additions & 0 deletions images/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from django.urls import path
from .views import BannerRetrieveUpdate

app_name = "images"

urlpatterns = [
path("banner/<pk>/", BannerRetrieveUpdate.as_view(), name="banner_change"),
]
15 changes: 15 additions & 0 deletions images/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from rest_framework.generics import (
RetrieveUpdateAPIView,
)
from rest_framework.parsers import MultiPartParser, FormParser

from profiles.permissions import UserIsProfileOwnerOrReadOnly
from profiles.models import Profile
from .serializers import BannerSerializer


class BannerRetrieveUpdate(RetrieveUpdateAPIView):
permission_classes = (UserIsProfileOwnerOrReadOnly,)
serializer_class = BannerSerializer
parser_classes = (MultiPartParser, FormParser)
queryset = Profile.objects.all()
4 changes: 3 additions & 1 deletion profiles/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@ class Profile(models.Model):
startup_idea = models.TextField(default=None, null=True)

banner_image = models.ImageField(
validators=[validate_image_format, validate_image_size], null=True
upload_to="banners",
validators=[validate_image_format, validate_image_size],
null=True,
)

is_deleted = models.BooleanField(default=False)
Expand Down
1 change: 1 addition & 0 deletions profiles/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class ProfileDetailSerializer(serializers.ModelSerializer):
categories = CategorySerializer(many=True, read_only=True)
is_saved = serializers.SerializerMethodField()
region_display = serializers.SerializerMethodField()
banner_image = serializers.ImageField(required=False)

class Meta:
model = Profile
Expand Down

0 comments on commit a3c7a8d

Please sign in to comment.