diff --git a/apps/blog/admin.py b/apps/blog/admin.py index fd6b756..02da2fa 100644 --- a/apps/blog/admin.py +++ b/apps/blog/admin.py @@ -3,6 +3,7 @@ from unfold.admin import ModelAdmin + @admin.register(Post) class PostAdmin(ModelAdmin): list_display = ["title", "content", "author", "is_active"] diff --git a/apps/blog/filters.py b/apps/blog/filters.py index 92a246d..fe8d9e9 100644 --- a/apps/blog/filters.py +++ b/apps/blog/filters.py @@ -11,4 +11,4 @@ class PostFilter(django_filters.FilterSet): class Meta: model = Post - fields = ['title', 'description', 'content', 'created_at'] + fields = ["title", "description", "content", "created_at"] diff --git a/apps/blog/utils.py b/apps/blog/utils.py index 069bf08..ee169d4 100644 --- a/apps/blog/utils.py +++ b/apps/blog/utils.py @@ -1,27 +1,35 @@ from django.db.models import QuerySet from django.db.models import Q from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector -from django.core.paginator import Paginator, Page, EmptyPage, PageNotAnInteger, InvalidPage +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, query: str = None -) -> QuerySet: +def get_search_model_queryset(model_queryset: QuerySet, query: str = None) -> QuerySet: if not query: return model_queryset search_vector = SearchVector("title", "description", "content") search_query = SearchQuery(query) - if settings.DATABASES['default']['ENGINE'] == 'django.db.backends.postgresql': + 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') + 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( diff --git a/apps/shared/management/commands/createadmin.py b/apps/shared/management/commands/createadmin.py index ae3f06f..dcb4660 100644 --- a/apps/shared/management/commands/createadmin.py +++ b/apps/shared/management/commands/createadmin.py @@ -4,6 +4,7 @@ from django.core.management import BaseCommand from dotenv import load_dotenv + load_dotenv() diff --git a/apps/users/admin.py b/apps/users/admin.py index 43b9313..0a15963 100644 --- a/apps/users/admin.py +++ b/apps/users/admin.py @@ -1,13 +1,14 @@ from django.contrib import admin -from django.contrib.auth.admin import UserAdmin as BaseUserAdmin +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(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): @@ -16,4 +17,4 @@ def get_post_count(self): @admin.register(UserProfile) class UserProfileAdmin(ModelAdmin): - pass + list_display = ["user", "avatar", "bio"] diff --git a/apps/users/api_endpoints/users/User/tests.py b/apps/users/api_endpoints/users/User/tests.py index 3c3639f..d8181e2 100644 --- a/apps/users/api_endpoints/users/User/tests.py +++ b/apps/users/api_endpoints/users/User/tests.py @@ -104,4 +104,4 @@ def _create_user(): _create_user() def test_api_user_update(self): - pass \ No newline at end of file + pass diff --git a/apps/users/api_endpoints/users/UserProfile/tests.py b/apps/users/api_endpoints/users/UserProfile/tests.py index 899736f..935ce5e 100644 --- a/apps/users/api_endpoints/users/UserProfile/tests.py +++ b/apps/users/api_endpoints/users/UserProfile/tests.py @@ -1,6 +1,6 @@ from rest_framework.test import APITestCase from rest_framework_simplejwt.tokens import RefreshToken -from apps.users.models import UserProfile, User +from apps.users.models import UserProfile, User # noqa class UserProfileApiTestCase(APITestCase): @@ -18,5 +18,3 @@ def setUp(self) -> None: refresh = RefreshToken.for_user(self.user) self.token = str(refresh.access_token) return super().setUp() - - \ No newline at end of file diff --git a/core/asgi.py b/core/asgi.py index 0188a94..2a55ab5 100644 --- a/core/asgi.py +++ b/core/asgi.py @@ -3,13 +3,14 @@ from django.core.asgi import get_asgi_application from dotenv import load_dotenv + load_dotenv() os.environ.setdefault( - "DJANGO_SETTINGS_MODULE", - os.getenv("DJANGO_SETTINGS_MODULE", "core.settings.development") + "DJANGO_SETTINGS_MODULE", + os.getenv("DJANGO_SETTINGS_MODULE", "core.settings.development"), ) application = get_asgi_application() -app = application \ No newline at end of file +app = application diff --git a/core/config/__init__.py b/core/config/__init__.py index 9c65ab1..cee22ae 100644 --- a/core/config/__init__.py +++ b/core/config/__init__.py @@ -1,5 +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 .unfold_navigation import * # noqa +from .unfold import * # noqa + +# from .cheditor5 import * # noqa diff --git a/core/config/apps.py b/core/config/apps.py index ccdf6be..dc75c09 100644 --- a/core/config/apps.py +++ b/core/config/apps.py @@ -26,6 +26,8 @@ "unfold.contrib.simple_history", # Translation "modeltranslation", + # + "django_ckeditor_5", # Translation pannel "rosetta", # DRF Swaggers diff --git a/core/config/cheditor5.py b/core/config/cheditor5.py new file mode 100644 index 0000000..7360ae9 --- /dev/null +++ b/core/config/cheditor5.py @@ -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", + } + }, +} diff --git a/core/config/unfold.py b/core/config/unfold.py index e4c6447..048dd39 100644 --- a/core/config/unfold.py +++ b/core/config/unfold.py @@ -62,6 +62,6 @@ "SIDEBAR": { "show_search": True, "show_all_applications": True, - "navigation": navigation.PAGES - } -} \ No newline at end of file + "navigation": navigation.PAGES, + }, +} diff --git a/core/config/unfold_navigation.py b/core/config/unfold_navigation.py index 749ae28..322b44f 100644 --- a/core/config/unfold_navigation.py +++ b/core/config/unfold_navigation.py @@ -5,11 +5,11 @@ def user_has_group_or_permission(user, permission): if user.is_superuser: return True - + group_names = user.groups.values_list("name", flat=True) if not group_names: return True - + return user.groups.filter(permissions__codename=permission).exists() @@ -33,7 +33,8 @@ def user_has_group_or_permission(user, permission): "icon": "person_add", "link": reverse_lazy("admin:auth_group_changelist"), "permission": lambda request: user_has_group_or_permission( - request.user, "view_group", + request.user, + "view_group", ), }, { @@ -41,9 +42,10 @@ def user_has_group_or_permission(user, permission): "icon": "person_add", "link": reverse_lazy("admin:users_user_changelist"), "permission": lambda request: user_has_group_or_permission( - request.user, "view_user", + request.user, + "view_user", ), }, ], }, -] \ No newline at end of file +] diff --git a/core/settings/base.py b/core/settings/base.py index db58ac0..ed17621 100644 --- a/core/settings/base.py +++ b/core/settings/base.py @@ -18,19 +18,23 @@ ALLOWED_HOSTS = str(os.getenv("ALLOWED_HOSTS")).split(",") +CSRF_TRUSTED_ORIGINS = str(os.getenv("CSRF_TRUSTED_ORIGINS")).split(",") -INSTALLED_APPS = THIRD_PARTY_APPS + DEFAULT_APPS + PROJECT_APPS # NOQA +INSTALLED_APPS = THIRD_PARTY_APPS + DEFAULT_APPS + PROJECT_APPS # noqa MIDDLEWARE = [ "django.middleware.security.SecurityMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.BrokenLinkEmailsMiddleware", + # "corsheaders.middleware.CorsMiddleware", "django.middleware.common.CommonMiddleware", + "django.middleware.locale.LocaleMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", - "apps.users.middleware.JWTAuthMiddleware", # My Jwt Auth Middleware + "apps.users.middleware.JWTAuthMiddleware", # My Jwt Auth Middleware ] ROOT_URLCONF = "core.urls" @@ -87,7 +91,7 @@ USE_TZ = True -gettext = lambda s: gettext_lazy(s) +gettext = lambda s: gettext_lazy(s) # noqa LANGUAGES = ( ("ru", gettext("Russia")), diff --git a/core/urls.py b/core/urls.py index be5fcd3..21147ec 100644 --- a/core/urls.py +++ b/core/urls.py @@ -1,5 +1,5 @@ from django.conf.urls import handler400, handler403, handler404, handler500 # noqa -from django.conf.urls.i18n import i18n_patterns # noqa: F401 +from django.conf.urls.i18n import i18n_patterns # noqa: F401 from django.conf.urls.static import static from django.conf import settings diff --git a/core/wsgi.py b/core/wsgi.py index 7546823..f832f53 100644 --- a/core/wsgi.py +++ b/core/wsgi.py @@ -3,6 +3,7 @@ from django.core.wsgi import get_wsgi_application from dotenv import load_dotenv + load_dotenv() os.environ.setdefault( diff --git a/manage.py b/manage.py index a2ee85e..563eacd 100644 --- a/manage.py +++ b/manage.py @@ -7,7 +7,7 @@ def main(): - + os.environ.setdefault( "DJANGO_SETTINGS_MODULE", os.getenv("DJANGO_SETTINGS_MODULE", "core.settings.development"), diff --git a/requirements.txt b/requirements.txt index 4b121cf..d7a152b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,3 +14,4 @@ django-modeltranslation==0.18.11 drf-spectacular==0.27.1 drf-spectacular-sidecar==2024.3.4 django-rosetta==0.10.0 +django-ckeditor-5==0.2.13