Merge branch 'main' into storefront-nuxt
This commit is contained in:
commit
1a6a9f666e
292 changed files with 12872 additions and 11522 deletions
|
|
@ -34,7 +34,7 @@ class PostAdmin(SummernoteModelAdminMixin, FieldsetsMixin, ActivationActionsMixi
|
||||||
|
|
||||||
|
|
||||||
@register(PostTag)
|
@register(PostTag)
|
||||||
class PostTagAdmin(ModelAdmin): # type: ignore [misc, type-arg]
|
class PostTagAdmin(ModelAdmin): # type: ignore [type-arg]
|
||||||
list_display = ("tag_name", "name")
|
list_display = ("tag_name", "name")
|
||||||
search_fields = ("tag_name", "name")
|
search_fields = ("tag_name", "name")
|
||||||
ordering = ("tag_name",)
|
ordering = ("tag_name",)
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,6 @@ class BlogConfig(AppConfig):
|
||||||
hide = False
|
hide = False
|
||||||
|
|
||||||
# noinspection PyUnresolvedReferences
|
# noinspection PyUnresolvedReferences
|
||||||
def ready(self):
|
def ready(self) -> None:
|
||||||
import blog.elasticsearch.documents
|
import blog.elasticsearch.documents
|
||||||
import blog.signals # noqa: F401
|
import blog.signals # noqa: F401
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ from core.elasticsearch import COMMON_ANALYSIS, ActiveOnlyMixin, add_multilang_f
|
||||||
from core.elasticsearch.documents import BaseDocument
|
from core.elasticsearch.documents import BaseDocument
|
||||||
|
|
||||||
|
|
||||||
class PostDocument(ActiveOnlyMixin, BaseDocument):
|
class PostDocument(ActiveOnlyMixin, BaseDocument): # type: ignore [misc]
|
||||||
title = fields.TextField(
|
title = fields.TextField(
|
||||||
attr="title",
|
attr="title",
|
||||||
analyzer="standard",
|
analyzer="standard",
|
||||||
|
|
@ -30,7 +30,7 @@ class PostDocument(ActiveOnlyMixin, BaseDocument):
|
||||||
model = Post
|
model = Post
|
||||||
fields = ["uuid"]
|
fields = ["uuid"]
|
||||||
|
|
||||||
def prepare_title(self, instance):
|
def prepare_title(self, instance: Post) -> str:
|
||||||
return getattr(instance, "title", "") or ""
|
return getattr(instance, "title", "") or ""
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ from blog.models import Post
|
||||||
from core.filters import CaseInsensitiveListFilter
|
from core.filters import CaseInsensitiveListFilter
|
||||||
|
|
||||||
|
|
||||||
class PostFilter(FilterSet):
|
class PostFilter(FilterSet): # type: ignore [misc]
|
||||||
uuid = UUIDFilter(field_name="uuid", lookup_expr="exact")
|
uuid = UUIDFilter(field_name="uuid", lookup_expr="exact")
|
||||||
slug = CharFilter(field_name="slug", lookup_expr="exact")
|
slug = CharFilter(field_name="slug", lookup_expr="exact")
|
||||||
author = UUIDFilter(field_name="author__uuid", lookup_expr="exact")
|
author = UUIDFilter(field_name="author__uuid", lookup_expr="exact")
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 3.0.0\n"
|
"Project-Id-Version: EVIBES 3.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-10-07 15:47+0300\n"
|
"POT-Creation-Date: 2025-10-13 13:56+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 3.0.0\n"
|
"Project-Id-Version: EVIBES 3.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-10-07 15:47+0300\n"
|
"POT-Creation-Date: 2025-10-13 13:56+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 3.0.0\n"
|
"Project-Id-Version: EVIBES 3.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-10-07 15:47+0300\n"
|
"POT-Creation-Date: 2025-10-13 13:56+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 3.0.0\n"
|
"Project-Id-Version: EVIBES 3.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-10-07 15:47+0300\n"
|
"POT-Creation-Date: 2025-10-13 13:56+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,12 @@
|
||||||
# Copyright (C) 2025 EGOR <FUREUNOIR> GORBUNOV
|
# Copyright (C) 2025 EGOR <FUREUNOIR> GORBUNOV
|
||||||
# This file is distributed under the same license as the EVIBES package.
|
# This file is distributed under the same license as the EVIBES package.
|
||||||
# EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>, 2025.
|
# EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>, 2025.
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 3.0.0\n"
|
"Project-Id-Version: EVIBES 3.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-10-07 15:47+0300\n"
|
"POT-Creation-Date: 2025-10-13 13:56+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 3.0.0\n"
|
"Project-Id-Version: EVIBES 3.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-10-07 15:47+0300\n"
|
"POT-Creation-Date: 2025-10-13 13:56+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 3.0.0\n"
|
"Project-Id-Version: EVIBES 3.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-10-07 15:47+0300\n"
|
"POT-Creation-Date: 2025-10-13 13:56+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,12 @@
|
||||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||||
# This file is distributed under the same license as the PACKAGE package.
|
# This file is distributed under the same license as the PACKAGE package.
|
||||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-10-07 15:47+0300\n"
|
"POT-Creation-Date: 2025-10-13 13:56+0300\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 3.0.0\n"
|
"Project-Id-Version: EVIBES 3.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-10-07 15:47+0300\n"
|
"POT-Creation-Date: 2025-10-13 13:56+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 3.0.0\n"
|
"Project-Id-Version: EVIBES 3.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-10-07 15:47+0300\n"
|
"POT-Creation-Date: 2025-10-13 13:56+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,12 @@
|
||||||
# Copyright (C) 2025 EGOR <FUREUNOIR> GORBUNOV
|
# Copyright (C) 2025 EGOR <FUREUNOIR> GORBUNOV
|
||||||
# This file is distributed under the same license as the EVIBES package.
|
# This file is distributed under the same license as the EVIBES package.
|
||||||
# EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>, 2025.
|
# EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>, 2025.
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 3.0.0\n"
|
"Project-Id-Version: EVIBES 3.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-10-07 15:47+0300\n"
|
"POT-Creation-Date: 2025-10-13 13:56+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,12 @@
|
||||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||||
# This file is distributed under the same license as the PACKAGE package.
|
# This file is distributed under the same license as the PACKAGE package.
|
||||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-10-07 15:47+0300\n"
|
"POT-Creation-Date: 2025-10-13 13:56+0300\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 3.0.0\n"
|
"Project-Id-Version: EVIBES 3.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-10-07 15:47+0300\n"
|
"POT-Creation-Date: 2025-10-13 13:56+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 3.0.0\n"
|
"Project-Id-Version: EVIBES 3.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-10-07 15:47+0300\n"
|
"POT-Creation-Date: 2025-10-13 13:56+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 3.0.0\n"
|
"Project-Id-Version: EVIBES 3.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-10-07 15:47+0300\n"
|
"POT-Creation-Date: 2025-10-13 13:56+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,12 @@
|
||||||
# Copyright (C) 2025 EGOR <FUREUNOIR> GORBUNOV
|
# Copyright (C) 2025 EGOR <FUREUNOIR> GORBUNOV
|
||||||
# This file is distributed under the same license as the EVIBES package.
|
# This file is distributed under the same license as the EVIBES package.
|
||||||
# EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>, 2025.
|
# EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>, 2025.
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 3.0.0\n"
|
"Project-Id-Version: EVIBES 3.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-10-07 15:47+0300\n"
|
"POT-Creation-Date: 2025-10-13 13:56+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 3.0.0\n"
|
"Project-Id-Version: EVIBES 3.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-10-07 15:47+0300\n"
|
"POT-Creation-Date: 2025-10-13 13:56+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 3.0.0\n"
|
"Project-Id-Version: EVIBES 3.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-10-07 15:47+0300\n"
|
"POT-Creation-Date: 2025-10-13 13:56+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 3.0.0\n"
|
"Project-Id-Version: EVIBES 3.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-10-07 15:47+0300\n"
|
"POT-Creation-Date: 2025-10-13 13:56+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 3.0.0\n"
|
"Project-Id-Version: EVIBES 3.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-10-07 15:47+0300\n"
|
"POT-Creation-Date: 2025-10-13 13:56+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 3.0.0\n"
|
"Project-Id-Version: EVIBES 3.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-10-07 15:47+0300\n"
|
"POT-Creation-Date: 2025-10-13 13:56+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 3.0.0\n"
|
"Project-Id-Version: EVIBES 3.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-10-07 15:47+0300\n"
|
"POT-Creation-Date: 2025-10-13 13:56+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 3.0.0\n"
|
"Project-Id-Version: EVIBES 3.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-10-07 15:47+0300\n"
|
"POT-Creation-Date: 2025-10-13 13:56+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 3.0.0\n"
|
"Project-Id-Version: EVIBES 3.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-10-07 15:47+0300\n"
|
"POT-Creation-Date: 2025-10-13 13:56+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 3.0.0\n"
|
"Project-Id-Version: EVIBES 3.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-10-07 15:47+0300\n"
|
"POT-Creation-Date: 2025-10-13 13:56+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 3.0.0\n"
|
"Project-Id-Version: EVIBES 3.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-10-07 15:47+0300\n"
|
"POT-Creation-Date: 2025-10-13 13:56+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 3.0.0\n"
|
"Project-Id-Version: EVIBES 3.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-10-07 15:47+0300\n"
|
"POT-Creation-Date: 2025-10-13 13:56+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 3.0.0\n"
|
"Project-Id-Version: EVIBES 3.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-10-07 15:47+0300\n"
|
"POT-Creation-Date: 2025-10-13 13:56+0300\n"
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ from blog.serializers import PostSerializer
|
||||||
from core.permissions import EvibesPermission
|
from core.permissions import EvibesPermission
|
||||||
|
|
||||||
|
|
||||||
class PostViewSet(ReadOnlyModelViewSet):
|
class PostViewSet(ReadOnlyModelViewSet): # type: ignore [type-arg]
|
||||||
"""
|
"""
|
||||||
Encapsulates operations for managing and retrieving Post entities in a read-only model view set.
|
Encapsulates operations for managing and retrieving Post entities in a read-only model view set.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
|
from django.forms.renderers import BaseRenderer
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -7,7 +10,10 @@ class MarkdownEditorWidget(forms.Textarea):
|
||||||
css = {"all": ("https://cdnjs.cloudflare.com/ajax/libs/easymde/2.14.0/easymde.min.css",)}
|
css = {"all": ("https://cdnjs.cloudflare.com/ajax/libs/easymde/2.14.0/easymde.min.css",)}
|
||||||
js = ("https://cdnjs.cloudflare.com/ajax/libs/easymde/2.14.0/easymde.min.js",)
|
js = ("https://cdnjs.cloudflare.com/ajax/libs/easymde/2.14.0/easymde.min.js",)
|
||||||
|
|
||||||
def render(self, name, value, attrs=None, renderer=None):
|
def render(self, name: str, value: str, attrs: dict[Any, Any] | None = None, renderer: BaseRenderer | None = None):
|
||||||
|
if not attrs:
|
||||||
|
attrs = {}
|
||||||
|
attrs["class"] = "markdown-editor"
|
||||||
textarea_html = super().render(name, value, attrs, renderer)
|
textarea_html = super().render(name, value, attrs, renderer)
|
||||||
textarea_id = attrs.get("id", f"id_{name}")
|
textarea_id = attrs.get("id", f"id_{name}")
|
||||||
init_js = f"""
|
init_js = f"""
|
||||||
|
|
|
||||||
|
|
@ -20,16 +20,16 @@ class NiceModel(Model):
|
||||||
verbose_name=_("is active"),
|
verbose_name=_("is active"),
|
||||||
help_text=_("if set to false, this object can't be seen by users without needed permission"),
|
help_text=_("if set to false, this object can't be seen by users without needed permission"),
|
||||||
)
|
)
|
||||||
created = CreationDateTimeField(_("created"), help_text=_("when the object first appeared on the database"))
|
created = CreationDateTimeField(_("created"), help_text=_("when the object first appeared on the database")) # type: ignore [no-untyped-call]
|
||||||
modified = ModificationDateTimeField(_("modified"), help_text=_("when the object was last modified"))
|
modified = ModificationDateTimeField(_("modified"), help_text=_("when the object was last modified")) # type: ignore [no-untyped-call]
|
||||||
|
|
||||||
def save(
|
def save( # type: ignore [override]
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
force_insert: bool = False,
|
force_insert: bool = False,
|
||||||
force_update: bool = False,
|
force_update: bool = False,
|
||||||
using: str | None = None,
|
using: str | None = None,
|
||||||
update_fields: Collection | None = None,
|
update_fields: Collection[str] | None = None,
|
||||||
update_modified: bool = True,
|
update_modified: bool = True,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.update_modified = update_modified
|
self.update_modified = update_modified
|
||||||
|
|
|
||||||
716
core/admin.py
716
core/admin.py
File diff suppressed because it is too large
Load diff
|
|
@ -11,6 +11,6 @@ class CoreConfig(AppConfig):
|
||||||
hide = False
|
hide = False
|
||||||
|
|
||||||
# noinspection PyUnresolvedReferences
|
# noinspection PyUnresolvedReferences
|
||||||
def ready(self):
|
def ready(self) -> None:
|
||||||
import core.elasticsearch.documents
|
import core.elasticsearch.documents
|
||||||
import core.signals # noqa: F401
|
import core.signals # noqa: F401
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ def process_query(
|
||||||
request: Request | None = None,
|
request: Request | None = None,
|
||||||
indexes: tuple[str, ...] = ("categories", "brands", "products"),
|
indexes: tuple[str, ...] = ("categories", "brands", "products"),
|
||||||
use_transliteration: bool = True,
|
use_transliteration: bool = True,
|
||||||
) -> dict[str, list[dict]] | None:
|
) -> dict[str, list[dict[str, Any]]] | None:
|
||||||
if not query:
|
if not query:
|
||||||
raise ValueError(_("no search term provided."))
|
raise ValueError(_("no search term provided."))
|
||||||
|
|
||||||
|
|
@ -235,7 +235,7 @@ def process_query(
|
||||||
):
|
):
|
||||||
hit_cache.append(h)
|
hit_cache.append(h)
|
||||||
if getattr(h, "uuid", None):
|
if getattr(h, "uuid", None):
|
||||||
uuids_by_index.setdefault(h.meta.index, []).append(str(h.uuid))
|
uuids_by_index.setdefault(h.meta.index, []).append({"uuid": str(h.uuid)})
|
||||||
|
|
||||||
products_by_uuid = {}
|
products_by_uuid = {}
|
||||||
brands_by_uuid = {}
|
brands_by_uuid = {}
|
||||||
|
|
@ -329,9 +329,9 @@ def _lang_analyzer(lang_code: str) -> str:
|
||||||
|
|
||||||
class ActiveOnlyMixin:
|
class ActiveOnlyMixin:
|
||||||
def get_queryset(self) -> QuerySet[Any]:
|
def get_queryset(self) -> QuerySet[Any]:
|
||||||
return super().get_queryset().filter(is_active=True)
|
return super().get_queryset().filter(is_active=True) # type: ignore [no-any-return, misc]
|
||||||
|
|
||||||
def should_index_object(self, obj) -> bool:
|
def should_index_object(self, obj) -> bool: # type: ignore [no-untyped-def]
|
||||||
return getattr(obj, "is_active", False)
|
return getattr(obj, "is_active", False)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -436,7 +436,7 @@ COMMON_ANALYSIS = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def add_multilang_fields(cls) -> None:
|
def add_multilang_fields(cls: Any) -> None:
|
||||||
for code, _lang in settings.LANGUAGES:
|
for code, _lang in settings.LANGUAGES:
|
||||||
lc = code.replace("-", "_").lower()
|
lc = code.replace("-", "_").lower()
|
||||||
name_field = f"name_{lc}"
|
name_field = f"name_{lc}"
|
||||||
|
|
@ -480,10 +480,11 @@ def add_multilang_fields(cls) -> None:
|
||||||
setattr(cls, f"prepare_{desc_field}", make_prepare(desc_field))
|
setattr(cls, f"prepare_{desc_field}", make_prepare(desc_field))
|
||||||
|
|
||||||
|
|
||||||
def populate_index():
|
def populate_index() -> None:
|
||||||
for doc in registry.get_documents(set(registry.get_models())):
|
for doc in registry.get_documents(set(registry.get_models())):
|
||||||
qs = doc().get_indexing_queryset()
|
qs = doc().get_indexing_queryset()
|
||||||
doc().update(qs, parallel=True, refresh=True)
|
doc().update(qs, parallel=True, refresh=True)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def process_system_query(
|
def process_system_query(
|
||||||
|
|
@ -493,7 +494,7 @@ def process_system_query(
|
||||||
size_per_index: int = 25,
|
size_per_index: int = 25,
|
||||||
language_code: str | None = None,
|
language_code: str | None = None,
|
||||||
use_transliteration: bool = True,
|
use_transliteration: bool = True,
|
||||||
) -> dict[str, list[dict]]:
|
) -> dict[str, list[dict[str, Any]]]:
|
||||||
if not query:
|
if not query:
|
||||||
raise ValueError(_("no search term provided."))
|
raise ValueError(_("no search term provided."))
|
||||||
|
|
||||||
|
|
@ -526,7 +527,7 @@ def process_system_query(
|
||||||
**({"fuzziness": fuzzy} if fuzzy else {}),
|
**({"fuzziness": fuzzy} if fuzzy else {}),
|
||||||
)
|
)
|
||||||
|
|
||||||
results: dict[str, list[dict]] = {idx: [] for idx in indexes}
|
results: dict[str, list[dict[str, Any]]] = {idx: [] for idx in indexes}
|
||||||
|
|
||||||
for idx in indexes:
|
for idx in indexes:
|
||||||
s = Search(index=[idx]).query(mm).extra(size=size_per_index, track_total_hits=False)
|
s = Search(index=[idx]).query(mm).extra(size=size_per_index, track_total_hits=False)
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from django.db.models import Model, QuerySet
|
||||||
from django_elasticsearch_dsl import Document, fields
|
from django_elasticsearch_dsl import Document, fields
|
||||||
from django_elasticsearch_dsl.registries import registry
|
from django_elasticsearch_dsl.registries import registry
|
||||||
from health_check.db.models import TestModel
|
from health_check.db.models import TestModel
|
||||||
|
|
@ -6,7 +9,7 @@ from core.elasticsearch import COMMON_ANALYSIS, ActiveOnlyMixin, add_multilang_f
|
||||||
from core.models import Brand, Category, Product
|
from core.models import Brand, Category, Product
|
||||||
|
|
||||||
|
|
||||||
class BaseDocument(Document):
|
class BaseDocument(Document): # type: ignore [misc]
|
||||||
name = fields.TextField(
|
name = fields.TextField(
|
||||||
attr="name",
|
attr="name",
|
||||||
analyzer="standard",
|
analyzer="standard",
|
||||||
|
|
@ -39,10 +42,10 @@ class BaseDocument(Document):
|
||||||
"index": {"max_ngram_diff": 20},
|
"index": {"max_ngram_diff": 20},
|
||||||
}
|
}
|
||||||
|
|
||||||
def prepare_name(self, instance):
|
def prepare_name(self, instance: Model) -> str:
|
||||||
return getattr(instance, "name", "") or ""
|
return getattr(instance, "name", "") or ""
|
||||||
|
|
||||||
def prepare_description(self, instance):
|
def prepare_description(self, instance: Model) -> str:
|
||||||
return getattr(instance, "description", "") or ""
|
return getattr(instance, "description", "") or ""
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -103,7 +106,7 @@ class ProductDocument(ActiveOnlyMixin, BaseDocument):
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self) -> QuerySet[Product]:
|
||||||
return (
|
return (
|
||||||
super()
|
super()
|
||||||
.get_queryset()
|
.get_queryset()
|
||||||
|
|
@ -156,7 +159,7 @@ add_multilang_fields(BrandDocument)
|
||||||
registry.register_document(BrandDocument)
|
registry.register_document(BrandDocument)
|
||||||
|
|
||||||
|
|
||||||
class TestModelDocument(Document):
|
class TestModelDocument(Document): # type: ignore [misc]
|
||||||
class Index:
|
class Index:
|
||||||
name = "testmodels"
|
name = "testmodels"
|
||||||
|
|
||||||
|
|
@ -164,7 +167,7 @@ class TestModelDocument(Document):
|
||||||
model = TestModel
|
model = TestModel
|
||||||
fields = ["title"]
|
fields = ["title"]
|
||||||
ignore_signals = True
|
ignore_signals = True
|
||||||
related_models: list = []
|
related_models: list[Any] = []
|
||||||
auto_refresh = False
|
auto_refresh = False
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import uuid
|
import uuid
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from django.core.exceptions import BadRequest
|
from django.core.exceptions import BadRequest
|
||||||
from django.db.models import (
|
from django.db.models import (
|
||||||
|
|
@ -19,6 +20,7 @@ from django.db.models import (
|
||||||
When,
|
When,
|
||||||
)
|
)
|
||||||
from django.db.models.functions import Coalesce
|
from django.db.models.functions import Coalesce
|
||||||
|
from django.http import HttpRequest
|
||||||
from django.utils.http import urlsafe_base64_decode
|
from django.utils.http import urlsafe_base64_decode
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django_filters import (
|
from django_filters import (
|
||||||
|
|
@ -31,6 +33,8 @@ from django_filters import (
|
||||||
OrderingFilter,
|
OrderingFilter,
|
||||||
UUIDFilter,
|
UUIDFilter,
|
||||||
)
|
)
|
||||||
|
from graphene import Context
|
||||||
|
from rest_framework.request import Request
|
||||||
|
|
||||||
from core.elasticsearch import process_query
|
from core.elasticsearch import process_query
|
||||||
from core.models import Address, Brand, Category, Feedback, Order, Product, Stock, Wishlist
|
from core.models import Address, Brand, Category, Feedback, Order, Product, Stock, Wishlist
|
||||||
|
|
@ -38,8 +42,8 @@ from core.models import Address, Brand, Category, Feedback, Order, Product, Stoc
|
||||||
logger = logging.getLogger("django")
|
logger = logging.getLogger("django")
|
||||||
|
|
||||||
|
|
||||||
class CaseInsensitiveListFilter(BaseInFilter, CharFilter):
|
class CaseInsensitiveListFilter(BaseInFilter, CharFilter): # type: ignore [misc]
|
||||||
def filter(self, qs, value):
|
def filter(self, qs: QuerySet[Any], value: Any) -> QuerySet[Any]:
|
||||||
if not value:
|
if not value:
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
|
|
@ -61,7 +65,7 @@ class CaseInsensitiveListFilter(BaseInFilter, CharFilter):
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyUnusedLocal
|
# noinspection PyUnusedLocal
|
||||||
class ProductFilter(FilterSet):
|
class ProductFilter(FilterSet): # type: ignore [misc]
|
||||||
search = CharFilter(field_name="name", method="search_products", label=_("Search"))
|
search = CharFilter(field_name="name", method="search_products", label=_("Search"))
|
||||||
uuid = UUIDFilter(field_name="uuid", lookup_expr="exact", label=_("UUID"))
|
uuid = UUIDFilter(field_name="uuid", lookup_expr="exact", label=_("UUID"))
|
||||||
name = CharFilter(lookup_expr="icontains", label=_("Name"))
|
name = CharFilter(lookup_expr="icontains", label=_("Name"))
|
||||||
|
|
@ -121,7 +125,15 @@ class ProductFilter(FilterSet):
|
||||||
"order_by",
|
"order_by",
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, data=None, queryset=None, *, request=None, prefix=None):
|
# noinspection PyTypeHints
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
data: dict[Any, Any] | None = None,
|
||||||
|
queryset: QuerySet[Product] | None = None,
|
||||||
|
*,
|
||||||
|
request: HttpRequest | Request | Context = None,
|
||||||
|
prefix: str | None = None,
|
||||||
|
) -> None:
|
||||||
super().__init__(data=data, queryset=queryset, request=request, prefix=prefix)
|
super().__init__(data=data, queryset=queryset, request=request, prefix=prefix)
|
||||||
ordering_param = self.data.get("order_by", "")
|
ordering_param = self.data.get("order_by", "")
|
||||||
if ordering_param:
|
if ordering_param:
|
||||||
|
|
@ -133,7 +145,7 @@ class ProductFilter(FilterSet):
|
||||||
.annotate(avg_rating=Avg("rating"))
|
.annotate(avg_rating=Avg("rating"))
|
||||||
.values("avg_rating")
|
.values("avg_rating")
|
||||||
)
|
)
|
||||||
self.queryset = self.queryset.annotate(
|
self.queryset: QuerySet[Product] = self.queryset.annotate(
|
||||||
rating=Coalesce(
|
rating=Coalesce(
|
||||||
Subquery(feedback_qs, output_field=FloatField()),
|
Subquery(feedback_qs, output_field=FloatField()),
|
||||||
Value(0, output_field=FloatField()),
|
Value(0, output_field=FloatField()),
|
||||||
|
|
@ -148,7 +160,7 @@ class ProductFilter(FilterSet):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def search_products(self, queryset: QuerySet[Product], name, value):
|
def search_products(self, queryset: QuerySet[Product], name: str, value: str) -> QuerySet[Product]:
|
||||||
if not value:
|
if not value:
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|
@ -156,17 +168,17 @@ class ProductFilter(FilterSet):
|
||||||
|
|
||||||
return queryset.filter(uuid__in=uuids)
|
return queryset.filter(uuid__in=uuids)
|
||||||
|
|
||||||
def filter_include_flag(self, queryset, name, value):
|
def filter_include_flag(self, queryset: QuerySet[Product], name: str, value: str) -> QuerySet[Product]:
|
||||||
if not self.data.get("category_uuid"):
|
if not self.data.get("category_uuid"):
|
||||||
raise BadRequest(_("there must be a category_uuid to use include_subcategories flag"))
|
raise BadRequest(_("there must be a category_uuid to use include_subcategories flag"))
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
def filter_include_personal_ordered(self, queryset, name, value):
|
def filter_include_personal_ordered(self, queryset: QuerySet[Product], name: str, value: str) -> QuerySet[Product]:
|
||||||
if self.data.get("include_personal_ordered", False):
|
if self.data.get("include_personal_ordered", False):
|
||||||
queryset = queryset.filter(stocks__isnull=False, stocks__quantity__gt=0, stocks__price__gt=0)
|
queryset = queryset.filter(stocks__isnull=False, stocks__quantity__gt=0, stocks__price__gt=0)
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
def filter_attributes(self, queryset, name, value):
|
def filter_attributes(self, queryset: QuerySet[Product], name: str, value: str) -> QuerySet[Product]:
|
||||||
if not value:
|
if not value:
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|
@ -228,7 +240,7 @@ class ProductFilter(FilterSet):
|
||||||
|
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
def filter_category(self, queryset, name, value):
|
def filter_category(self, queryset: QuerySet[Product], name: str, value: str) -> QuerySet[Product]:
|
||||||
if not value:
|
if not value:
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|
@ -247,7 +259,7 @@ class ProductFilter(FilterSet):
|
||||||
return queryset.filter(category__uuid=value)
|
return queryset.filter(category__uuid=value)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _infer_type(value):
|
def _infer_type(value: str) -> Any:
|
||||||
try:
|
try:
|
||||||
parsed_value = json.loads(value)
|
parsed_value = json.loads(value)
|
||||||
if isinstance(parsed_value, list | dict):
|
if isinstance(parsed_value, list | dict):
|
||||||
|
|
@ -271,7 +283,7 @@ class ProductFilter(FilterSet):
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def qs(self):
|
def qs(self) -> QuerySet[Product]:
|
||||||
qs = super().qs
|
qs = super().qs
|
||||||
|
|
||||||
ordering_param = self.data.get("order_by", "")
|
ordering_param = self.data.get("order_by", "")
|
||||||
|
|
@ -320,7 +332,8 @@ class ProductFilter(FilterSet):
|
||||||
return qs.distinct()
|
return qs.distinct()
|
||||||
|
|
||||||
|
|
||||||
class OrderFilter(FilterSet):
|
# noinspection PyUnusedLocal
|
||||||
|
class OrderFilter(FilterSet): # type: ignore [misc]
|
||||||
search = CharFilter(
|
search = CharFilter(
|
||||||
method="filter_search",
|
method="filter_search",
|
||||||
label=_("Search (ID, product name or part number)"),
|
label=_("Search (ID, product name or part number)"),
|
||||||
|
|
@ -367,7 +380,7 @@ class OrderFilter(FilterSet):
|
||||||
"max_buy_time",
|
"max_buy_time",
|
||||||
]
|
]
|
||||||
|
|
||||||
def filter_search(self, queryset, _name, value):
|
def filter_search(self, queryset: QuerySet[Order], name: str, value: str):
|
||||||
return queryset.filter(
|
return queryset.filter(
|
||||||
Q(human_readable_id__icontains=value)
|
Q(human_readable_id__icontains=value)
|
||||||
| Q(order_products__product__name__icontains=value)
|
| Q(order_products__product__name__icontains=value)
|
||||||
|
|
@ -375,7 +388,7 @@ class OrderFilter(FilterSet):
|
||||||
).distinct()
|
).distinct()
|
||||||
|
|
||||||
|
|
||||||
class WishlistFilter(FilterSet):
|
class WishlistFilter(FilterSet): # type: ignore [misc]
|
||||||
uuid = UUIDFilter(field_name="uuid", lookup_expr="exact")
|
uuid = UUIDFilter(field_name="uuid", lookup_expr="exact")
|
||||||
user_email = CharFilter(field_name="user__email", lookup_expr="iexact", label=_("User email"))
|
user_email = CharFilter(field_name="user__email", lookup_expr="iexact", label=_("User email"))
|
||||||
user = UUIDFilter(field_name="user__uuid", lookup_expr="exact", label=_("User UUID"))
|
user = UUIDFilter(field_name="user__uuid", lookup_expr="exact", label=_("User UUID"))
|
||||||
|
|
@ -395,7 +408,7 @@ class WishlistFilter(FilterSet):
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyUnusedLocal
|
# noinspection PyUnusedLocal
|
||||||
class CategoryFilter(FilterSet):
|
class CategoryFilter(FilterSet): # type: ignore [misc]
|
||||||
search = CharFilter(field_name="name", method="search_categories", label=_("Search"))
|
search = CharFilter(field_name="name", method="search_categories", label=_("Search"))
|
||||||
uuid = UUIDFilter(field_name="uuid", lookup_expr="exact")
|
uuid = UUIDFilter(field_name="uuid", lookup_expr="exact")
|
||||||
name = CharFilter(lookup_expr="icontains", label=_("Name"))
|
name = CharFilter(lookup_expr="icontains", label=_("Name"))
|
||||||
|
|
@ -424,7 +437,7 @@ class CategoryFilter(FilterSet):
|
||||||
"whole",
|
"whole",
|
||||||
]
|
]
|
||||||
|
|
||||||
def search_categories(self, queryset: QuerySet[Product], name, value):
|
def search_categories(self, queryset: QuerySet[Category], name: str, value: str) -> QuerySet[Category]:
|
||||||
if not value:
|
if not value:
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|
@ -432,7 +445,7 @@ class CategoryFilter(FilterSet):
|
||||||
|
|
||||||
return queryset.filter(uuid__in=uuids)
|
return queryset.filter(uuid__in=uuids)
|
||||||
|
|
||||||
def filter_order_by(self, queryset, _name, value):
|
def filter_order_by(self, queryset: QuerySet[Category], name: str, value: str) -> QuerySet[Category]:
|
||||||
if not value:
|
if not value:
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|
@ -456,7 +469,7 @@ class CategoryFilter(FilterSet):
|
||||||
|
|
||||||
qs = queryset.order_by(order_expression).prefetch_related(None)
|
qs = queryset.order_by(order_expression).prefetch_related(None)
|
||||||
|
|
||||||
def create_ordered_tree_prefetch(max_depth=10):
|
def create_ordered_tree_prefetch(max_depth=10) -> Prefetch | None:
|
||||||
if field == "?":
|
if field == "?":
|
||||||
|
|
||||||
def build_random_prefetch(depth):
|
def build_random_prefetch(depth):
|
||||||
|
|
@ -494,7 +507,7 @@ class CategoryFilter(FilterSet):
|
||||||
|
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
def filter_whole_categories(self, queryset, _name, value):
|
def filter_whole_categories(self, queryset: QuerySet[Category], name: str, value: str) -> QuerySet[Category]:
|
||||||
has_own_products = Exists(Product.objects.filter(category=OuterRef("pk")))
|
has_own_products = Exists(Product.objects.filter(category=OuterRef("pk")))
|
||||||
has_desc_products = Exists(
|
has_desc_products = Exists(
|
||||||
Product.objects.filter(
|
Product.objects.filter(
|
||||||
|
|
@ -509,7 +522,7 @@ class CategoryFilter(FilterSet):
|
||||||
return annotated.filter(has_products=True).distinct()
|
return annotated.filter(has_products=True).distinct()
|
||||||
return annotated.filter(has_products=False).distinct()
|
return annotated.filter(has_products=False).distinct()
|
||||||
|
|
||||||
def filter_parent_uuid(self, queryset, _name, value):
|
def filter_parent_uuid(self, queryset: QuerySet[Category], name: str, value: str):
|
||||||
if value in ("", "null", "None"):
|
if value in ("", "null", "None"):
|
||||||
return queryset.filter(parent=None)
|
return queryset.filter(parent=None)
|
||||||
|
|
||||||
|
|
@ -522,7 +535,7 @@ class CategoryFilter(FilterSet):
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyUnusedLocal
|
# noinspection PyUnusedLocal
|
||||||
class BrandFilter(FilterSet):
|
class BrandFilter(FilterSet): # type: ignore [misc]
|
||||||
search = CharFilter(field_name="name", method="search_brands", label=_("Search"))
|
search = CharFilter(field_name="name", method="search_brands", label=_("Search"))
|
||||||
uuid = UUIDFilter(field_name="uuid", lookup_expr="exact")
|
uuid = UUIDFilter(field_name="uuid", lookup_expr="exact")
|
||||||
name = CharFilter(lookup_expr="icontains", label=_("Name"))
|
name = CharFilter(lookup_expr="icontains", label=_("Name"))
|
||||||
|
|
@ -543,7 +556,7 @@ class BrandFilter(FilterSet):
|
||||||
model = Brand
|
model = Brand
|
||||||
fields = ["uuid", "name", "slug", "priority"]
|
fields = ["uuid", "name", "slug", "priority"]
|
||||||
|
|
||||||
def search_brands(self, queryset: QuerySet[Product], name, value):
|
def search_brands(self, queryset: QuerySet[Brand], name: str, value: str) -> QuerySet[Brand]:
|
||||||
if not value:
|
if not value:
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|
@ -552,7 +565,7 @@ class BrandFilter(FilterSet):
|
||||||
return queryset.filter(uuid__in=uuids)
|
return queryset.filter(uuid__in=uuids)
|
||||||
|
|
||||||
|
|
||||||
class FeedbackFilter(FilterSet):
|
class FeedbackFilter(FilterSet): # type: ignore [misc]
|
||||||
uuid = UUIDFilter(field_name="uuid", lookup_expr="exact", label=_("UUID"))
|
uuid = UUIDFilter(field_name="uuid", lookup_expr="exact", label=_("UUID"))
|
||||||
product_uuid = UUIDFilter(
|
product_uuid = UUIDFilter(
|
||||||
field_name="order_product__product__uuid",
|
field_name="order_product__product__uuid",
|
||||||
|
|
@ -581,7 +594,7 @@ class FeedbackFilter(FilterSet):
|
||||||
fields = ["uuid", "product_uuid", "user_uuid", "order_by"]
|
fields = ["uuid", "product_uuid", "user_uuid", "order_by"]
|
||||||
|
|
||||||
|
|
||||||
class AddressFilter(FilterSet):
|
class AddressFilter(FilterSet): # type: ignore [misc]
|
||||||
uuid = UUIDFilter(field_name="uuid", lookup_expr="exact", label=_("UUID"))
|
uuid = UUIDFilter(field_name="uuid", lookup_expr="exact", label=_("UUID"))
|
||||||
user_uuid = UUIDFilter(field_name="user__uuid", lookup_expr="exact", label=_("User UUID"))
|
user_uuid = UUIDFilter(field_name="user__uuid", lookup_expr="exact", label=_("User UUID"))
|
||||||
user_email = CharFilter(field_name="user__email", lookup_expr="iexact", label=_("User email"))
|
user_email = CharFilter(field_name="user__email", lookup_expr="iexact", label=_("User email"))
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,16 @@ class VendorForm(forms.ModelForm):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class CRMForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = Product
|
||||||
|
fields = "__all__"
|
||||||
|
widgets = {
|
||||||
|
"authentication": JSONTableWidget(),
|
||||||
|
"attributes": JSONTableWidget(),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class OrderProductForm(forms.ModelForm):
|
class OrderProductForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = OrderProduct
|
model = OrderProduct
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from graphene import Mutation
|
from graphene import Mutation
|
||||||
|
|
||||||
|
|
||||||
class BaseMutation(Mutation): # type: ignore [misc]
|
class BaseMutation(Mutation): # type: ignore [misc]
|
||||||
def __init__(self, *args, **kwargs) -> None:
|
def __init__(self, *args: list[Any], **kwargs: dict[Any, Any]) -> None:
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mutate(**kwargs) -> None:
|
def mutate(**kwargs: Any) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
|
|
@ -31,6 +32,7 @@ from payments.graphene.object_types import TransactionType
|
||||||
logger = logging.getLogger("django")
|
logger = logging.getLogger("django")
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal
|
||||||
class CacheOperator(BaseMutation):
|
class CacheOperator(BaseMutation):
|
||||||
class Meta:
|
class Meta:
|
||||||
description = _("cache I/O")
|
description = _("cache I/O")
|
||||||
|
|
@ -46,10 +48,11 @@ class CacheOperator(BaseMutation):
|
||||||
data = GenericScalar(description=_("cached data"))
|
data = GenericScalar(description=_("cached data"))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mutate(_parent, info, key, data=None, timeout=None):
|
def mutate(parent, info, key, data=None, timeout=None) -> dict[Any, Any]: # type: ignore [override]
|
||||||
return camelize(web_cache(info.context, key, data, timeout))
|
return camelize(web_cache(info.context, key, data, timeout))
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal
|
||||||
class RequestCursedURL(BaseMutation):
|
class RequestCursedURL(BaseMutation):
|
||||||
class Meta:
|
class Meta:
|
||||||
description = _("request a CORSed URL")
|
description = _("request a CORSed URL")
|
||||||
|
|
@ -60,7 +63,7 @@ class RequestCursedURL(BaseMutation):
|
||||||
data = GenericScalar(description=_("camelized JSON data from the requested URL"))
|
data = GenericScalar(description=_("camelized JSON data from the requested URL"))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mutate(_parent, info, url):
|
def mutate(parent, info, url) -> dict[str, Any]: # type: ignore [override]
|
||||||
if not is_url_safe(url):
|
if not is_url_safe(url):
|
||||||
raise BadRequest(_("only URLs starting with http(s):// are allowed"))
|
raise BadRequest(_("only URLs starting with http(s):// are allowed"))
|
||||||
try:
|
try:
|
||||||
|
|
@ -75,6 +78,7 @@ class RequestCursedURL(BaseMutation):
|
||||||
return {"data": {"error": str(e)}}
|
return {"data": {"error": str(e)}}
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal,PyTypeChecker
|
||||||
class AddOrderProduct(BaseMutation):
|
class AddOrderProduct(BaseMutation):
|
||||||
class Meta:
|
class Meta:
|
||||||
description = _("add a product to the order")
|
description = _("add a product to the order")
|
||||||
|
|
@ -87,7 +91,7 @@ class AddOrderProduct(BaseMutation):
|
||||||
order = Field(OrderType)
|
order = Field(OrderType)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mutate(_parent, info, product_uuid, order_uuid, attributes=None):
|
def mutate(parent, info, product_uuid, order_uuid, attributes=None): # type: ignore [override]
|
||||||
user = info.context.user
|
user = info.context.user
|
||||||
try:
|
try:
|
||||||
order = Order.objects.get(uuid=order_uuid)
|
order = Order.objects.get(uuid=order_uuid)
|
||||||
|
|
@ -101,6 +105,7 @@ class AddOrderProduct(BaseMutation):
|
||||||
raise Http404(_(f"order {order_uuid} not found")) from dne
|
raise Http404(_(f"order {order_uuid} not found")) from dne
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal
|
||||||
class RemoveOrderProduct(BaseMutation):
|
class RemoveOrderProduct(BaseMutation):
|
||||||
class Meta:
|
class Meta:
|
||||||
description = _("remove a product from the order")
|
description = _("remove a product from the order")
|
||||||
|
|
@ -113,7 +118,7 @@ class RemoveOrderProduct(BaseMutation):
|
||||||
order = Field(OrderType)
|
order = Field(OrderType)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mutate(_parent, info, product_uuid, order_uuid, attributes=None):
|
def mutate(parent, info, product_uuid, order_uuid, attributes=None) -> AddOrderProduct | None: # type: ignore [override]
|
||||||
user = info.context.user
|
user = info.context.user
|
||||||
try:
|
try:
|
||||||
order = Order.objects.get(uuid=order_uuid)
|
order = Order.objects.get(uuid=order_uuid)
|
||||||
|
|
@ -127,6 +132,7 @@ class RemoveOrderProduct(BaseMutation):
|
||||||
raise Http404(_(f"order {order_uuid} not found")) from dne
|
raise Http404(_(f"order {order_uuid} not found")) from dne
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal,PyTypeChecker
|
||||||
class RemoveAllOrderProducts(BaseMutation):
|
class RemoveAllOrderProducts(BaseMutation):
|
||||||
class Meta:
|
class Meta:
|
||||||
description = _("remove all products from the order")
|
description = _("remove all products from the order")
|
||||||
|
|
@ -137,7 +143,7 @@ class RemoveAllOrderProducts(BaseMutation):
|
||||||
order = Field(OrderType)
|
order = Field(OrderType)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mutate(_parent, info, order_uuid):
|
def mutate(parent, info, order_uuid): # type: ignore [override]
|
||||||
user = info.context.user
|
user = info.context.user
|
||||||
order = Order.objects.get(uuid=order_uuid)
|
order = Order.objects.get(uuid=order_uuid)
|
||||||
if not (user.has_perm("core.delete_orderproduct") or user == order.user):
|
if not (user.has_perm("core.delete_orderproduct") or user == order.user):
|
||||||
|
|
@ -148,6 +154,7 @@ class RemoveAllOrderProducts(BaseMutation):
|
||||||
return RemoveAllOrderProducts(order=order)
|
return RemoveAllOrderProducts(order=order)
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal,PyTypeChecker
|
||||||
class RemoveOrderProductsOfAKind(BaseMutation):
|
class RemoveOrderProductsOfAKind(BaseMutation):
|
||||||
class Meta:
|
class Meta:
|
||||||
description = _("remove a product from the order")
|
description = _("remove a product from the order")
|
||||||
|
|
@ -159,7 +166,7 @@ class RemoveOrderProductsOfAKind(BaseMutation):
|
||||||
order = Field(OrderType)
|
order = Field(OrderType)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mutate(_parent, info, product_uuid, order_uuid):
|
def mutate(parent, info, product_uuid, order_uuid): # type: ignore [override]
|
||||||
user = info.context.user
|
user = info.context.user
|
||||||
order = Order.objects.get(uuid=order_uuid)
|
order = Order.objects.get(uuid=order_uuid)
|
||||||
if not (user.has_perm("core.delete_orderproduct") or user == order.user):
|
if not (user.has_perm("core.delete_orderproduct") or user == order.user):
|
||||||
|
|
@ -170,6 +177,7 @@ class RemoveOrderProductsOfAKind(BaseMutation):
|
||||||
return RemoveOrderProductsOfAKind(order=order)
|
return RemoveOrderProductsOfAKind(order=order)
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal,PyTypeChecker
|
||||||
class BuyOrder(BaseMutation):
|
class BuyOrder(BaseMutation):
|
||||||
class Meta:
|
class Meta:
|
||||||
description = _("buy an order")
|
description = _("buy an order")
|
||||||
|
|
@ -189,7 +197,7 @@ class BuyOrder(BaseMutation):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mutate(
|
def mutate(
|
||||||
_parent,
|
parent,
|
||||||
info,
|
info,
|
||||||
order_uuid=None,
|
order_uuid=None,
|
||||||
order_hr_id=None,
|
order_hr_id=None,
|
||||||
|
|
@ -199,7 +207,7 @@ class BuyOrder(BaseMutation):
|
||||||
shipping_address=None,
|
shipping_address=None,
|
||||||
billing_address=None,
|
billing_address=None,
|
||||||
chosen_products=None,
|
chosen_products=None,
|
||||||
):
|
): # type: ignore [override]
|
||||||
if not any([order_uuid, order_hr_id]) or all([order_uuid, order_hr_id]):
|
if not any([order_uuid, order_hr_id]) or all([order_uuid, order_hr_id]):
|
||||||
raise BadRequest(_("please provide either order_uuid or order_hr_id - mutually exclusive"))
|
raise BadRequest(_("please provide either order_uuid or order_hr_id - mutually exclusive"))
|
||||||
user = info.context.user
|
user = info.context.user
|
||||||
|
|
@ -232,6 +240,7 @@ class BuyOrder(BaseMutation):
|
||||||
raise Http404(_(f"order {order_uuid} not found")) from dne
|
raise Http404(_(f"order {order_uuid} not found")) from dne
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal,PyTypeChecker
|
||||||
class BulkOrderAction(BaseMutation):
|
class BulkOrderAction(BaseMutation):
|
||||||
class Meta:
|
class Meta:
|
||||||
description = _("perform an action on a list of products in the order")
|
description = _("perform an action on a list of products in the order")
|
||||||
|
|
@ -246,13 +255,13 @@ class BulkOrderAction(BaseMutation):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mutate(
|
def mutate(
|
||||||
_parent,
|
parent,
|
||||||
info,
|
info,
|
||||||
action,
|
action,
|
||||||
products,
|
products,
|
||||||
order_uuid=None,
|
order_uuid=None,
|
||||||
order_hr_id=None,
|
order_hr_id=None,
|
||||||
):
|
): # type: ignore [override]
|
||||||
if not any([order_uuid, order_hr_id]) or all([order_uuid, order_hr_id]):
|
if not any([order_uuid, order_hr_id]) or all([order_uuid, order_hr_id]):
|
||||||
raise BadRequest(_("please provide either order_uuid or order_hr_id - mutually exclusive"))
|
raise BadRequest(_("please provide either order_uuid or order_hr_id - mutually exclusive"))
|
||||||
user = info.context.user
|
user = info.context.user
|
||||||
|
|
@ -279,6 +288,7 @@ class BulkOrderAction(BaseMutation):
|
||||||
raise Http404(_(f"order {order_uuid} not found")) from dne
|
raise Http404(_(f"order {order_uuid} not found")) from dne
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal,PyTypeChecker
|
||||||
class BulkWishlistAction(BaseMutation):
|
class BulkWishlistAction(BaseMutation):
|
||||||
class Meta:
|
class Meta:
|
||||||
description = _("perform an action on a list of products in the wishlist")
|
description = _("perform an action on a list of products in the wishlist")
|
||||||
|
|
@ -292,12 +302,12 @@ class BulkWishlistAction(BaseMutation):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mutate(
|
def mutate(
|
||||||
_parent,
|
parent,
|
||||||
info,
|
info,
|
||||||
action,
|
action,
|
||||||
products,
|
products,
|
||||||
wishlist_uuid=None,
|
wishlist_uuid=None,
|
||||||
):
|
): # type: ignore [override]
|
||||||
if not wishlist_uuid:
|
if not wishlist_uuid:
|
||||||
raise BadRequest(_("please provide wishlist_uuid value"))
|
raise BadRequest(_("please provide wishlist_uuid value"))
|
||||||
user = info.context.user
|
user = info.context.user
|
||||||
|
|
@ -319,6 +329,7 @@ class BulkWishlistAction(BaseMutation):
|
||||||
raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
|
raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal
|
||||||
class BuyUnregisteredOrder(BaseMutation):
|
class BuyUnregisteredOrder(BaseMutation):
|
||||||
class Meta:
|
class Meta:
|
||||||
description = _("purchase an order without account creation")
|
description = _("purchase an order without account creation")
|
||||||
|
|
@ -338,7 +349,7 @@ class BuyUnregisteredOrder(BaseMutation):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mutate(
|
def mutate(
|
||||||
_parent,
|
parent,
|
||||||
info,
|
info,
|
||||||
products,
|
products,
|
||||||
customer_name,
|
customer_name,
|
||||||
|
|
@ -349,7 +360,7 @@ class BuyUnregisteredOrder(BaseMutation):
|
||||||
customer_shipping_address=None,
|
customer_shipping_address=None,
|
||||||
promocode_uuid=None,
|
promocode_uuid=None,
|
||||||
is_business=False,
|
is_business=False,
|
||||||
):
|
): # type: ignore [override]
|
||||||
order = Order.objects.create(status="MOMENTAL")
|
order = Order.objects.create(status="MOMENTAL")
|
||||||
transaction = order.buy_without_registration(
|
transaction = order.buy_without_registration(
|
||||||
products=products,
|
products=products,
|
||||||
|
|
@ -362,9 +373,11 @@ class BuyUnregisteredOrder(BaseMutation):
|
||||||
payment_method=payment_method,
|
payment_method=payment_method,
|
||||||
is_business=is_business,
|
is_business=is_business,
|
||||||
)
|
)
|
||||||
|
# noinspection PyTypeChecker
|
||||||
return BuyUnregisteredOrder(transaction=transaction)
|
return BuyUnregisteredOrder(transaction=transaction)
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal,PyTypeChecker
|
||||||
class AddWishlistProduct(BaseMutation):
|
class AddWishlistProduct(BaseMutation):
|
||||||
class Meta:
|
class Meta:
|
||||||
description = _("add a product to the wishlist")
|
description = _("add a product to the wishlist")
|
||||||
|
|
@ -376,7 +389,7 @@ class AddWishlistProduct(BaseMutation):
|
||||||
wishlist = Field(WishlistType)
|
wishlist = Field(WishlistType)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mutate(_parent, info, product_uuid, wishlist_uuid):
|
def mutate(parent, info, product_uuid, wishlist_uuid): # type: ignore [override]
|
||||||
user = info.context.user
|
user = info.context.user
|
||||||
try:
|
try:
|
||||||
wishlist = Wishlist.objects.get(uuid=wishlist_uuid)
|
wishlist = Wishlist.objects.get(uuid=wishlist_uuid)
|
||||||
|
|
@ -392,6 +405,7 @@ class AddWishlistProduct(BaseMutation):
|
||||||
raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
|
raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal,PyTypeChecker
|
||||||
class RemoveWishlistProduct(BaseMutation):
|
class RemoveWishlistProduct(BaseMutation):
|
||||||
class Meta:
|
class Meta:
|
||||||
description = _("remove a product from the wishlist")
|
description = _("remove a product from the wishlist")
|
||||||
|
|
@ -403,7 +417,7 @@ class RemoveWishlistProduct(BaseMutation):
|
||||||
wishlist = Field(WishlistType)
|
wishlist = Field(WishlistType)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mutate(_parent, info, product_uuid, wishlist_uuid):
|
def mutate(parent, info, product_uuid, wishlist_uuid): # type: ignore [override]
|
||||||
user = info.context.user
|
user = info.context.user
|
||||||
try:
|
try:
|
||||||
wishlist = Wishlist.objects.get(uuid=wishlist_uuid)
|
wishlist = Wishlist.objects.get(uuid=wishlist_uuid)
|
||||||
|
|
@ -419,6 +433,7 @@ class RemoveWishlistProduct(BaseMutation):
|
||||||
raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
|
raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal,PyTypeChecker
|
||||||
class RemoveAllWishlistProducts(BaseMutation):
|
class RemoveAllWishlistProducts(BaseMutation):
|
||||||
class Meta:
|
class Meta:
|
||||||
description = _("remove all products from the wishlist")
|
description = _("remove all products from the wishlist")
|
||||||
|
|
@ -429,7 +444,7 @@ class RemoveAllWishlistProducts(BaseMutation):
|
||||||
wishlist = Field(WishlistType)
|
wishlist = Field(WishlistType)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mutate(_parent, info, wishlist_uuid):
|
def mutate(parent, info, wishlist_uuid): # type: ignore [override]
|
||||||
user = info.context.user
|
user = info.context.user
|
||||||
try:
|
try:
|
||||||
wishlist = Wishlist.objects.get(uuid=wishlist_uuid)
|
wishlist = Wishlist.objects.get(uuid=wishlist_uuid)
|
||||||
|
|
@ -446,6 +461,7 @@ class RemoveAllWishlistProducts(BaseMutation):
|
||||||
raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
|
raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal,PyTypeChecker
|
||||||
class BuyWishlist(BaseMutation):
|
class BuyWishlist(BaseMutation):
|
||||||
class Meta:
|
class Meta:
|
||||||
description = _("buy all products from the wishlist")
|
description = _("buy all products from the wishlist")
|
||||||
|
|
@ -459,7 +475,7 @@ class BuyWishlist(BaseMutation):
|
||||||
transaction = Field(TransactionType, required=False)
|
transaction = Field(TransactionType, required=False)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mutate(_parent, info, wishlist_uuid, force_balance=False, force_payment=False):
|
def mutate(parent, info, wishlist_uuid, force_balance=False, force_payment=False): # type: ignore [override]
|
||||||
user = info.context.user
|
user = info.context.user
|
||||||
try:
|
try:
|
||||||
wishlist = Wishlist.objects.get(uuid=wishlist_uuid)
|
wishlist = Wishlist.objects.get(uuid=wishlist_uuid)
|
||||||
|
|
@ -489,6 +505,7 @@ class BuyWishlist(BaseMutation):
|
||||||
raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
|
raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal,PyTypeChecker
|
||||||
class BuyProduct(BaseMutation):
|
class BuyProduct(BaseMutation):
|
||||||
class Meta:
|
class Meta:
|
||||||
description = _("buy a product")
|
description = _("buy a product")
|
||||||
|
|
@ -507,13 +524,13 @@ class BuyProduct(BaseMutation):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mutate(
|
def mutate(
|
||||||
_parent,
|
parent,
|
||||||
info,
|
info,
|
||||||
product_uuid,
|
product_uuid,
|
||||||
attributes=None,
|
attributes=None,
|
||||||
force_balance=False,
|
force_balance=False,
|
||||||
force_payment=False,
|
force_payment=False,
|
||||||
):
|
): # type: ignore [override]
|
||||||
user = info.context.user
|
user = info.context.user
|
||||||
order = Order.objects.create(user=user, status="MOMENTAL")
|
order = Order.objects.create(user=user, status="MOMENTAL")
|
||||||
order.add_product(product_uuid=product_uuid, attributes=format_attributes(attributes))
|
order.add_product(product_uuid=product_uuid, attributes=format_attributes(attributes))
|
||||||
|
|
@ -527,6 +544,7 @@ class BuyProduct(BaseMutation):
|
||||||
raise TypeError(_(f"wrong type came from order.buy() method: {type(instance)!s}"))
|
raise TypeError(_(f"wrong type came from order.buy() method: {type(instance)!s}"))
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal,PyTypeChecker
|
||||||
class FeedbackProductAction(BaseMutation):
|
class FeedbackProductAction(BaseMutation):
|
||||||
class Meta:
|
class Meta:
|
||||||
description = _("add or delete a feedback for orderproduct")
|
description = _("add or delete a feedback for orderproduct")
|
||||||
|
|
@ -540,7 +558,7 @@ class FeedbackProductAction(BaseMutation):
|
||||||
feedback = Field(FeedbackType, required=False)
|
feedback = Field(FeedbackType, required=False)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mutate(_parent, info, order_product_uuid, action, comment=None, rating=None):
|
def mutate(parent, info, order_product_uuid, action, comment=None, rating=None): # type: ignore [override]
|
||||||
user = info.context.user
|
user = info.context.user
|
||||||
try:
|
try:
|
||||||
order_product = OrderProduct.objects.get(uuid=order_product_uuid)
|
order_product = OrderProduct.objects.get(uuid=order_product_uuid)
|
||||||
|
|
@ -559,6 +577,7 @@ class FeedbackProductAction(BaseMutation):
|
||||||
raise Http404(_(f"order product {order_product_uuid} not found")) from dne
|
raise Http404(_(f"order product {order_product_uuid} not found")) from dne
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal,PyTypeChecker
|
||||||
class CreateProduct(BaseMutation):
|
class CreateProduct(BaseMutation):
|
||||||
class Arguments:
|
class Arguments:
|
||||||
name = String(required=True)
|
name = String(required=True)
|
||||||
|
|
@ -568,7 +587,7 @@ class CreateProduct(BaseMutation):
|
||||||
product = Field(ProductType)
|
product = Field(ProductType)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mutate(_parent, info, name, category_uuid, description=None):
|
def mutate(parent, info, name, category_uuid, description=None): # type: ignore [override]
|
||||||
if not info.context.user.has_perm("core.add_product"):
|
if not info.context.user.has_perm("core.add_product"):
|
||||||
raise PermissionDenied(permission_denied_message)
|
raise PermissionDenied(permission_denied_message)
|
||||||
category = Category.objects.get(uuid=category_uuid)
|
category = Category.objects.get(uuid=category_uuid)
|
||||||
|
|
@ -576,6 +595,7 @@ class CreateProduct(BaseMutation):
|
||||||
return CreateProduct(product=product)
|
return CreateProduct(product=product)
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal,PyTypeChecker
|
||||||
class UpdateProduct(BaseMutation):
|
class UpdateProduct(BaseMutation):
|
||||||
class Arguments:
|
class Arguments:
|
||||||
uuid = UUID(required=True)
|
uuid = UUID(required=True)
|
||||||
|
|
@ -586,7 +606,7 @@ class UpdateProduct(BaseMutation):
|
||||||
product = Field(ProductType)
|
product = Field(ProductType)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mutate(_parent, info, uuid, name=None, description=None, category_uuid=None):
|
def mutate(parent, info, uuid, name=None, description=None, category_uuid=None): # type: ignore [override]
|
||||||
user = info.context.user
|
user = info.context.user
|
||||||
if not user.has_perm("core.change_product"):
|
if not user.has_perm("core.change_product"):
|
||||||
raise PermissionDenied(permission_denied_message)
|
raise PermissionDenied(permission_denied_message)
|
||||||
|
|
@ -601,6 +621,7 @@ class UpdateProduct(BaseMutation):
|
||||||
return UpdateProduct(product=product)
|
return UpdateProduct(product=product)
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal,PyTypeChecker
|
||||||
class DeleteProduct(BaseMutation):
|
class DeleteProduct(BaseMutation):
|
||||||
class Arguments:
|
class Arguments:
|
||||||
uuid = UUID(required=True)
|
uuid = UUID(required=True)
|
||||||
|
|
@ -608,7 +629,7 @@ class DeleteProduct(BaseMutation):
|
||||||
ok = Boolean()
|
ok = Boolean()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mutate(_parent, info, uuid):
|
def mutate(parent, info, uuid): # type: ignore [override]
|
||||||
user = info.context.user
|
user = info.context.user
|
||||||
if not user.has_perm("core.delete_product"):
|
if not user.has_perm("core.delete_product"):
|
||||||
raise PermissionDenied(permission_denied_message)
|
raise PermissionDenied(permission_denied_message)
|
||||||
|
|
@ -617,6 +638,7 @@ class DeleteProduct(BaseMutation):
|
||||||
return DeleteProduct(ok=True)
|
return DeleteProduct(ok=True)
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal,PyTypeChecker
|
||||||
class CreateAddress(BaseMutation):
|
class CreateAddress(BaseMutation):
|
||||||
class Arguments:
|
class Arguments:
|
||||||
raw_data = String(required=True, description=_("original address string provided by the user"))
|
raw_data = String(required=True, description=_("original address string provided by the user"))
|
||||||
|
|
@ -624,13 +646,14 @@ class CreateAddress(BaseMutation):
|
||||||
address = Field(AddressType)
|
address = Field(AddressType)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mutate(_parent, info, raw_data):
|
def mutate(parent, info, raw_data): # type: ignore [override]
|
||||||
user = info.context.user if info.context.user.is_authenticated else None
|
user = info.context.user if info.context.user.is_authenticated else None
|
||||||
|
|
||||||
address = Address.objects.create(raw_data=raw_data, user=user)
|
address = Address.objects.create(raw_data=raw_data, user=user)
|
||||||
return CreateAddress(address=address)
|
return CreateAddress(address=address)
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal
|
||||||
class DeleteAddress(BaseMutation):
|
class DeleteAddress(BaseMutation):
|
||||||
class Arguments:
|
class Arguments:
|
||||||
uuid = UUID(required=True)
|
uuid = UUID(required=True)
|
||||||
|
|
@ -638,7 +661,7 @@ class DeleteAddress(BaseMutation):
|
||||||
success = Boolean()
|
success = Boolean()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mutate(_parent, info, uuid):
|
def mutate(parent, info, uuid): # type: ignore [override]
|
||||||
try:
|
try:
|
||||||
address = Address.objects.get(uuid=uuid)
|
address = Address.objects.get(uuid=uuid)
|
||||||
if (
|
if (
|
||||||
|
|
@ -647,6 +670,7 @@ class DeleteAddress(BaseMutation):
|
||||||
or info.context.user == address.user
|
or info.context.user == address.user
|
||||||
):
|
):
|
||||||
address.delete()
|
address.delete()
|
||||||
|
# noinspection PyTypeChecker
|
||||||
return DeleteAddress(success=True)
|
return DeleteAddress(success=True)
|
||||||
|
|
||||||
raise PermissionDenied(permission_denied_message)
|
raise PermissionDenied(permission_denied_message)
|
||||||
|
|
@ -656,6 +680,7 @@ class DeleteAddress(BaseMutation):
|
||||||
raise Http404(_(f"{name} does not exist: {uuid}")) from dne
|
raise Http404(_(f"{name} does not exist: {uuid}")) from dne
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal
|
||||||
class AutocompleteAddress(BaseMutation):
|
class AutocompleteAddress(BaseMutation):
|
||||||
class Arguments:
|
class Arguments:
|
||||||
q = String()
|
q = String()
|
||||||
|
|
@ -664,7 +689,7 @@ class AutocompleteAddress(BaseMutation):
|
||||||
suggestions = GenericScalar()
|
suggestions = GenericScalar()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mutate(_parent, info, q, limit):
|
def mutate(parent, info, q, limit): # type: ignore [override]
|
||||||
if 1 > limit > 10:
|
if 1 > limit > 10:
|
||||||
raise BadRequest(_("limit must be between 1 and 10"))
|
raise BadRequest(_("limit must be between 1 and 10"))
|
||||||
try:
|
try:
|
||||||
|
|
@ -672,9 +697,11 @@ class AutocompleteAddress(BaseMutation):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise BadRequest(f"geocoding error: {e!s}") from e
|
raise BadRequest(f"geocoding error: {e!s}") from e
|
||||||
|
|
||||||
|
# noinspection PyTypeChecker
|
||||||
return AutocompleteAddress(suggestions=suggestions)
|
return AutocompleteAddress(suggestions=suggestions)
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal
|
||||||
class ContactUs(BaseMutation):
|
class ContactUs(BaseMutation):
|
||||||
class Arguments:
|
class Arguments:
|
||||||
email = String(required=True)
|
email = String(required=True)
|
||||||
|
|
@ -687,7 +714,7 @@ class ContactUs(BaseMutation):
|
||||||
error = String()
|
error = String()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mutate(_parent, info, email, name, subject, message, phone_number=None):
|
def mutate(parent, info, email, name, subject, message, phone_number=None): # type: ignore [override]
|
||||||
try:
|
try:
|
||||||
contact_us_email.delay(
|
contact_us_email.delay(
|
||||||
{
|
{
|
||||||
|
|
@ -698,12 +725,14 @@ class ContactUs(BaseMutation):
|
||||||
"message": message,
|
"message": message,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
# noinspection PyTypeChecker
|
||||||
return ContactUs(received=True)
|
return ContactUs(received=True)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
# noinspection PyTypeChecker
|
||||||
return ContactUs(received=False, error=str(e))
|
return ContactUs(received=False, error=str(e))
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyArgumentList
|
# noinspection PyArgumentList PyUnusedLocal
|
||||||
class Search(BaseMutation):
|
class Search(BaseMutation):
|
||||||
class Arguments:
|
class Arguments:
|
||||||
query = String(required=True)
|
query = String(required=True)
|
||||||
|
|
@ -714,9 +743,10 @@ class Search(BaseMutation):
|
||||||
description = _("elasticsearch - works like a charm")
|
description = _("elasticsearch - works like a charm")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mutate(_parent, info, query):
|
def mutate(parent, info, query): # type: ignore [override]
|
||||||
data = process_query(query=query, request=info.context)
|
data = process_query(query=query, request=info.context)
|
||||||
|
|
||||||
|
# noinspection PyTypeChecker
|
||||||
return Search(
|
return Search(
|
||||||
results=SearchResultsType(
|
results=SearchResultsType(
|
||||||
products=data["products"],
|
products=data["products"],
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ from typing import Any
|
||||||
|
|
||||||
from constance import config
|
from constance import config
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.db.models import Max, Min
|
from django.db.models import Max, Min, QuerySet
|
||||||
from django.db.models.functions import Length
|
from django.db.models.functions import Length
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from graphene import (
|
from graphene import (
|
||||||
|
|
@ -60,7 +60,7 @@ from payments.graphene.object_types import TransactionType
|
||||||
logger = logging.getLogger("django")
|
logger = logging.getLogger("django")
|
||||||
|
|
||||||
|
|
||||||
class SEOMetaType(ObjectType):
|
class SEOMetaType(ObjectType): # type: ignore [misc]
|
||||||
title = String()
|
title = String()
|
||||||
description = String()
|
description = String()
|
||||||
canonical = String()
|
canonical = String()
|
||||||
|
|
@ -71,7 +71,7 @@ class SEOMetaType(ObjectType):
|
||||||
hreflang = String()
|
hreflang = String()
|
||||||
|
|
||||||
|
|
||||||
class AttributeType(DjangoObjectType):
|
class AttributeType(DjangoObjectType): # type: ignore [misc]
|
||||||
values = List(lambda: AttributeValueType, description=_("attribute values"))
|
values = List(lambda: AttributeValueType, description=_("attribute values"))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
@ -81,7 +81,7 @@ class AttributeType(DjangoObjectType):
|
||||||
filter_fields = ["uuid"]
|
filter_fields = ["uuid"]
|
||||||
description = _("attributes")
|
description = _("attributes")
|
||||||
|
|
||||||
def resolve_values(self, info):
|
def resolve_values(self, info) -> QuerySet[AttributeValue]:
|
||||||
base_qs = AttributeValue.objects.filter(attribute=self)
|
base_qs = AttributeValue.objects.filter(attribute=self)
|
||||||
product_uuid = getattr(info.context, "_product_uuid", None)
|
product_uuid = getattr(info.context, "_product_uuid", None)
|
||||||
|
|
||||||
|
|
@ -91,7 +91,7 @@ class AttributeType(DjangoObjectType):
|
||||||
return base_qs
|
return base_qs
|
||||||
|
|
||||||
|
|
||||||
class AttributeGroupType(DjangoObjectType):
|
class AttributeGroupType(DjangoObjectType): # type: ignore [misc]
|
||||||
attributes = List(lambda: AttributeType, description=_("grouped attributes"))
|
attributes = List(lambda: AttributeType, description=_("grouped attributes"))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
@ -101,7 +101,7 @@ class AttributeGroupType(DjangoObjectType):
|
||||||
filter_fields = ["uuid"]
|
filter_fields = ["uuid"]
|
||||||
description = _("groups of attributes")
|
description = _("groups of attributes")
|
||||||
|
|
||||||
def resolve_attributes(self: AttributeGroup, info):
|
def resolve_attributes(self: AttributeGroup, info) -> QuerySet[Attribute]:
|
||||||
product_uuid = getattr(info.context, "_product_uuid", None)
|
product_uuid = getattr(info.context, "_product_uuid", None)
|
||||||
|
|
||||||
qs = self.attributes.all()
|
qs = self.attributes.all()
|
||||||
|
|
@ -112,7 +112,7 @@ class AttributeGroupType(DjangoObjectType):
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
|
|
||||||
class BrandType(DjangoObjectType):
|
class BrandType(DjangoObjectType): # type: ignore [misc]
|
||||||
categories = List(lambda: CategoryType, description=_("categories"))
|
categories = List(lambda: CategoryType, description=_("categories"))
|
||||||
seo_meta = Field(SEOMetaType, description=_("SEO Meta snapshot"))
|
seo_meta = Field(SEOMetaType, description=_("SEO Meta snapshot"))
|
||||||
|
|
||||||
|
|
@ -123,18 +123,18 @@ class BrandType(DjangoObjectType):
|
||||||
filter_fields = ["uuid", "name"]
|
filter_fields = ["uuid", "name"]
|
||||||
description = _("brands")
|
description = _("brands")
|
||||||
|
|
||||||
def resolve_categories(self: Brand, info):
|
def resolve_categories(self: Brand, info) -> QuerySet[Category]:
|
||||||
if info.context.user.has_perm("core.view_category"):
|
if info.context.user.has_perm("core.view_category"):
|
||||||
return self.categories.all()
|
return self.categories.all()
|
||||||
return self.categories.filter(is_active=True)
|
return self.categories.filter(is_active=True)
|
||||||
|
|
||||||
def resolve_big_logo(self: Brand, info):
|
def resolve_big_logo(self: Brand, info) -> str | None:
|
||||||
return info.context.build_absolute_uri(self.big_logo.url) if self.big_logo else ""
|
return info.context.build_absolute_uri(self.big_logo.url) if self.big_logo else ""
|
||||||
|
|
||||||
def resolve_small_logo(self: Brand, info):
|
def resolve_small_logo(self: Brand, info) -> str | None:
|
||||||
return info.context.build_absolute_uri(self.small_logo.url) if self.small_logo else ""
|
return info.context.build_absolute_uri(self.small_logo.url) if self.small_logo else ""
|
||||||
|
|
||||||
def resolve_seo_meta(self: Brand, info):
|
def resolve_seo_meta(self: Brand, info) -> dict[str, str | list[Any] | dict[str, str] | None]:
|
||||||
lang = graphene_current_lang()
|
lang = graphene_current_lang()
|
||||||
base = f"https://{config.BASE_DOMAIN}"
|
base = f"https://{config.BASE_DOMAIN}"
|
||||||
canonical = f"{base}/{lang}/brand/{self.slug}"
|
canonical = f"{base}/{lang}/brand/{self.slug}"
|
||||||
|
|
@ -177,17 +177,17 @@ class BrandType(DjangoObjectType):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class FilterableAttributeType(ObjectType):
|
class FilterableAttributeType(ObjectType): # type: ignore [misc]
|
||||||
attribute_name = String(required=True)
|
attribute_name = String(required=True)
|
||||||
possible_values = List(String, required=True)
|
possible_values = List(String, required=True)
|
||||||
|
|
||||||
|
|
||||||
class MinMaxPriceType(ObjectType):
|
class MinMaxPriceType(ObjectType): # type: ignore [misc]
|
||||||
min_price = Float()
|
min_price = Float()
|
||||||
max_price = Float()
|
max_price = Float()
|
||||||
|
|
||||||
|
|
||||||
class CategoryType(DjangoObjectType):
|
class CategoryType(DjangoObjectType): # type: ignore [misc]
|
||||||
children = List(
|
children = List(
|
||||||
lambda: CategoryType,
|
lambda: CategoryType,
|
||||||
description=_("categories"),
|
description=_("categories"),
|
||||||
|
|
@ -340,7 +340,7 @@ class CategoryType(DjangoObjectType):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class VendorType(DjangoObjectType):
|
class VendorType(DjangoObjectType): # type: ignore [misc]
|
||||||
markup_percent = Float(description=_("markup percentage"))
|
markup_percent = Float(description=_("markup percentage"))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
@ -351,7 +351,7 @@ class VendorType(DjangoObjectType):
|
||||||
description = _("vendors")
|
description = _("vendors")
|
||||||
|
|
||||||
|
|
||||||
class AddressType(DjangoObjectType):
|
class AddressType(DjangoObjectType): # type: ignore [misc]
|
||||||
latitude = Float(description=_("Latitude (Y coordinate)"))
|
latitude = Float(description=_("Latitude (Y coordinate)"))
|
||||||
longitude = Float(description=_("Longitude (X coordinate)"))
|
longitude = Float(description=_("Longitude (X coordinate)"))
|
||||||
|
|
||||||
|
|
@ -381,7 +381,7 @@ class AddressType(DjangoObjectType):
|
||||||
return self.location.y if self.location else None
|
return self.location.y if self.location else None
|
||||||
|
|
||||||
|
|
||||||
class FeedbackType(DjangoObjectType):
|
class FeedbackType(DjangoObjectType): # type: ignore [misc]
|
||||||
comment = String(description=_("comment"))
|
comment = String(description=_("comment"))
|
||||||
rating = Int(description=_("rating value from 1 to 10, inclusive, or 0 if not set."))
|
rating = Int(description=_("rating value from 1 to 10, inclusive, or 0 if not set."))
|
||||||
|
|
||||||
|
|
@ -393,7 +393,7 @@ class FeedbackType(DjangoObjectType):
|
||||||
description = _("represents feedback from a user.")
|
description = _("represents feedback from a user.")
|
||||||
|
|
||||||
|
|
||||||
class OrderProductType(DjangoObjectType):
|
class OrderProductType(DjangoObjectType): # type: ignore [misc]
|
||||||
attributes = GenericScalar(description=_("attributes"))
|
attributes = GenericScalar(description=_("attributes"))
|
||||||
notifications = GenericScalar(description=_("notifications"))
|
notifications = GenericScalar(description=_("notifications"))
|
||||||
download_url = String(description=_("download url for this order product if applicable"))
|
download_url = String(description=_("download url for this order product if applicable"))
|
||||||
|
|
@ -429,7 +429,7 @@ class OrderProductType(DjangoObjectType):
|
||||||
return self.download_url
|
return self.download_url
|
||||||
|
|
||||||
|
|
||||||
class OrderType(DjangoObjectType):
|
class OrderType(DjangoObjectType): # type: ignore [misc]
|
||||||
order_products = DjangoFilterConnectionField(
|
order_products = DjangoFilterConnectionField(
|
||||||
OrderProductType, description=_("a list of order products in this order")
|
OrderProductType, description=_("a list of order products in this order")
|
||||||
)
|
)
|
||||||
|
|
@ -482,7 +482,7 @@ class OrderType(DjangoObjectType):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
class ProductImageType(DjangoObjectType):
|
class ProductImageType(DjangoObjectType): # type: ignore [misc]
|
||||||
image = String(description=_("image url"))
|
image = String(description=_("image url"))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
@ -496,7 +496,7 @@ class ProductImageType(DjangoObjectType):
|
||||||
return info.context.build_absolute_uri(self.image.url) if self.image else ""
|
return info.context.build_absolute_uri(self.image.url) if self.image else ""
|
||||||
|
|
||||||
|
|
||||||
class ProductType(DjangoObjectType):
|
class ProductType(DjangoObjectType): # type: ignore [misc]
|
||||||
category = Field(CategoryType, description=_("category"))
|
category = Field(CategoryType, description=_("category"))
|
||||||
images = DjangoFilterConnectionField(ProductImageType, description=_("images"))
|
images = DjangoFilterConnectionField(ProductImageType, description=_("images"))
|
||||||
feedbacks = DjangoFilterConnectionField(FeedbackType, description=_("feedbacks"))
|
feedbacks = DjangoFilterConnectionField(FeedbackType, description=_("feedbacks"))
|
||||||
|
|
@ -605,7 +605,7 @@ class ProductType(DjangoObjectType):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class AttributeValueType(DjangoObjectType):
|
class AttributeValueType(DjangoObjectType): # type: ignore [misc]
|
||||||
value = String(description=_("attribute value"))
|
value = String(description=_("attribute value"))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
@ -616,7 +616,7 @@ class AttributeValueType(DjangoObjectType):
|
||||||
description = _("attribute value")
|
description = _("attribute value")
|
||||||
|
|
||||||
|
|
||||||
class PromoCodeType(DjangoObjectType):
|
class PromoCodeType(DjangoObjectType): # type: ignore [misc]
|
||||||
discount = Float()
|
discount = Float()
|
||||||
discount_type = String()
|
discount_type = String()
|
||||||
|
|
||||||
|
|
@ -640,7 +640,7 @@ class PromoCodeType(DjangoObjectType):
|
||||||
return "percent" if self.discount_percent else "amount"
|
return "percent" if self.discount_percent else "amount"
|
||||||
|
|
||||||
|
|
||||||
class PromotionType(DjangoObjectType):
|
class PromotionType(DjangoObjectType): # type: ignore [misc]
|
||||||
products = DjangoFilterConnectionField(ProductType, description=_("products on sale"))
|
products = DjangoFilterConnectionField(ProductType, description=_("products on sale"))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
@ -651,7 +651,7 @@ class PromotionType(DjangoObjectType):
|
||||||
description = _("promotions")
|
description = _("promotions")
|
||||||
|
|
||||||
|
|
||||||
class StockType(DjangoObjectType):
|
class StockType(DjangoObjectType): # type: ignore [misc]
|
||||||
vendor = Field(VendorType, description=_("vendor"))
|
vendor = Field(VendorType, description=_("vendor"))
|
||||||
product = Field(ProductType, description=_("product"))
|
product = Field(ProductType, description=_("product"))
|
||||||
|
|
||||||
|
|
@ -663,7 +663,7 @@ class StockType(DjangoObjectType):
|
||||||
description = _("stocks")
|
description = _("stocks")
|
||||||
|
|
||||||
|
|
||||||
class WishlistType(DjangoObjectType):
|
class WishlistType(DjangoObjectType): # type: ignore [misc]
|
||||||
products = DjangoFilterConnectionField(ProductType, description=_("wishlisted products"))
|
products = DjangoFilterConnectionField(ProductType, description=_("wishlisted products"))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
@ -673,7 +673,7 @@ class WishlistType(DjangoObjectType):
|
||||||
description = _("wishlists")
|
description = _("wishlists")
|
||||||
|
|
||||||
|
|
||||||
class ProductTagType(DjangoObjectType):
|
class ProductTagType(DjangoObjectType): # type: ignore [misc]
|
||||||
product_set = DjangoFilterConnectionField(ProductType, description=_("tagged products"))
|
product_set = DjangoFilterConnectionField(ProductType, description=_("tagged products"))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
@ -684,7 +684,7 @@ class ProductTagType(DjangoObjectType):
|
||||||
description = _("product tags")
|
description = _("product tags")
|
||||||
|
|
||||||
|
|
||||||
class CategoryTagType(DjangoObjectType):
|
class CategoryTagType(DjangoObjectType): # type: ignore [misc]
|
||||||
category_set = DjangoFilterConnectionField(CategoryType, description=_("tagged categories"))
|
category_set = DjangoFilterConnectionField(CategoryType, description=_("tagged categories"))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
@ -695,7 +695,7 @@ class CategoryTagType(DjangoObjectType):
|
||||||
description = _("categories tags")
|
description = _("categories tags")
|
||||||
|
|
||||||
|
|
||||||
class ConfigType(ObjectType):
|
class ConfigType(ObjectType): # type: ignore [misc]
|
||||||
project_name = String(description=_("project name"))
|
project_name = String(description=_("project name"))
|
||||||
base_domain = String(description=_("company email"))
|
base_domain = String(description=_("company email"))
|
||||||
company_name = String(description=_("company name"))
|
company_name = String(description=_("company name"))
|
||||||
|
|
@ -712,7 +712,7 @@ class ConfigType(ObjectType):
|
||||||
description = _("company configuration")
|
description = _("company configuration")
|
||||||
|
|
||||||
|
|
||||||
class LanguageType(ObjectType):
|
class LanguageType(ObjectType): # type: ignore [misc]
|
||||||
code = String(description=_("language code"))
|
code = String(description=_("language code"))
|
||||||
name = String(description=_("language name"))
|
name = String(description=_("language name"))
|
||||||
flag = String(description=_("language flag, if exists :)"))
|
flag = String(description=_("language flag, if exists :)"))
|
||||||
|
|
@ -721,40 +721,40 @@ class LanguageType(ObjectType):
|
||||||
description = _("supported languages")
|
description = _("supported languages")
|
||||||
|
|
||||||
|
|
||||||
class SearchProductsResultsType(ObjectType):
|
class SearchProductsResultsType(ObjectType): # type: ignore [misc]
|
||||||
uuid = UUID()
|
uuid = UUID()
|
||||||
name = String()
|
name = String()
|
||||||
slug = String()
|
slug = String()
|
||||||
image = String()
|
image = String()
|
||||||
|
|
||||||
|
|
||||||
class SearchCategoriesResultsType(ObjectType):
|
class SearchCategoriesResultsType(ObjectType): # type: ignore [misc]
|
||||||
uuid = UUID()
|
uuid = UUID()
|
||||||
name = String()
|
name = String()
|
||||||
slug = String()
|
slug = String()
|
||||||
image = String()
|
image = String()
|
||||||
|
|
||||||
|
|
||||||
class SearchBrandsResultsType(ObjectType):
|
class SearchBrandsResultsType(ObjectType): # type: ignore [misc]
|
||||||
uuid = UUID()
|
uuid = UUID()
|
||||||
name = String()
|
name = String()
|
||||||
slug = String()
|
slug = String()
|
||||||
image = String()
|
image = String()
|
||||||
|
|
||||||
|
|
||||||
class SearchPostsResultsType(ObjectType):
|
class SearchPostsResultsType(ObjectType): # type: ignore [misc]
|
||||||
uuid = UUID()
|
uuid = UUID()
|
||||||
name = String()
|
name = String()
|
||||||
slug = String()
|
slug = String()
|
||||||
|
|
||||||
|
|
||||||
class SearchResultsType(ObjectType):
|
class SearchResultsType(ObjectType): # type: ignore [misc]
|
||||||
products = List(description=_("products search results"), of_type=SearchProductsResultsType)
|
products = List(description=_("products search results"), of_type=SearchProductsResultsType)
|
||||||
categories = List(description=_("products search results"), of_type=SearchCategoriesResultsType)
|
categories = List(description=_("products search results"), of_type=SearchCategoriesResultsType)
|
||||||
brands = List(description=_("products search results"), of_type=SearchBrandsResultsType)
|
brands = List(description=_("products search results"), of_type=SearchBrandsResultsType)
|
||||||
posts = List(description=_("posts search results"), of_type=SearchPostsResultsType)
|
posts = List(description=_("posts search results"), of_type=SearchPostsResultsType)
|
||||||
|
|
||||||
|
|
||||||
class BulkProductInput(InputObjectType):
|
class BulkProductInput(InputObjectType): # type: ignore [misc]
|
||||||
uuid = UUID(required=True)
|
uuid = UUID(required=True)
|
||||||
attributes = GenericScalar(required=False)
|
attributes = GenericScalar(required=False)
|
||||||
|
|
|
||||||
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,7 @@
|
||||||
import os
|
import os
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
import redis
|
import redis
|
||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import BaseCommand
|
||||||
|
|
@ -11,10 +12,10 @@ from redis.exceptions import ConnectionError # noqa: A004
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args: list[Any], **options: dict[Any, Any]) -> None:
|
||||||
self.stdout.write("Waiting for services...")
|
self.stdout.write("Waiting for services...")
|
||||||
|
|
||||||
def wait_for_db():
|
def wait_for_db() -> None:
|
||||||
db_up = False
|
db_up = False
|
||||||
while not db_up:
|
while not db_up:
|
||||||
try:
|
try:
|
||||||
|
|
@ -31,7 +32,7 @@ class Command(BaseCommand):
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
self.stdout.write(self.style.SUCCESS("Database available!"))
|
self.stdout.write(self.style.SUCCESS("Database available!"))
|
||||||
|
|
||||||
def wait_for_redis():
|
def wait_for_redis() -> None:
|
||||||
redis_up = False
|
redis_up = False
|
||||||
while not redis_up:
|
while not redis_up:
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
import contextlib
|
import contextlib
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
from argparse import ArgumentParser
|
||||||
from tempfile import NamedTemporaryFile
|
from tempfile import NamedTemporaryFile
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
import polib
|
import polib
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
|
|
@ -64,7 +66,7 @@ def load_po_sanitized(path: str) -> polib.POFile:
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
help = "Scan target-language .po files and report any placeholder mismatches, grouped by app."
|
help = "Scan target-language .po files and report any placeholder mismatches, grouped by app."
|
||||||
|
|
||||||
def add_arguments(self, parser):
|
def add_arguments(self, parser: ArgumentParser) -> None:
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-l",
|
"-l",
|
||||||
"--language",
|
"--language",
|
||||||
|
|
@ -92,14 +94,14 @@ class Command(BaseCommand):
|
||||||
help="Root path prefix to adjust file links",
|
help="Root path prefix to adjust file links",
|
||||||
)
|
)
|
||||||
|
|
||||||
def handle(self, *args, **options) -> None:
|
def handle(self, *args: list[Any], **options: dict[str, str | list[str]]) -> None:
|
||||||
langs: list[str] = options["target_languages"]
|
langs: list[str] = options.get("target_languages", []) # type: ignore [assignment]
|
||||||
if "ALL" in langs:
|
if "ALL" in langs:
|
||||||
langs = list(dict(settings.LANGUAGES).keys())
|
langs = list(dict(settings.LANGUAGES).keys())
|
||||||
apps_to_scan: set[str] = set(options["target_apps"])
|
apps_to_scan: set[str] = set(options["target_apps"])
|
||||||
if "ALL" in apps_to_scan:
|
if "ALL" in apps_to_scan:
|
||||||
apps_to_scan = set(TRANSLATABLE_APPS)
|
apps_to_scan = set(TRANSLATABLE_APPS)
|
||||||
root_path: str = options.get("root_path") or "/app/"
|
root_path: str = options.get("root_path") or "/app/" # type: ignore [assignment]
|
||||||
|
|
||||||
configs = list(apps.get_app_configs())
|
configs = list(apps.get_app_configs())
|
||||||
# noinspection PyTypeChecker
|
# noinspection PyTypeChecker
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import BaseCommand
|
||||||
|
|
||||||
|
|
@ -6,17 +7,16 @@ from core.models import Category, Product, Stock
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args: list[Any], **options: dict[Any, Any]) -> None:
|
||||||
self.stdout.write(self.style.SUCCESS("Starting clearing unwanted data..."))
|
self.stdout.write(self.style.SUCCESS("Starting clearing unwanted data..."))
|
||||||
|
|
||||||
# 1. Clean up duplicate Stock entries per product and vendor:
|
# 1. Clean up duplicate Stock entries per product and vendor:
|
||||||
# Group stocks by (product, vendor)
|
# Group stocks by (product, vendor)
|
||||||
stocks_by_group = defaultdict(list)
|
stocks_by_group = defaultdict(list)
|
||||||
for stock in Stock.objects.all().order_by("modified"):
|
for stock in Stock.objects.all().order_by("modified"):
|
||||||
key = (stock.product_id, stock.vendor)
|
stocks_by_group[stock.product_pk].append(stock)
|
||||||
stocks_by_group[key].append(stock)
|
|
||||||
|
|
||||||
stock_deletions = []
|
stock_deletions: list[str] = []
|
||||||
for group in stocks_by_group.values():
|
for group in stocks_by_group.values():
|
||||||
if len(group) <= 1:
|
if len(group) <= 1:
|
||||||
continue
|
continue
|
||||||
|
|
@ -32,20 +32,20 @@ class Command(BaseCommand):
|
||||||
|
|
||||||
# Mark all stocks (except the designated one) for deletion.
|
# Mark all stocks (except the designated one) for deletion.
|
||||||
for s in group:
|
for s in group:
|
||||||
if s.id != record_to_keep.id:
|
if s.uuid != record_to_keep.uuid:
|
||||||
stock_deletions.append(s.id)
|
stock_deletions.append(str(s.uuid))
|
||||||
|
|
||||||
if stock_deletions:
|
if stock_deletions:
|
||||||
Stock.objects.filter(id__in=stock_deletions).delete()
|
Stock.objects.filter(uuid__in=stock_deletions).delete()
|
||||||
self.stdout.write(self.style.SUCCESS(f"Deleted {len(stock_deletions)} duplicate stock entries."))
|
self.stdout.write(self.style.SUCCESS(f"Deleted {len(stock_deletions)} duplicate stock entries."))
|
||||||
|
|
||||||
# 2. Clean up duplicate Category entries based on name (case-insensitive)
|
# 2. Clean up duplicate Category entries based on name (case-insensitive)
|
||||||
category_groups = defaultdict(list)
|
category_groups = defaultdict(list)
|
||||||
for cat in Category.objects.all().order_by("modified"):
|
for cat in Category.objects.all().order_by("modified"):
|
||||||
key = cat.name.lower()
|
key: str = cat.name.lower()
|
||||||
category_groups[key].append(cat)
|
category_groups[key].append(cat)
|
||||||
|
|
||||||
categories_to_delete = []
|
categories_to_delete: list[str] = []
|
||||||
total_product_updates = 0
|
total_product_updates = 0
|
||||||
for cat_list in category_groups.values():
|
for cat_list in category_groups.values():
|
||||||
if len(cat_list) <= 1:
|
if len(cat_list) <= 1:
|
||||||
|
|
@ -59,13 +59,13 @@ class Command(BaseCommand):
|
||||||
keep_category = max(cat_list, key=lambda c: c.modified)
|
keep_category = max(cat_list, key=lambda c: c.modified)
|
||||||
|
|
||||||
for duplicate in cat_list:
|
for duplicate in cat_list:
|
||||||
if duplicate.id == keep_category.id:
|
if duplicate.uuid == keep_category.uuid:
|
||||||
continue
|
continue
|
||||||
total_product_updates += Product.objects.filter(category=duplicate).update(category=keep_category)
|
total_product_updates += Product.objects.filter(category=duplicate).update(category=keep_category)
|
||||||
categories_to_delete.append(duplicate.id)
|
categories_to_delete.append(str(duplicate.uuid))
|
||||||
|
|
||||||
if categories_to_delete:
|
if categories_to_delete:
|
||||||
Category.objects.filter(id__in=categories_to_delete).delete()
|
Category.objects.filter(uuid__in=categories_to_delete).delete()
|
||||||
self.stdout.write(
|
self.stdout.write(
|
||||||
self.style.SUCCESS(
|
self.style.SUCCESS(
|
||||||
f"Replaced category for {total_product_updates} product(s) "
|
f"Replaced category for {total_product_updates} product(s) "
|
||||||
|
|
@ -74,7 +74,7 @@ class Command(BaseCommand):
|
||||||
)
|
)
|
||||||
|
|
||||||
# 3. For Products without stocks: set is_active = False.
|
# 3. For Products without stocks: set is_active = False.
|
||||||
inactive_products = Product.objects.filter(stock__isnull=True)
|
inactive_products = Product.objects.filter(stocks__isnull=True)
|
||||||
count_inactive = inactive_products.count()
|
count_inactive = inactive_products.count()
|
||||||
if count_inactive:
|
if count_inactive:
|
||||||
inactive_products.update(is_active=False)
|
inactive_products.update(is_active=False)
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,15 @@
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
from argparse import ArgumentParser
|
||||||
from tempfile import NamedTemporaryFile
|
from tempfile import NamedTemporaryFile
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
import polib
|
import polib
|
||||||
import requests
|
import requests
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.core.management.base import BaseCommand, CommandError
|
from django.core.management.base import BaseCommand, CommandError
|
||||||
|
|
||||||
from core.management.commands import RootDirectory, DEEPL_TARGET_LANGUAGES_MAPPING, TRANSLATABLE_APPS
|
from core.management.commands import DEEPL_TARGET_LANGUAGES_MAPPING, TRANSLATABLE_APPS, RootDirectory
|
||||||
|
|
||||||
# Patterns to identify placeholders
|
# Patterns to identify placeholders
|
||||||
PLACEHOLDER_REGEXES = [
|
PLACEHOLDER_REGEXES = [
|
||||||
|
|
@ -23,7 +25,7 @@ def placeholderize(text: str) -> tuple[str, list[str]]:
|
||||||
"""
|
"""
|
||||||
placeholders: list[str] = []
|
placeholders: list[str] = []
|
||||||
|
|
||||||
def _repl(match: re.Match) -> str:
|
def _repl(match: re.Match) -> str: # type: ignore [type-arg]
|
||||||
idx = len(placeholders)
|
idx = len(placeholders)
|
||||||
placeholders.append(match.group(0))
|
placeholders.append(match.group(0))
|
||||||
return f"__PH_{idx}__"
|
return f"__PH_{idx}__"
|
||||||
|
|
@ -77,7 +79,7 @@ def load_po_sanitized(path: str) -> polib.POFile | None:
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
help = "Merge msgid/msgstr from en_GB PO into target-language POs via DeepL, preserving placeholders."
|
help = "Merge msgid/msgstr from en_GB PO into target-language POs via DeepL, preserving placeholders."
|
||||||
|
|
||||||
def add_arguments(self, parser):
|
def add_arguments(self, parser: ArgumentParser) -> None:
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-l",
|
"-l",
|
||||||
"--language",
|
"--language",
|
||||||
|
|
@ -97,10 +99,10 @@ class Command(BaseCommand):
|
||||||
help="App label for translation, e.g. core, payments. Use ALL to translate all apps.",
|
help="App label for translation, e.g. core, payments. Use ALL to translate all apps.",
|
||||||
)
|
)
|
||||||
|
|
||||||
def handle(self, *args, **options) -> None:
|
def handle(self, *args: list[Any], **options: dict[Any, Any]) -> None:
|
||||||
target_langs = options["target_languages"]
|
target_langs: list[str] = options["target_languages"] # type: ignore [assignment]
|
||||||
if "ALL" in target_langs:
|
if "ALL" in target_langs:
|
||||||
target_langs = DEEPL_TARGET_LANGUAGES_MAPPING.keys()
|
target_langs = DEEPL_TARGET_LANGUAGES_MAPPING.keys() # type: ignore [assignment]
|
||||||
target_apps = set(options["target_apps"])
|
target_apps = set(options["target_apps"])
|
||||||
if "ALL" in target_apps:
|
if "ALL" in target_apps:
|
||||||
target_apps = {
|
target_apps = {
|
||||||
|
|
@ -152,9 +154,9 @@ class Command(BaseCommand):
|
||||||
default = e.msgid
|
default = e.msgid
|
||||||
if readline:
|
if readline:
|
||||||
|
|
||||||
def hook():
|
def hook() -> None:
|
||||||
readline.insert_text(default) # noqa: B023
|
readline.insert_text(default) # type: ignore [attr-defined] # noqa: B023
|
||||||
readline.redisplay()
|
readline.redisplay() # type: ignore [attr-defined]
|
||||||
|
|
||||||
readline.set_pre_input_hook(hook) # type: ignore [attr-defined]
|
readline.set_pre_input_hook(hook) # type: ignore [attr-defined]
|
||||||
|
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue