Skip to content

Commit

Permalink
Merge pull request #19 from RustamovAkrom/main
Browse files Browse the repository at this point in the history
Main
  • Loading branch information
RustamovAkrom authored Nov 21, 2024
2 parents c14f710 + 1564ffb commit 215736d
Show file tree
Hide file tree
Showing 29 changed files with 4,520 additions and 49 deletions.
12 changes: 7 additions & 5 deletions apps/blog/admin.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from django.contrib import admin
from .models import Post, PostComment, PostLike, PostDislike, PostCommentLike

from unfold.admin import ModelAdmin


@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
class PostAdmin(ModelAdmin):
list_display = ["title", "content", "author", "is_active"]
search_fields = ["title", "content"]
list_filter = ["author", "is_active"]
Expand All @@ -12,20 +14,20 @@ class PostAdmin(admin.ModelAdmin):


@admin.register(PostComment)
class PostCommentAdmin(admin.ModelAdmin):
class PostCommentAdmin(ModelAdmin):
pass


@admin.register(PostLike)
class PostLikeAdmin(admin.ModelAdmin):
class PostLikeAdmin(ModelAdmin):
pass


@admin.register(PostDislike)
class PostDislike(admin.ModelAdmin):
class PostDislike(ModelAdmin):
pass


@admin.register(PostCommentLike)
class PostCommentLikeAdmin(admin.ModelAdmin):
class PostCommentLikeAdmin(ModelAdmin):
pass
14 changes: 14 additions & 0 deletions apps/blog/filters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import django_filters

from .models import Post


class PostFilter(django_filters.FilterSet):
title = django_filters.CharFilter(lookup_expr="icontains")
description = django_filters.CharFilter(lookup_expr="icontains")
content = django_filters.CharFilter(lookup_expr="icontains")
created_at = django_filters.DateFromToRangeFilter()

class Meta:
model = Post
fields = ["title", "description", "content", "created_at"]
48 changes: 36 additions & 12 deletions apps/blog/utils.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,44 @@
from django.db.models import QuerySet
from django.db.models import Q
from django.core.paginator import Paginator, Page, EmptyPage, PageNotAnInteger
from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector
from django.core.paginator import (
Paginator,
Page,
EmptyPage,
PageNotAnInteger,
InvalidPage,
)
from django.conf import settings

from .models import PostLike, PostDislike, Post, PostComment


def get_search_model_queryset(
model_queryset: QuerySet, search_query: str = None
) -> QuerySet:
if not search_query:
def get_search_model_queryset(model_queryset: QuerySet, query: str = None) -> QuerySet:
if not query:
return model_queryset

search_query = model_queryset.filter(
Q(title__icontains=search_query)
| Q(description__icontains=search_query)
| Q(content__icontains=search_query)
)

return search_query
search_vector = SearchVector("title", "description", "content")
search_query = SearchQuery(query)

if settings.DATABASES["default"]["ENGINE"] == "django.db.backends.postgresql":
# PostgreSQL search
queryset = (
model_queryset.annotate(
search=search_vector,
rank=SearchRank(search_vector, search_query),
)
.filter(search=search_query)
.order_by("-rank")
)
else:
# SQLite3 search
queryset = model_queryset.filter(
Q(title__icontains=query)
| Q(description__icontains=query)
| Q(content__icontains=query)
)

return queryset


def get_pagination_obj(model_queryset: QuerySet, page: int = 1, size: int = 4) -> Page:
Expand All @@ -29,6 +50,9 @@ def get_pagination_obj(model_queryset: QuerySet, page: int = 1, size: int = 4) -
except PageNotAnInteger:
page_obj = paginator.page(1)

except InvalidPage:
page_obj = paginator.page(1)

except EmptyPage:
page_obj = paginator.page(paginator.num_pages)

Expand Down
1 change: 1 addition & 0 deletions apps/shared/management/commands/createadmin.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from django.core.management import BaseCommand

from dotenv import load_dotenv

load_dotenv()


Expand Down
11 changes: 7 additions & 4 deletions apps/users/admin.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin # noqa
from .models import User, UserProfile

from unfold.admin import ModelAdmin


@admin.register(User)
class UserAdmin(admin.ModelAdmin):
class UserAdmin(ModelAdmin):
list_display = ["username", "post_count"]
search_fields = ["first_name", "last_name", "username"]
search_fields = ["first_name", "last_name", "username", "email"]
list_display_links = ["username"]

def get_post_count(self):
return self.post_count


@admin.register(UserProfile)
class UserProfileAdmin(admin.ModelAdmin):
pass
class UserProfileAdmin(ModelAdmin):
list_display = ["user", "avatar", "bio"]
3 changes: 3 additions & 0 deletions apps/users/api_endpoints/users/User/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,6 @@ def _create_user():
_check_user_error_field()
_check_user_passwords_field()
_create_user()

def test_api_user_update(self):
pass
20 changes: 20 additions & 0 deletions apps/users/api_endpoints/users/UserProfile/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from rest_framework.test import APITestCase
from rest_framework_simplejwt.tokens import RefreshToken
from apps.users.models import UserProfile, User # noqa


class UserProfileApiTestCase(APITestCase):
def setUp(self) -> None:
self.username = "Admin"
self.email = "[email protected]"
self.password = "password"
user = User.objects.create(
username=self.username,
email=self.email,
)
user.set_password(self.password)
user.save()
self.user = user
refresh = RefreshToken.for_user(self.user)
self.token = str(refresh.access_token)
return super().setUp()
1 change: 1 addition & 0 deletions apps/users/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

class JWTAuthMiddleware(MiddlewareMixin):
def process_request(self, request):
# If admin auth for session
if request.path.startswith("/admin"):
return

Expand Down
20 changes: 10 additions & 10 deletions core/asgi.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
"""
ASGI config for config project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.0/howto/deployment/asgi/
"""

import os

from django.core.asgi import get_asgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "core.settings")
from dotenv import load_dotenv

load_dotenv()

os.environ.setdefault(
"DJANGO_SETTINGS_MODULE",
os.getenv("DJANGO_SETTINGS_MODULE", "core.settings.development"),
)

application = get_asgi_application()

app = application
4 changes: 4 additions & 0 deletions core/config/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
from .apps import * # noqa
from .jwt import * # noqa
from .rest_framework import * # noqa
from .unfold_navigation import * # noqa
from .unfold import * # noqa

# from .cheditor5 import * # noqa
18 changes: 18 additions & 0 deletions core/config/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,25 @@
]

THIRD_PARTY_APPS = [
# Admin panel
"unfold",
"unfold.contrib.filters",
"unfold.contrib.forms",
"unfold.contrib.import_export",
"unfold.contrib.guardian",
"unfold.contrib.simple_history",
# Translation
"modeltranslation",
#
"django_ckeditor_5",
# Translation pannel
"rosetta",
# DRF Swaggers
"drf_spectacular",
"drf_spectacular_sidecar",
# Rest Framework
"rest_framework",
# Rest Framework JWT (Json web token)s
"rest_framework_simplejwt",
"rest_framework_simplejwt.token_blacklist",
]
140 changes: 140 additions & 0 deletions core/config/cheditor5.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
customColorPalette = [
{"color": "hsl(4, 90%, 58%)", "label": "Red"},
{"color": "hsl(340, 82%, 52%)", "label": "Pink"},
{"color": "hsl(291, 64%, 42%)", "label": "Purple"},
{"color": "hsl(262, 52%, 47%)", "label": "Deep Purple"},
{"color": "hsl(231, 48%, 48%)", "label": "Indigo"},
{"color": "hsl(207, 90%, 54%)", "label": "Blue"},
]

CKEDITOR_5_CONFIGS = {
"default": {
"toolbar": [
"heading",
"|",
"bold",
"italic",
"link",
"bulletedList",
"numberedList",
"blockQuote",
"imageUpload",
],
},
"extends": {
"blockToolbar": [
"paragraph",
"heading1",
"heading2",
"heading3",
"|",
"bulletedList",
"numberedList",
"|",
"blockQuote",
],
"toolbar": [
"heading",
"|",
"outdent",
"indent",
"|",
"bold",
"italic",
"link",
"underline",
"strikethrough",
"code",
"subscript",
"superscript",
"highlight",
"|",
"codeBlock",
"sourceEditing",
"insertImage",
"bulletedList",
"numberedList",
"todoList",
"|",
"blockQuote",
"imageUpload",
"|",
"fontSize",
"fontFamily",
"fontColor",
"fontBackgroundColor",
"mediaEmbed",
"removeFormat",
"insertTable",
],
"image": {
"toolbar": [
"imageTextAlternative",
"|",
"imageStyle:alignLeft",
"imageStyle:alignRight",
"imageStyle:alignCenter",
"imageStyle:side",
"|",
],
"styles": [
"full",
"side",
"alignLeft",
"alignRight",
"alignCenter",
],
},
"table": {
"contentToolbar": [
"tableColumn",
"tableRow",
"mergeTableCells",
"tableProperties",
"tableCellProperties",
],
"tableProperties": {
"borderColors": customColorPalette,
"backgroundColors": customColorPalette,
},
"tableCellProperties": {
"borderColors": customColorPalette,
"backgroundColors": customColorPalette,
},
},
"heading": {
"options": [
{
"model": "paragraph",
"title": "Paragraph",
"class": "ck-heading_paragraph",
},
{
"model": "heading1",
"view": "h1",
"title": "Heading 1",
"class": "ck-heading_heading1",
},
{
"model": "heading2",
"view": "h2",
"title": "Heading 2",
"class": "ck-heading_heading2",
},
{
"model": "heading3",
"view": "h3",
"title": "Heading 3",
"class": "ck-heading_heading3",
},
]
},
},
"list": {
"properties": {
"styles": "true",
"startIndex": "true",
"reversed": "true",
}
},
}
Loading

0 comments on commit 215736d

Please sign in to comment.