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)
|
||||
class PostTagAdmin(ModelAdmin): # type: ignore [misc, type-arg]
|
||||
class PostTagAdmin(ModelAdmin): # type: ignore [type-arg]
|
||||
list_display = ("tag_name", "name")
|
||||
search_fields = ("tag_name", "name")
|
||||
ordering = ("tag_name",)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,6 @@ class BlogConfig(AppConfig):
|
|||
hide = False
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
def ready(self):
|
||||
def ready(self) -> None:
|
||||
import blog.elasticsearch.documents
|
||||
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
|
||||
|
||||
|
||||
class PostDocument(ActiveOnlyMixin, BaseDocument):
|
||||
class PostDocument(ActiveOnlyMixin, BaseDocument): # type: ignore [misc]
|
||||
title = fields.TextField(
|
||||
attr="title",
|
||||
analyzer="standard",
|
||||
|
|
@ -30,7 +30,7 @@ class PostDocument(ActiveOnlyMixin, BaseDocument):
|
|||
model = Post
|
||||
fields = ["uuid"]
|
||||
|
||||
def prepare_title(self, instance):
|
||||
def prepare_title(self, instance: Post) -> str:
|
||||
return getattr(instance, "title", "") or ""
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from blog.models import Post
|
|||
from core.filters import CaseInsensitiveListFilter
|
||||
|
||||
|
||||
class PostFilter(FilterSet):
|
||||
class PostFilter(FilterSet): # type: ignore [misc]
|
||||
uuid = UUIDFilter(field_name="uuid", lookup_expr="exact")
|
||||
slug = CharFilter(field_name="slug", lookup_expr="exact")
|
||||
author = UUIDFilter(field_name="author__uuid", lookup_expr="exact")
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 3.0.0\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"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 3.0.0\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"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 3.0.0\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"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 3.0.0\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"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 3.0.0\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"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 3.0.0\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"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 3.0.0\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"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\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"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 3.0.0\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"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 3.0.0\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"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 3.0.0\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"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\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"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 3.0.0\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"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 3.0.0\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"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 3.0.0\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"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 3.0.0\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"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 3.0.0\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"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 3.0.0\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"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 3.0.0\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"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 3.0.0\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"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 3.0.0\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"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 3.0.0\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"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 3.0.0\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"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 3.0.0\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"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 3.0.0\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"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 3.0.0\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"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 3.0.0\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"
|
||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 3.0.0\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"
|
||||
"Last-Translator: EGOR GORBUNOV <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
|
||||
|
||||
|
||||
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.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
from typing import Any
|
||||
|
||||
from django import forms
|
||||
from django.forms.renderers import BaseRenderer
|
||||
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",)}
|
||||
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_id = attrs.get("id", f"id_{name}")
|
||||
init_js = f"""
|
||||
|
|
|
|||
|
|
@ -20,16 +20,16 @@ class NiceModel(Model):
|
|||
verbose_name=_("is active"),
|
||||
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"))
|
||||
modified = ModificationDateTimeField(_("modified"), help_text=_("when the object was last modified"))
|
||||
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")) # type: ignore [no-untyped-call]
|
||||
|
||||
def save(
|
||||
def save( # type: ignore [override]
|
||||
self,
|
||||
*,
|
||||
force_insert: bool = False,
|
||||
force_update: bool = False,
|
||||
using: str | None = None,
|
||||
update_fields: Collection | None = None,
|
||||
update_fields: Collection[str] | None = None,
|
||||
update_modified: bool = True,
|
||||
) -> None:
|
||||
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
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
def ready(self):
|
||||
def ready(self) -> None:
|
||||
import core.elasticsearch.documents
|
||||
import core.signals # noqa: F401
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ def process_query(
|
|||
request: Request | None = None,
|
||||
indexes: tuple[str, ...] = ("categories", "brands", "products"),
|
||||
use_transliteration: bool = True,
|
||||
) -> dict[str, list[dict]] | None:
|
||||
) -> dict[str, list[dict[str, Any]]] | None:
|
||||
if not query:
|
||||
raise ValueError(_("no search term provided."))
|
||||
|
||||
|
|
@ -235,7 +235,7 @@ def process_query(
|
|||
):
|
||||
hit_cache.append(h)
|
||||
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 = {}
|
||||
brands_by_uuid = {}
|
||||
|
|
@ -329,9 +329,9 @@ def _lang_analyzer(lang_code: str) -> str:
|
|||
|
||||
class ActiveOnlyMixin:
|
||||
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)
|
||||
|
||||
|
||||
|
|
@ -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:
|
||||
lc = code.replace("-", "_").lower()
|
||||
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))
|
||||
|
||||
|
||||
def populate_index():
|
||||
def populate_index() -> None:
|
||||
for doc in registry.get_documents(set(registry.get_models())):
|
||||
qs = doc().get_indexing_queryset()
|
||||
doc().update(qs, parallel=True, refresh=True)
|
||||
return None
|
||||
|
||||
|
||||
def process_system_query(
|
||||
|
|
@ -493,7 +494,7 @@ def process_system_query(
|
|||
size_per_index: int = 25,
|
||||
language_code: str | None = None,
|
||||
use_transliteration: bool = True,
|
||||
) -> dict[str, list[dict]]:
|
||||
) -> dict[str, list[dict[str, Any]]]:
|
||||
if not query:
|
||||
raise ValueError(_("no search term provided."))
|
||||
|
||||
|
|
@ -526,7 +527,7 @@ def process_system_query(
|
|||
**({"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:
|
||||
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.registries import registry
|
||||
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
|
||||
|
||||
|
||||
class BaseDocument(Document):
|
||||
class BaseDocument(Document): # type: ignore [misc]
|
||||
name = fields.TextField(
|
||||
attr="name",
|
||||
analyzer="standard",
|
||||
|
|
@ -39,10 +42,10 @@ class BaseDocument(Document):
|
|||
"index": {"max_ngram_diff": 20},
|
||||
}
|
||||
|
||||
def prepare_name(self, instance):
|
||||
def prepare_name(self, instance: Model) -> str:
|
||||
return getattr(instance, "name", "") or ""
|
||||
|
||||
def prepare_description(self, instance):
|
||||
def prepare_description(self, instance: Model) -> str:
|
||||
return getattr(instance, "description", "") or ""
|
||||
|
||||
|
||||
|
|
@ -103,7 +106,7 @@ class ProductDocument(ActiveOnlyMixin, BaseDocument):
|
|||
},
|
||||
)
|
||||
|
||||
def get_queryset(self):
|
||||
def get_queryset(self) -> QuerySet[Product]:
|
||||
return (
|
||||
super()
|
||||
.get_queryset()
|
||||
|
|
@ -156,7 +159,7 @@ add_multilang_fields(BrandDocument)
|
|||
registry.register_document(BrandDocument)
|
||||
|
||||
|
||||
class TestModelDocument(Document):
|
||||
class TestModelDocument(Document): # type: ignore [misc]
|
||||
class Index:
|
||||
name = "testmodels"
|
||||
|
||||
|
|
@ -164,7 +167,7 @@ class TestModelDocument(Document):
|
|||
model = TestModel
|
||||
fields = ["title"]
|
||||
ignore_signals = True
|
||||
related_models: list = []
|
||||
related_models: list[Any] = []
|
||||
auto_refresh = False
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import json
|
||||
import logging
|
||||
import uuid
|
||||
from typing import Any
|
||||
|
||||
from django.core.exceptions import BadRequest
|
||||
from django.db.models import (
|
||||
|
|
@ -19,6 +20,7 @@ from django.db.models import (
|
|||
When,
|
||||
)
|
||||
from django.db.models.functions import Coalesce
|
||||
from django.http import HttpRequest
|
||||
from django.utils.http import urlsafe_base64_decode
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django_filters import (
|
||||
|
|
@ -31,6 +33,8 @@ from django_filters import (
|
|||
OrderingFilter,
|
||||
UUIDFilter,
|
||||
)
|
||||
from graphene import Context
|
||||
from rest_framework.request import Request
|
||||
|
||||
from core.elasticsearch import process_query
|
||||
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")
|
||||
|
||||
|
||||
class CaseInsensitiveListFilter(BaseInFilter, CharFilter):
|
||||
def filter(self, qs, value):
|
||||
class CaseInsensitiveListFilter(BaseInFilter, CharFilter): # type: ignore [misc]
|
||||
def filter(self, qs: QuerySet[Any], value: Any) -> QuerySet[Any]:
|
||||
if not value:
|
||||
return qs
|
||||
|
||||
|
|
@ -61,7 +65,7 @@ class CaseInsensitiveListFilter(BaseInFilter, CharFilter):
|
|||
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
class ProductFilter(FilterSet):
|
||||
class ProductFilter(FilterSet): # type: ignore [misc]
|
||||
search = CharFilter(field_name="name", method="search_products", label=_("Search"))
|
||||
uuid = UUIDFilter(field_name="uuid", lookup_expr="exact", label=_("UUID"))
|
||||
name = CharFilter(lookup_expr="icontains", label=_("Name"))
|
||||
|
|
@ -121,7 +125,15 @@ class ProductFilter(FilterSet):
|
|||
"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)
|
||||
ordering_param = self.data.get("order_by", "")
|
||||
if ordering_param:
|
||||
|
|
@ -133,7 +145,7 @@ class ProductFilter(FilterSet):
|
|||
.annotate(avg_rating=Avg("rating"))
|
||||
.values("avg_rating")
|
||||
)
|
||||
self.queryset = self.queryset.annotate(
|
||||
self.queryset: QuerySet[Product] = self.queryset.annotate(
|
||||
rating=Coalesce(
|
||||
Subquery(feedback_qs, 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:
|
||||
return queryset
|
||||
|
||||
|
|
@ -156,17 +168,17 @@ class ProductFilter(FilterSet):
|
|||
|
||||
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"):
|
||||
raise BadRequest(_("there must be a category_uuid to use include_subcategories flag"))
|
||||
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):
|
||||
queryset = queryset.filter(stocks__isnull=False, stocks__quantity__gt=0, stocks__price__gt=0)
|
||||
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:
|
||||
return queryset
|
||||
|
||||
|
|
@ -228,7 +240,7 @@ class ProductFilter(FilterSet):
|
|||
|
||||
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:
|
||||
return queryset
|
||||
|
||||
|
|
@ -247,7 +259,7 @@ class ProductFilter(FilterSet):
|
|||
return queryset.filter(category__uuid=value)
|
||||
|
||||
@staticmethod
|
||||
def _infer_type(value):
|
||||
def _infer_type(value: str) -> Any:
|
||||
try:
|
||||
parsed_value = json.loads(value)
|
||||
if isinstance(parsed_value, list | dict):
|
||||
|
|
@ -271,7 +283,7 @@ class ProductFilter(FilterSet):
|
|||
return value
|
||||
|
||||
@property
|
||||
def qs(self):
|
||||
def qs(self) -> QuerySet[Product]:
|
||||
qs = super().qs
|
||||
|
||||
ordering_param = self.data.get("order_by", "")
|
||||
|
|
@ -320,7 +332,8 @@ class ProductFilter(FilterSet):
|
|||
return qs.distinct()
|
||||
|
||||
|
||||
class OrderFilter(FilterSet):
|
||||
# noinspection PyUnusedLocal
|
||||
class OrderFilter(FilterSet): # type: ignore [misc]
|
||||
search = CharFilter(
|
||||
method="filter_search",
|
||||
label=_("Search (ID, product name or part number)"),
|
||||
|
|
@ -367,7 +380,7 @@ class OrderFilter(FilterSet):
|
|||
"max_buy_time",
|
||||
]
|
||||
|
||||
def filter_search(self, queryset, _name, value):
|
||||
def filter_search(self, queryset: QuerySet[Order], name: str, value: str):
|
||||
return queryset.filter(
|
||||
Q(human_readable_id__icontains=value)
|
||||
| Q(order_products__product__name__icontains=value)
|
||||
|
|
@ -375,7 +388,7 @@ class OrderFilter(FilterSet):
|
|||
).distinct()
|
||||
|
||||
|
||||
class WishlistFilter(FilterSet):
|
||||
class WishlistFilter(FilterSet): # type: ignore [misc]
|
||||
uuid = UUIDFilter(field_name="uuid", lookup_expr="exact")
|
||||
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"))
|
||||
|
|
@ -395,7 +408,7 @@ class WishlistFilter(FilterSet):
|
|||
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
class CategoryFilter(FilterSet):
|
||||
class CategoryFilter(FilterSet): # type: ignore [misc]
|
||||
search = CharFilter(field_name="name", method="search_categories", label=_("Search"))
|
||||
uuid = UUIDFilter(field_name="uuid", lookup_expr="exact")
|
||||
name = CharFilter(lookup_expr="icontains", label=_("Name"))
|
||||
|
|
@ -424,7 +437,7 @@ class CategoryFilter(FilterSet):
|
|||
"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:
|
||||
return queryset
|
||||
|
||||
|
|
@ -432,7 +445,7 @@ class CategoryFilter(FilterSet):
|
|||
|
||||
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:
|
||||
return queryset
|
||||
|
||||
|
|
@ -456,7 +469,7 @@ class CategoryFilter(FilterSet):
|
|||
|
||||
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 == "?":
|
||||
|
||||
def build_random_prefetch(depth):
|
||||
|
|
@ -494,7 +507,7 @@ class CategoryFilter(FilterSet):
|
|||
|
||||
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_desc_products = Exists(
|
||||
Product.objects.filter(
|
||||
|
|
@ -509,7 +522,7 @@ class CategoryFilter(FilterSet):
|
|||
return annotated.filter(has_products=True).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"):
|
||||
return queryset.filter(parent=None)
|
||||
|
||||
|
|
@ -522,7 +535,7 @@ class CategoryFilter(FilterSet):
|
|||
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
class BrandFilter(FilterSet):
|
||||
class BrandFilter(FilterSet): # type: ignore [misc]
|
||||
search = CharFilter(field_name="name", method="search_brands", label=_("Search"))
|
||||
uuid = UUIDFilter(field_name="uuid", lookup_expr="exact")
|
||||
name = CharFilter(lookup_expr="icontains", label=_("Name"))
|
||||
|
|
@ -543,7 +556,7 @@ class BrandFilter(FilterSet):
|
|||
model = Brand
|
||||
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:
|
||||
return queryset
|
||||
|
||||
|
|
@ -552,7 +565,7 @@ class BrandFilter(FilterSet):
|
|||
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"))
|
||||
product_uuid = UUIDFilter(
|
||||
field_name="order_product__product__uuid",
|
||||
|
|
@ -581,7 +594,7 @@ class FeedbackFilter(FilterSet):
|
|||
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"))
|
||||
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"))
|
||||
|
|
|
|||
|
|
@ -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 Meta:
|
||||
model = OrderProduct
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
from typing import Any
|
||||
|
||||
from graphene import Mutation
|
||||
|
||||
|
||||
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)
|
||||
|
||||
@staticmethod
|
||||
def mutate(**kwargs) -> None:
|
||||
def mutate(**kwargs: Any) -> None:
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import logging
|
||||
from typing import Any
|
||||
|
||||
import requests
|
||||
from django.core.cache import cache
|
||||
|
|
@ -31,6 +32,7 @@ from payments.graphene.object_types import TransactionType
|
|||
logger = logging.getLogger("django")
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
class CacheOperator(BaseMutation):
|
||||
class Meta:
|
||||
description = _("cache I/O")
|
||||
|
|
@ -46,10 +48,11 @@ class CacheOperator(BaseMutation):
|
|||
data = GenericScalar(description=_("cached data"))
|
||||
|
||||
@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))
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
class RequestCursedURL(BaseMutation):
|
||||
class Meta:
|
||||
description = _("request a CORSed URL")
|
||||
|
|
@ -60,7 +63,7 @@ class RequestCursedURL(BaseMutation):
|
|||
data = GenericScalar(description=_("camelized JSON data from the requested URL"))
|
||||
|
||||
@staticmethod
|
||||
def mutate(_parent, info, url):
|
||||
def mutate(parent, info, url) -> dict[str, Any]: # type: ignore [override]
|
||||
if not is_url_safe(url):
|
||||
raise BadRequest(_("only URLs starting with http(s):// are allowed"))
|
||||
try:
|
||||
|
|
@ -75,6 +78,7 @@ class RequestCursedURL(BaseMutation):
|
|||
return {"data": {"error": str(e)}}
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal,PyTypeChecker
|
||||
class AddOrderProduct(BaseMutation):
|
||||
class Meta:
|
||||
description = _("add a product to the order")
|
||||
|
|
@ -87,7 +91,7 @@ class AddOrderProduct(BaseMutation):
|
|||
order = Field(OrderType)
|
||||
|
||||
@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
|
||||
try:
|
||||
order = Order.objects.get(uuid=order_uuid)
|
||||
|
|
@ -101,6 +105,7 @@ class AddOrderProduct(BaseMutation):
|
|||
raise Http404(_(f"order {order_uuid} not found")) from dne
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
class RemoveOrderProduct(BaseMutation):
|
||||
class Meta:
|
||||
description = _("remove a product from the order")
|
||||
|
|
@ -113,7 +118,7 @@ class RemoveOrderProduct(BaseMutation):
|
|||
order = Field(OrderType)
|
||||
|
||||
@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
|
||||
try:
|
||||
order = Order.objects.get(uuid=order_uuid)
|
||||
|
|
@ -127,6 +132,7 @@ class RemoveOrderProduct(BaseMutation):
|
|||
raise Http404(_(f"order {order_uuid} not found")) from dne
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal,PyTypeChecker
|
||||
class RemoveAllOrderProducts(BaseMutation):
|
||||
class Meta:
|
||||
description = _("remove all products from the order")
|
||||
|
|
@ -137,7 +143,7 @@ class RemoveAllOrderProducts(BaseMutation):
|
|||
order = Field(OrderType)
|
||||
|
||||
@staticmethod
|
||||
def mutate(_parent, info, order_uuid):
|
||||
def mutate(parent, info, order_uuid): # type: ignore [override]
|
||||
user = info.context.user
|
||||
order = Order.objects.get(uuid=order_uuid)
|
||||
if not (user.has_perm("core.delete_orderproduct") or user == order.user):
|
||||
|
|
@ -148,6 +154,7 @@ class RemoveAllOrderProducts(BaseMutation):
|
|||
return RemoveAllOrderProducts(order=order)
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal,PyTypeChecker
|
||||
class RemoveOrderProductsOfAKind(BaseMutation):
|
||||
class Meta:
|
||||
description = _("remove a product from the order")
|
||||
|
|
@ -159,7 +166,7 @@ class RemoveOrderProductsOfAKind(BaseMutation):
|
|||
order = Field(OrderType)
|
||||
|
||||
@staticmethod
|
||||
def mutate(_parent, info, product_uuid, order_uuid):
|
||||
def mutate(parent, info, product_uuid, order_uuid): # type: ignore [override]
|
||||
user = info.context.user
|
||||
order = Order.objects.get(uuid=order_uuid)
|
||||
if not (user.has_perm("core.delete_orderproduct") or user == order.user):
|
||||
|
|
@ -170,6 +177,7 @@ class RemoveOrderProductsOfAKind(BaseMutation):
|
|||
return RemoveOrderProductsOfAKind(order=order)
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal,PyTypeChecker
|
||||
class BuyOrder(BaseMutation):
|
||||
class Meta:
|
||||
description = _("buy an order")
|
||||
|
|
@ -189,7 +197,7 @@ class BuyOrder(BaseMutation):
|
|||
|
||||
@staticmethod
|
||||
def mutate(
|
||||
_parent,
|
||||
parent,
|
||||
info,
|
||||
order_uuid=None,
|
||||
order_hr_id=None,
|
||||
|
|
@ -199,7 +207,7 @@ class BuyOrder(BaseMutation):
|
|||
shipping_address=None,
|
||||
billing_address=None,
|
||||
chosen_products=None,
|
||||
):
|
||||
): # type: ignore [override]
|
||||
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"))
|
||||
user = info.context.user
|
||||
|
|
@ -232,6 +240,7 @@ class BuyOrder(BaseMutation):
|
|||
raise Http404(_(f"order {order_uuid} not found")) from dne
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal,PyTypeChecker
|
||||
class BulkOrderAction(BaseMutation):
|
||||
class Meta:
|
||||
description = _("perform an action on a list of products in the order")
|
||||
|
|
@ -246,13 +255,13 @@ class BulkOrderAction(BaseMutation):
|
|||
|
||||
@staticmethod
|
||||
def mutate(
|
||||
_parent,
|
||||
parent,
|
||||
info,
|
||||
action,
|
||||
products,
|
||||
order_uuid=None,
|
||||
order_hr_id=None,
|
||||
):
|
||||
): # type: ignore [override]
|
||||
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"))
|
||||
user = info.context.user
|
||||
|
|
@ -279,6 +288,7 @@ class BulkOrderAction(BaseMutation):
|
|||
raise Http404(_(f"order {order_uuid} not found")) from dne
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal,PyTypeChecker
|
||||
class BulkWishlistAction(BaseMutation):
|
||||
class Meta:
|
||||
description = _("perform an action on a list of products in the wishlist")
|
||||
|
|
@ -292,12 +302,12 @@ class BulkWishlistAction(BaseMutation):
|
|||
|
||||
@staticmethod
|
||||
def mutate(
|
||||
_parent,
|
||||
parent,
|
||||
info,
|
||||
action,
|
||||
products,
|
||||
wishlist_uuid=None,
|
||||
):
|
||||
): # type: ignore [override]
|
||||
if not wishlist_uuid:
|
||||
raise BadRequest(_("please provide wishlist_uuid value"))
|
||||
user = info.context.user
|
||||
|
|
@ -319,6 +329,7 @@ class BulkWishlistAction(BaseMutation):
|
|||
raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
class BuyUnregisteredOrder(BaseMutation):
|
||||
class Meta:
|
||||
description = _("purchase an order without account creation")
|
||||
|
|
@ -338,7 +349,7 @@ class BuyUnregisteredOrder(BaseMutation):
|
|||
|
||||
@staticmethod
|
||||
def mutate(
|
||||
_parent,
|
||||
parent,
|
||||
info,
|
||||
products,
|
||||
customer_name,
|
||||
|
|
@ -349,7 +360,7 @@ class BuyUnregisteredOrder(BaseMutation):
|
|||
customer_shipping_address=None,
|
||||
promocode_uuid=None,
|
||||
is_business=False,
|
||||
):
|
||||
): # type: ignore [override]
|
||||
order = Order.objects.create(status="MOMENTAL")
|
||||
transaction = order.buy_without_registration(
|
||||
products=products,
|
||||
|
|
@ -362,9 +373,11 @@ class BuyUnregisteredOrder(BaseMutation):
|
|||
payment_method=payment_method,
|
||||
is_business=is_business,
|
||||
)
|
||||
# noinspection PyTypeChecker
|
||||
return BuyUnregisteredOrder(transaction=transaction)
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal,PyTypeChecker
|
||||
class AddWishlistProduct(BaseMutation):
|
||||
class Meta:
|
||||
description = _("add a product to the wishlist")
|
||||
|
|
@ -376,7 +389,7 @@ class AddWishlistProduct(BaseMutation):
|
|||
wishlist = Field(WishlistType)
|
||||
|
||||
@staticmethod
|
||||
def mutate(_parent, info, product_uuid, wishlist_uuid):
|
||||
def mutate(parent, info, product_uuid, wishlist_uuid): # type: ignore [override]
|
||||
user = info.context.user
|
||||
try:
|
||||
wishlist = Wishlist.objects.get(uuid=wishlist_uuid)
|
||||
|
|
@ -392,6 +405,7 @@ class AddWishlistProduct(BaseMutation):
|
|||
raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal,PyTypeChecker
|
||||
class RemoveWishlistProduct(BaseMutation):
|
||||
class Meta:
|
||||
description = _("remove a product from the wishlist")
|
||||
|
|
@ -403,7 +417,7 @@ class RemoveWishlistProduct(BaseMutation):
|
|||
wishlist = Field(WishlistType)
|
||||
|
||||
@staticmethod
|
||||
def mutate(_parent, info, product_uuid, wishlist_uuid):
|
||||
def mutate(parent, info, product_uuid, wishlist_uuid): # type: ignore [override]
|
||||
user = info.context.user
|
||||
try:
|
||||
wishlist = Wishlist.objects.get(uuid=wishlist_uuid)
|
||||
|
|
@ -419,6 +433,7 @@ class RemoveWishlistProduct(BaseMutation):
|
|||
raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal,PyTypeChecker
|
||||
class RemoveAllWishlistProducts(BaseMutation):
|
||||
class Meta:
|
||||
description = _("remove all products from the wishlist")
|
||||
|
|
@ -429,7 +444,7 @@ class RemoveAllWishlistProducts(BaseMutation):
|
|||
wishlist = Field(WishlistType)
|
||||
|
||||
@staticmethod
|
||||
def mutate(_parent, info, wishlist_uuid):
|
||||
def mutate(parent, info, wishlist_uuid): # type: ignore [override]
|
||||
user = info.context.user
|
||||
try:
|
||||
wishlist = Wishlist.objects.get(uuid=wishlist_uuid)
|
||||
|
|
@ -446,6 +461,7 @@ class RemoveAllWishlistProducts(BaseMutation):
|
|||
raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal,PyTypeChecker
|
||||
class BuyWishlist(BaseMutation):
|
||||
class Meta:
|
||||
description = _("buy all products from the wishlist")
|
||||
|
|
@ -459,7 +475,7 @@ class BuyWishlist(BaseMutation):
|
|||
transaction = Field(TransactionType, required=False)
|
||||
|
||||
@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
|
||||
try:
|
||||
wishlist = Wishlist.objects.get(uuid=wishlist_uuid)
|
||||
|
|
@ -489,6 +505,7 @@ class BuyWishlist(BaseMutation):
|
|||
raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal,PyTypeChecker
|
||||
class BuyProduct(BaseMutation):
|
||||
class Meta:
|
||||
description = _("buy a product")
|
||||
|
|
@ -507,13 +524,13 @@ class BuyProduct(BaseMutation):
|
|||
|
||||
@staticmethod
|
||||
def mutate(
|
||||
_parent,
|
||||
parent,
|
||||
info,
|
||||
product_uuid,
|
||||
attributes=None,
|
||||
force_balance=False,
|
||||
force_payment=False,
|
||||
):
|
||||
): # type: ignore [override]
|
||||
user = info.context.user
|
||||
order = Order.objects.create(user=user, status="MOMENTAL")
|
||||
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}"))
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal,PyTypeChecker
|
||||
class FeedbackProductAction(BaseMutation):
|
||||
class Meta:
|
||||
description = _("add or delete a feedback for orderproduct")
|
||||
|
|
@ -540,7 +558,7 @@ class FeedbackProductAction(BaseMutation):
|
|||
feedback = Field(FeedbackType, required=False)
|
||||
|
||||
@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
|
||||
try:
|
||||
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
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal,PyTypeChecker
|
||||
class CreateProduct(BaseMutation):
|
||||
class Arguments:
|
||||
name = String(required=True)
|
||||
|
|
@ -568,7 +587,7 @@ class CreateProduct(BaseMutation):
|
|||
product = Field(ProductType)
|
||||
|
||||
@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"):
|
||||
raise PermissionDenied(permission_denied_message)
|
||||
category = Category.objects.get(uuid=category_uuid)
|
||||
|
|
@ -576,6 +595,7 @@ class CreateProduct(BaseMutation):
|
|||
return CreateProduct(product=product)
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal,PyTypeChecker
|
||||
class UpdateProduct(BaseMutation):
|
||||
class Arguments:
|
||||
uuid = UUID(required=True)
|
||||
|
|
@ -586,7 +606,7 @@ class UpdateProduct(BaseMutation):
|
|||
product = Field(ProductType)
|
||||
|
||||
@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
|
||||
if not user.has_perm("core.change_product"):
|
||||
raise PermissionDenied(permission_denied_message)
|
||||
|
|
@ -601,6 +621,7 @@ class UpdateProduct(BaseMutation):
|
|||
return UpdateProduct(product=product)
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal,PyTypeChecker
|
||||
class DeleteProduct(BaseMutation):
|
||||
class Arguments:
|
||||
uuid = UUID(required=True)
|
||||
|
|
@ -608,7 +629,7 @@ class DeleteProduct(BaseMutation):
|
|||
ok = Boolean()
|
||||
|
||||
@staticmethod
|
||||
def mutate(_parent, info, uuid):
|
||||
def mutate(parent, info, uuid): # type: ignore [override]
|
||||
user = info.context.user
|
||||
if not user.has_perm("core.delete_product"):
|
||||
raise PermissionDenied(permission_denied_message)
|
||||
|
|
@ -617,6 +638,7 @@ class DeleteProduct(BaseMutation):
|
|||
return DeleteProduct(ok=True)
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal,PyTypeChecker
|
||||
class CreateAddress(BaseMutation):
|
||||
class Arguments:
|
||||
raw_data = String(required=True, description=_("original address string provided by the user"))
|
||||
|
|
@ -624,13 +646,14 @@ class CreateAddress(BaseMutation):
|
|||
address = Field(AddressType)
|
||||
|
||||
@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
|
||||
|
||||
address = Address.objects.create(raw_data=raw_data, user=user)
|
||||
return CreateAddress(address=address)
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
class DeleteAddress(BaseMutation):
|
||||
class Arguments:
|
||||
uuid = UUID(required=True)
|
||||
|
|
@ -638,7 +661,7 @@ class DeleteAddress(BaseMutation):
|
|||
success = Boolean()
|
||||
|
||||
@staticmethod
|
||||
def mutate(_parent, info, uuid):
|
||||
def mutate(parent, info, uuid): # type: ignore [override]
|
||||
try:
|
||||
address = Address.objects.get(uuid=uuid)
|
||||
if (
|
||||
|
|
@ -647,6 +670,7 @@ class DeleteAddress(BaseMutation):
|
|||
or info.context.user == address.user
|
||||
):
|
||||
address.delete()
|
||||
# noinspection PyTypeChecker
|
||||
return DeleteAddress(success=True)
|
||||
|
||||
raise PermissionDenied(permission_denied_message)
|
||||
|
|
@ -656,6 +680,7 @@ class DeleteAddress(BaseMutation):
|
|||
raise Http404(_(f"{name} does not exist: {uuid}")) from dne
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
class AutocompleteAddress(BaseMutation):
|
||||
class Arguments:
|
||||
q = String()
|
||||
|
|
@ -664,7 +689,7 @@ class AutocompleteAddress(BaseMutation):
|
|||
suggestions = GenericScalar()
|
||||
|
||||
@staticmethod
|
||||
def mutate(_parent, info, q, limit):
|
||||
def mutate(parent, info, q, limit): # type: ignore [override]
|
||||
if 1 > limit > 10:
|
||||
raise BadRequest(_("limit must be between 1 and 10"))
|
||||
try:
|
||||
|
|
@ -672,9 +697,11 @@ class AutocompleteAddress(BaseMutation):
|
|||
except Exception as e:
|
||||
raise BadRequest(f"geocoding error: {e!s}") from e
|
||||
|
||||
# noinspection PyTypeChecker
|
||||
return AutocompleteAddress(suggestions=suggestions)
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
class ContactUs(BaseMutation):
|
||||
class Arguments:
|
||||
email = String(required=True)
|
||||
|
|
@ -687,7 +714,7 @@ class ContactUs(BaseMutation):
|
|||
error = String()
|
||||
|
||||
@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:
|
||||
contact_us_email.delay(
|
||||
{
|
||||
|
|
@ -698,12 +725,14 @@ class ContactUs(BaseMutation):
|
|||
"message": message,
|
||||
}
|
||||
)
|
||||
# noinspection PyTypeChecker
|
||||
return ContactUs(received=True)
|
||||
except Exception as e:
|
||||
# noinspection PyTypeChecker
|
||||
return ContactUs(received=False, error=str(e))
|
||||
|
||||
|
||||
# noinspection PyArgumentList
|
||||
# noinspection PyArgumentList PyUnusedLocal
|
||||
class Search(BaseMutation):
|
||||
class Arguments:
|
||||
query = String(required=True)
|
||||
|
|
@ -714,9 +743,10 @@ class Search(BaseMutation):
|
|||
description = _("elasticsearch - works like a charm")
|
||||
|
||||
@staticmethod
|
||||
def mutate(_parent, info, query):
|
||||
def mutate(parent, info, query): # type: ignore [override]
|
||||
data = process_query(query=query, request=info.context)
|
||||
|
||||
# noinspection PyTypeChecker
|
||||
return Search(
|
||||
results=SearchResultsType(
|
||||
products=data["products"],
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ from typing import Any
|
|||
|
||||
from constance import config
|
||||
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.utils.translation import gettext_lazy as _
|
||||
from graphene import (
|
||||
|
|
@ -60,7 +60,7 @@ from payments.graphene.object_types import TransactionType
|
|||
logger = logging.getLogger("django")
|
||||
|
||||
|
||||
class SEOMetaType(ObjectType):
|
||||
class SEOMetaType(ObjectType): # type: ignore [misc]
|
||||
title = String()
|
||||
description = String()
|
||||
canonical = String()
|
||||
|
|
@ -71,7 +71,7 @@ class SEOMetaType(ObjectType):
|
|||
hreflang = String()
|
||||
|
||||
|
||||
class AttributeType(DjangoObjectType):
|
||||
class AttributeType(DjangoObjectType): # type: ignore [misc]
|
||||
values = List(lambda: AttributeValueType, description=_("attribute values"))
|
||||
|
||||
class Meta:
|
||||
|
|
@ -81,7 +81,7 @@ class AttributeType(DjangoObjectType):
|
|||
filter_fields = ["uuid"]
|
||||
description = _("attributes")
|
||||
|
||||
def resolve_values(self, info):
|
||||
def resolve_values(self, info) -> QuerySet[AttributeValue]:
|
||||
base_qs = AttributeValue.objects.filter(attribute=self)
|
||||
product_uuid = getattr(info.context, "_product_uuid", None)
|
||||
|
||||
|
|
@ -91,7 +91,7 @@ class AttributeType(DjangoObjectType):
|
|||
return base_qs
|
||||
|
||||
|
||||
class AttributeGroupType(DjangoObjectType):
|
||||
class AttributeGroupType(DjangoObjectType): # type: ignore [misc]
|
||||
attributes = List(lambda: AttributeType, description=_("grouped attributes"))
|
||||
|
||||
class Meta:
|
||||
|
|
@ -101,7 +101,7 @@ class AttributeGroupType(DjangoObjectType):
|
|||
filter_fields = ["uuid"]
|
||||
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)
|
||||
|
||||
qs = self.attributes.all()
|
||||
|
|
@ -112,7 +112,7 @@ class AttributeGroupType(DjangoObjectType):
|
|||
return qs
|
||||
|
||||
|
||||
class BrandType(DjangoObjectType):
|
||||
class BrandType(DjangoObjectType): # type: ignore [misc]
|
||||
categories = List(lambda: CategoryType, description=_("categories"))
|
||||
seo_meta = Field(SEOMetaType, description=_("SEO Meta snapshot"))
|
||||
|
||||
|
|
@ -123,18 +123,18 @@ class BrandType(DjangoObjectType):
|
|||
filter_fields = ["uuid", "name"]
|
||||
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"):
|
||||
return self.categories.all()
|
||||
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 ""
|
||||
|
||||
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 ""
|
||||
|
||||
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()
|
||||
base = f"https://{config.BASE_DOMAIN}"
|
||||
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)
|
||||
possible_values = List(String, required=True)
|
||||
|
||||
|
||||
class MinMaxPriceType(ObjectType):
|
||||
class MinMaxPriceType(ObjectType): # type: ignore [misc]
|
||||
min_price = Float()
|
||||
max_price = Float()
|
||||
|
||||
|
||||
class CategoryType(DjangoObjectType):
|
||||
class CategoryType(DjangoObjectType): # type: ignore [misc]
|
||||
children = List(
|
||||
lambda: CategoryType,
|
||||
description=_("categories"),
|
||||
|
|
@ -340,7 +340,7 @@ class CategoryType(DjangoObjectType):
|
|||
}
|
||||
|
||||
|
||||
class VendorType(DjangoObjectType):
|
||||
class VendorType(DjangoObjectType): # type: ignore [misc]
|
||||
markup_percent = Float(description=_("markup percentage"))
|
||||
|
||||
class Meta:
|
||||
|
|
@ -351,7 +351,7 @@ class VendorType(DjangoObjectType):
|
|||
description = _("vendors")
|
||||
|
||||
|
||||
class AddressType(DjangoObjectType):
|
||||
class AddressType(DjangoObjectType): # type: ignore [misc]
|
||||
latitude = Float(description=_("Latitude (Y coordinate)"))
|
||||
longitude = Float(description=_("Longitude (X coordinate)"))
|
||||
|
||||
|
|
@ -381,7 +381,7 @@ class AddressType(DjangoObjectType):
|
|||
return self.location.y if self.location else None
|
||||
|
||||
|
||||
class FeedbackType(DjangoObjectType):
|
||||
class FeedbackType(DjangoObjectType): # type: ignore [misc]
|
||||
comment = String(description=_("comment"))
|
||||
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.")
|
||||
|
||||
|
||||
class OrderProductType(DjangoObjectType):
|
||||
class OrderProductType(DjangoObjectType): # type: ignore [misc]
|
||||
attributes = GenericScalar(description=_("attributes"))
|
||||
notifications = GenericScalar(description=_("notifications"))
|
||||
download_url = String(description=_("download url for this order product if applicable"))
|
||||
|
|
@ -429,7 +429,7 @@ class OrderProductType(DjangoObjectType):
|
|||
return self.download_url
|
||||
|
||||
|
||||
class OrderType(DjangoObjectType):
|
||||
class OrderType(DjangoObjectType): # type: ignore [misc]
|
||||
order_products = DjangoFilterConnectionField(
|
||||
OrderProductType, description=_("a list of order products in this order")
|
||||
)
|
||||
|
|
@ -482,7 +482,7 @@ class OrderType(DjangoObjectType):
|
|||
return None
|
||||
|
||||
|
||||
class ProductImageType(DjangoObjectType):
|
||||
class ProductImageType(DjangoObjectType): # type: ignore [misc]
|
||||
image = String(description=_("image url"))
|
||||
|
||||
class Meta:
|
||||
|
|
@ -496,7 +496,7 @@ class ProductImageType(DjangoObjectType):
|
|||
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"))
|
||||
images = DjangoFilterConnectionField(ProductImageType, description=_("images"))
|
||||
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"))
|
||||
|
||||
class Meta:
|
||||
|
|
@ -616,7 +616,7 @@ class AttributeValueType(DjangoObjectType):
|
|||
description = _("attribute value")
|
||||
|
||||
|
||||
class PromoCodeType(DjangoObjectType):
|
||||
class PromoCodeType(DjangoObjectType): # type: ignore [misc]
|
||||
discount = Float()
|
||||
discount_type = String()
|
||||
|
||||
|
|
@ -640,7 +640,7 @@ class PromoCodeType(DjangoObjectType):
|
|||
return "percent" if self.discount_percent else "amount"
|
||||
|
||||
|
||||
class PromotionType(DjangoObjectType):
|
||||
class PromotionType(DjangoObjectType): # type: ignore [misc]
|
||||
products = DjangoFilterConnectionField(ProductType, description=_("products on sale"))
|
||||
|
||||
class Meta:
|
||||
|
|
@ -651,7 +651,7 @@ class PromotionType(DjangoObjectType):
|
|||
description = _("promotions")
|
||||
|
||||
|
||||
class StockType(DjangoObjectType):
|
||||
class StockType(DjangoObjectType): # type: ignore [misc]
|
||||
vendor = Field(VendorType, description=_("vendor"))
|
||||
product = Field(ProductType, description=_("product"))
|
||||
|
||||
|
|
@ -663,7 +663,7 @@ class StockType(DjangoObjectType):
|
|||
description = _("stocks")
|
||||
|
||||
|
||||
class WishlistType(DjangoObjectType):
|
||||
class WishlistType(DjangoObjectType): # type: ignore [misc]
|
||||
products = DjangoFilterConnectionField(ProductType, description=_("wishlisted products"))
|
||||
|
||||
class Meta:
|
||||
|
|
@ -673,7 +673,7 @@ class WishlistType(DjangoObjectType):
|
|||
description = _("wishlists")
|
||||
|
||||
|
||||
class ProductTagType(DjangoObjectType):
|
||||
class ProductTagType(DjangoObjectType): # type: ignore [misc]
|
||||
product_set = DjangoFilterConnectionField(ProductType, description=_("tagged products"))
|
||||
|
||||
class Meta:
|
||||
|
|
@ -684,7 +684,7 @@ class ProductTagType(DjangoObjectType):
|
|||
description = _("product tags")
|
||||
|
||||
|
||||
class CategoryTagType(DjangoObjectType):
|
||||
class CategoryTagType(DjangoObjectType): # type: ignore [misc]
|
||||
category_set = DjangoFilterConnectionField(CategoryType, description=_("tagged categories"))
|
||||
|
||||
class Meta:
|
||||
|
|
@ -695,7 +695,7 @@ class CategoryTagType(DjangoObjectType):
|
|||
description = _("categories tags")
|
||||
|
||||
|
||||
class ConfigType(ObjectType):
|
||||
class ConfigType(ObjectType): # type: ignore [misc]
|
||||
project_name = String(description=_("project name"))
|
||||
base_domain = String(description=_("company email"))
|
||||
company_name = String(description=_("company name"))
|
||||
|
|
@ -712,7 +712,7 @@ class ConfigType(ObjectType):
|
|||
description = _("company configuration")
|
||||
|
||||
|
||||
class LanguageType(ObjectType):
|
||||
class LanguageType(ObjectType): # type: ignore [misc]
|
||||
code = String(description=_("language code"))
|
||||
name = String(description=_("language name"))
|
||||
flag = String(description=_("language flag, if exists :)"))
|
||||
|
|
@ -721,40 +721,40 @@ class LanguageType(ObjectType):
|
|||
description = _("supported languages")
|
||||
|
||||
|
||||
class SearchProductsResultsType(ObjectType):
|
||||
class SearchProductsResultsType(ObjectType): # type: ignore [misc]
|
||||
uuid = UUID()
|
||||
name = String()
|
||||
slug = String()
|
||||
image = String()
|
||||
|
||||
|
||||
class SearchCategoriesResultsType(ObjectType):
|
||||
class SearchCategoriesResultsType(ObjectType): # type: ignore [misc]
|
||||
uuid = UUID()
|
||||
name = String()
|
||||
slug = String()
|
||||
image = String()
|
||||
|
||||
|
||||
class SearchBrandsResultsType(ObjectType):
|
||||
class SearchBrandsResultsType(ObjectType): # type: ignore [misc]
|
||||
uuid = UUID()
|
||||
name = String()
|
||||
slug = String()
|
||||
image = String()
|
||||
|
||||
|
||||
class SearchPostsResultsType(ObjectType):
|
||||
class SearchPostsResultsType(ObjectType): # type: ignore [misc]
|
||||
uuid = UUID()
|
||||
name = String()
|
||||
slug = String()
|
||||
|
||||
|
||||
class SearchResultsType(ObjectType):
|
||||
class SearchResultsType(ObjectType): # type: ignore [misc]
|
||||
products = List(description=_("products search results"), of_type=SearchProductsResultsType)
|
||||
categories = List(description=_("products search results"), of_type=SearchCategoriesResultsType)
|
||||
brands = List(description=_("products search results"), of_type=SearchBrandsResultsType)
|
||||
posts = List(description=_("posts search results"), of_type=SearchPostsResultsType)
|
||||
|
||||
|
||||
class BulkProductInput(InputObjectType):
|
||||
class BulkProductInput(InputObjectType): # type: ignore [misc]
|
||||
uuid = UUID(required=True)
|
||||
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 threading
|
||||
import time
|
||||
from typing import Any
|
||||
|
||||
import redis
|
||||
from django.core.management.base import BaseCommand
|
||||
|
|
@ -11,10 +12,10 @@ from redis.exceptions import ConnectionError # noqa: A004
|
|||
|
||||
|
||||
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...")
|
||||
|
||||
def wait_for_db():
|
||||
def wait_for_db() -> None:
|
||||
db_up = False
|
||||
while not db_up:
|
||||
try:
|
||||
|
|
@ -31,7 +32,7 @@ class Command(BaseCommand):
|
|||
time.sleep(1)
|
||||
self.stdout.write(self.style.SUCCESS("Database available!"))
|
||||
|
||||
def wait_for_redis():
|
||||
def wait_for_redis() -> None:
|
||||
redis_up = False
|
||||
while not redis_up:
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
import contextlib
|
||||
import os
|
||||
import re
|
||||
from argparse import ArgumentParser
|
||||
from tempfile import NamedTemporaryFile
|
||||
from typing import Any
|
||||
|
||||
import polib
|
||||
from django.apps import apps
|
||||
|
|
@ -64,7 +66,7 @@ def load_po_sanitized(path: str) -> polib.POFile:
|
|||
class Command(BaseCommand):
|
||||
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(
|
||||
"-l",
|
||||
"--language",
|
||||
|
|
@ -92,14 +94,14 @@ class Command(BaseCommand):
|
|||
help="Root path prefix to adjust file links",
|
||||
)
|
||||
|
||||
def handle(self, *args, **options) -> None:
|
||||
langs: list[str] = options["target_languages"]
|
||||
def handle(self, *args: list[Any], **options: dict[str, str | list[str]]) -> None:
|
||||
langs: list[str] = options.get("target_languages", []) # type: ignore [assignment]
|
||||
if "ALL" in langs:
|
||||
langs = list(dict(settings.LANGUAGES).keys())
|
||||
apps_to_scan: set[str] = set(options["target_apps"])
|
||||
if "ALL" in apps_to_scan:
|
||||
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())
|
||||
# noinspection PyTypeChecker
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
from collections import defaultdict
|
||||
from typing import Any
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
|
|
@ -6,17 +7,16 @@ from core.models import Category, Product, Stock
|
|||
|
||||
|
||||
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..."))
|
||||
|
||||
# 1. Clean up duplicate Stock entries per product and vendor:
|
||||
# Group stocks by (product, vendor)
|
||||
stocks_by_group = defaultdict(list)
|
||||
for stock in Stock.objects.all().order_by("modified"):
|
||||
key = (stock.product_id, stock.vendor)
|
||||
stocks_by_group[key].append(stock)
|
||||
stocks_by_group[stock.product_pk].append(stock)
|
||||
|
||||
stock_deletions = []
|
||||
stock_deletions: list[str] = []
|
||||
for group in stocks_by_group.values():
|
||||
if len(group) <= 1:
|
||||
continue
|
||||
|
|
@ -32,20 +32,20 @@ class Command(BaseCommand):
|
|||
|
||||
# Mark all stocks (except the designated one) for deletion.
|
||||
for s in group:
|
||||
if s.id != record_to_keep.id:
|
||||
stock_deletions.append(s.id)
|
||||
if s.uuid != record_to_keep.uuid:
|
||||
stock_deletions.append(str(s.uuid))
|
||||
|
||||
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."))
|
||||
|
||||
# 2. Clean up duplicate Category entries based on name (case-insensitive)
|
||||
category_groups = defaultdict(list)
|
||||
for cat in Category.objects.all().order_by("modified"):
|
||||
key = cat.name.lower()
|
||||
key: str = cat.name.lower()
|
||||
category_groups[key].append(cat)
|
||||
|
||||
categories_to_delete = []
|
||||
categories_to_delete: list[str] = []
|
||||
total_product_updates = 0
|
||||
for cat_list in category_groups.values():
|
||||
if len(cat_list) <= 1:
|
||||
|
|
@ -59,13 +59,13 @@ class Command(BaseCommand):
|
|||
keep_category = max(cat_list, key=lambda c: c.modified)
|
||||
|
||||
for duplicate in cat_list:
|
||||
if duplicate.id == keep_category.id:
|
||||
if duplicate.uuid == keep_category.uuid:
|
||||
continue
|
||||
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:
|
||||
Category.objects.filter(id__in=categories_to_delete).delete()
|
||||
Category.objects.filter(uuid__in=categories_to_delete).delete()
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS(
|
||||
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.
|
||||
inactive_products = Product.objects.filter(stock__isnull=True)
|
||||
inactive_products = Product.objects.filter(stocks__isnull=True)
|
||||
count_inactive = inactive_products.count()
|
||||
if count_inactive:
|
||||
inactive_products.update(is_active=False)
|
||||
|
|
|
|||
|
|
@ -1,13 +1,15 @@
|
|||
import os
|
||||
import re
|
||||
from argparse import ArgumentParser
|
||||
from tempfile import NamedTemporaryFile
|
||||
from typing import Any
|
||||
|
||||
import polib
|
||||
import requests
|
||||
from django.apps import apps
|
||||
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
|
||||
PLACEHOLDER_REGEXES = [
|
||||
|
|
@ -23,7 +25,7 @@ def placeholderize(text: str) -> tuple[str, list[str]]:
|
|||
"""
|
||||
placeholders: list[str] = []
|
||||
|
||||
def _repl(match: re.Match) -> str:
|
||||
def _repl(match: re.Match) -> str: # type: ignore [type-arg]
|
||||
idx = len(placeholders)
|
||||
placeholders.append(match.group(0))
|
||||
return f"__PH_{idx}__"
|
||||
|
|
@ -77,7 +79,7 @@ def load_po_sanitized(path: str) -> polib.POFile | None:
|
|||
class Command(BaseCommand):
|
||||
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(
|
||||
"-l",
|
||||
"--language",
|
||||
|
|
@ -97,10 +99,10 @@ class Command(BaseCommand):
|
|||
help="App label for translation, e.g. core, payments. Use ALL to translate all apps.",
|
||||
)
|
||||
|
||||
def handle(self, *args, **options) -> None:
|
||||
target_langs = options["target_languages"]
|
||||
def handle(self, *args: list[Any], **options: dict[Any, Any]) -> None:
|
||||
target_langs: list[str] = options["target_languages"] # type: ignore [assignment]
|
||||
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"])
|
||||
if "ALL" in target_apps:
|
||||
target_apps = {
|
||||
|
|
@ -152,9 +154,9 @@ class Command(BaseCommand):
|
|||
default = e.msgid
|
||||
if readline:
|
||||
|
||||
def hook():
|
||||
readline.insert_text(default) # noqa: B023
|
||||
readline.redisplay()
|
||||
def hook() -> None:
|
||||
readline.insert_text(default) # type: ignore [attr-defined] # noqa: B023
|
||||
readline.redisplay() # 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