Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion app_settings/config.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import os

SECRET_KEY = os.environ.get("SECRET_KEY", "django-insecure-)@#djte1uunyz)-cjrf1tte^ljapdb=t*ejeo)nhs(4ldifxuz")
SECRET_KEY = os.environ.get(
"SECRET_KEY", "django-insecure-)@#djte1uunyz)-cjrf1tte^ljapdb=t*ejeo)nhs(4ldifxuz"
)
DEBUG = os.environ.get("DEBUG", True)

POSTGRES_USER = os.environ.get("POSTGRES_USER", "postgres")
Expand Down
17 changes: 17 additions & 0 deletions main/apps/filtersets.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@


class AppFilterset(filters.FilterSet):
SORT_CHOICES = (
("newest", "Newest"),
# ("rating", "Rating"),
# ("popular", "Popular"),
("relevance", "Relevance"),
)

sort = filters.ChoiceFilter(method="filter_sort", choices=SORT_CHOICES)
category_id = filters.NumberFilter("category_id")
type = filters.ChoiceFilter(field_name="type", choices=App.APP_TYPES)
q = filters.CharFilter(method="filter_q")
Expand All @@ -14,6 +22,15 @@ def filter_q(self, queryset, name, value):
Q(name__icontains=value) | Q(description__icontains=value)
)

def filter_sort(self, queryset, name, value):
match value:
case "newest":
return queryset.order_by("-updated_at")
case "relevance":
return queryset.order_by("-updated_at")
case _:
return queryset

class Meta:
model = App
fields = [
Expand Down
75 changes: 75 additions & 0 deletions main/apps/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import pytest
from django.utils import timezone
from rest_framework.test import APIClient

from users.models import User
from developer_profiles.models import DeveloperProfile
from category.models import Category
from apps.models import App


@pytest.fixture
def api_client():
return APIClient()


@pytest.fixture
def user():
return User.objects.create(
type="developer",
email="email@mail.com",
login="user_login",
password="password",
)


@pytest.fixture
def developer(user):
return DeveloperProfile.objects.create(user=user)


@pytest.fixture
def category(db):
return Category.objects.create(name="Test category")


@pytest.fixture
def apps(developer, category):
app1 = App.objects.create(
name="Old App",
description="Old",
type="internal",
status="published",
developer=developer,
category=category,
)

app2 = App.objects.create(
name="New App",
description="New",
type="external",
status="published",
developer=developer,
category=category,
)

app3 = App.objects.create(
name="Popular App",
description="Popular",
type="external",
status="published",
developer=developer,
category=category,
)

App.objects.filter(pk=app1.pk).update(
updated_at=timezone.now() - timezone.timedelta(days=10)
)
App.objects.filter(pk=app2.pk).update(
updated_at=timezone.now() - timezone.timedelta(days=1)
)
App.objects.filter(pk=app3.pk).update(
updated_at=timezone.now() - timezone.timedelta(days=5)
)

return [app1, app2, app3]
46 changes: 46 additions & 0 deletions main/apps/tests/test_app_view_filter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import pytest
from django.urls import reverse


@pytest.mark.django_db
def test_apps_sort_newest(api_client, apps):
url = reverse("app-list") + "?sort=newest"
response = api_client.get(url)

assert response.status_code == 200

items = (
response.data if isinstance(response.data, list) else response.data["results"]
)
print(items)
names = [item["name"] for item in items]

assert names == [
"New App",
"Popular App",
"Old App",
]


@pytest.mark.django_db
def test_apps_sort_relevance_is_newest(api_client, apps):
url = reverse("app-list") + "?sort=relevance"
response = api_client.get(url)

assert response.status_code == 200

items = (
response.data if isinstance(response.data, list) else response.data["results"]
)
updated = [item["updated_at"] for item in items]

assert updated == sorted(updated, reverse=True)


@pytest.mark.django_db
def test_apps_sort_invalid_value(api_client, apps):
url = reverse("app-list") + "?sort=invalid"
response = api_client.get(url)

assert response.status_code == 400
assert "sort" in response.data
8 changes: 6 additions & 2 deletions main/apps/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
from apps.views import AppViewSet

urlpatterns = [
path("", AppViewSet.as_view({"get": "list", "post": "create"})),
path("<int:pk>/", AppViewSet.as_view({"get": "retrieve", "delete": "destroy"})),
path("", AppViewSet.as_view({"get": "list", "post": "create"}), name="app-list"),
path(
"<int:pk>/",
AppViewSet.as_view({"get": "retrieve", "delete": "destroy"}),
name="app-detail",
),
]
3 changes: 0 additions & 3 deletions main/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
ALLOWED_HOSTS = []



DJANGO_APPS = [
"django.contrib.admin",
"django.contrib.auth",
Expand Down Expand Up @@ -44,7 +43,6 @@
INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS



REST_FRAMEWORK = {
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
"DEFAULT_AUTHENTICATION_CLASSES": [
Expand Down Expand Up @@ -99,7 +97,6 @@
}



AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
Expand Down
7 changes: 3 additions & 4 deletions main/users/jwt_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from typing import Optional

import jwt
from jwt import DecodeError

import settings
from users.models import User
Expand Down Expand Up @@ -38,7 +37,7 @@ def create_token(self, user: User) -> tuple[str, str]:
return access_token, refresh_token

def decode_token(self, token: str) -> Optional[dict]:
decode = jwt.decode(jwt=token,
key=settings.JWT_SECRET_KEY,
algorithms=[settings.JWT_ALGORITHM])
decode = jwt.decode(
jwt=token, key=settings.JWT_SECRET_KEY, algorithms=[settings.JWT_ALGORITHM]
)
return decode
20 changes: 8 additions & 12 deletions main/users/middleware/jwt_middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,7 @@ def __call__(self, request: HttpRequest, *args, **kwargs):
request_authorization = request.headers.get("Authorization")

if not request_authorization or not request_authorization.startswith("Bearer"):
return JsonResponse(
{"Error": "Unauthorized"},
status=401
)
return JsonResponse({"Error": "Unauthorized"}, status=401)

try:
token = request_authorization.split()[1]
Expand All @@ -34,17 +31,16 @@ def __call__(self, request: HttpRequest, *args, **kwargs):
user_id = payload["user_id"]
user = user_service.get_user_by_user_id(id=user_id)

except (jwt.InvalidTokenError,
jwt.DecodeError,
User.DoesNotExist,):
return JsonResponse(
{"Error": "Unauthorized"},
status=401
)
except (
jwt.InvalidTokenError,
jwt.DecodeError,
User.DoesNotExist,
):
return JsonResponse({"Error": "Unauthorized"}, status=401)

else:
request.user = user
request.user_id = user_id
request.user_role = user.type

return self.get_response(request)
return self.get_response(request)