Merge branch 'main' into storefront-nuxt

This commit is contained in:
Egor Pavlovich Gorbunov 2025-12-26 04:01:50 +03:00
commit 7d0b6301ea
248 changed files with 17269 additions and 17666 deletions

View file

@ -23,19 +23,17 @@ lint:
- "**/*.py" - "**/*.py"
- "pyproject.toml" - "pyproject.toml"
- ".pre-commit-config.yaml" - ".pre-commit-config.yaml"
- "pyrightconfig.json"
when: on_success when: on_success
- when: never - when: never
typecheck: typecheck:
stage: typecheck stage: typecheck
script: script:
- uv run pyright - uv run ty check
rules: rules:
- changes: - changes:
- "**/*.py" - "**/*.py"
- "pyproject.toml" - "pyproject.toml"
- "pyrightconfig.json"
when: on_success when: on_success
- when: never - when: never

View file

@ -1,18 +0,0 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.6.9
hooks:
- id: ruff
name: Ruff (lint & fix)
args: ["--fix", "--exit-non-zero-on-fix"]
files: "\\.(py|pyi)$"
exclude: "^storefront/"
- id: ruff-format
name: Ruff (format)
files: "\\.(py|pyi)$"
exclude: "^storefront/"
ci:
autofix_commit_msg: "chore(pre-commit): auto-fix issues"
autofix_prs: true
autoupdate_commit_msg: "chore(pre-commit): autoupdate hooks"

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2025.4\n" "Project-Id-Version: EVIBES 2025.4\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-12-18 17:19+0300\n" "POT-Creation-Date: 2025-12-21 00:38+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"

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2025.4\n" "Project-Id-Version: EVIBES 2025.4\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-12-18 17:19+0300\n" "POT-Creation-Date: 2025-12-21 00:38+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"

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2025.4\n" "Project-Id-Version: EVIBES 2025.4\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-12-18 17:19+0300\n" "POT-Creation-Date: 2025-12-21 00:38+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"

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2025.4\n" "Project-Id-Version: EVIBES 2025.4\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-12-18 17:19+0300\n" "POT-Creation-Date: 2025-12-21 00:38+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"

View file

@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2025.4\n" "Project-Id-Version: EVIBES 2025.4\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-12-18 17:19+0300\n" "POT-Creation-Date: 2025-12-21 00:38+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"

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2025.4\n" "Project-Id-Version: EVIBES 2025.4\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-12-18 17:19+0300\n" "POT-Creation-Date: 2025-12-21 00:38+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"

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2025.4\n" "Project-Id-Version: EVIBES 2025.4\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-12-18 17:19+0300\n" "POT-Creation-Date: 2025-12-21 00:38+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"

View file

@ -7,7 +7,7 @@ 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-12-18 17:19+0300\n" "POT-Creation-Date: 2025-12-21 00:38+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"

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2025.4\n" "Project-Id-Version: EVIBES 2025.4\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-12-18 17:19+0300\n" "POT-Creation-Date: 2025-12-21 00:38+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"

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2025.4\n" "Project-Id-Version: EVIBES 2025.4\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-12-18 17:19+0300\n" "POT-Creation-Date: 2025-12-21 00:38+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"

View file

@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2025.4\n" "Project-Id-Version: EVIBES 2025.4\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-12-18 17:19+0300\n" "POT-Creation-Date: 2025-12-21 00:38+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"

View file

@ -7,7 +7,7 @@ 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-12-18 17:19+0300\n" "POT-Creation-Date: 2025-12-21 00:38+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"

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2025.4\n" "Project-Id-Version: EVIBES 2025.4\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-12-18 17:19+0300\n" "POT-Creation-Date: 2025-12-21 00:38+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"

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2025.4\n" "Project-Id-Version: EVIBES 2025.4\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-12-18 17:19+0300\n" "POT-Creation-Date: 2025-12-21 00:38+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"

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2025.4\n" "Project-Id-Version: EVIBES 2025.4\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-12-18 17:19+0300\n" "POT-Creation-Date: 2025-12-21 00:38+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"

View file

@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2025.4\n" "Project-Id-Version: EVIBES 2025.4\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-12-18 17:19+0300\n" "POT-Creation-Date: 2025-12-21 00:38+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"

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2025.4\n" "Project-Id-Version: EVIBES 2025.4\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-12-18 17:19+0300\n" "POT-Creation-Date: 2025-12-21 00:38+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"

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2025.4\n" "Project-Id-Version: EVIBES 2025.4\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-12-18 17:19+0300\n" "POT-Creation-Date: 2025-12-21 00:38+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"

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2025.4\n" "Project-Id-Version: EVIBES 2025.4\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-12-18 17:19+0300\n" "POT-Creation-Date: 2025-12-21 00:38+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"

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2025.4\n" "Project-Id-Version: EVIBES 2025.4\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-12-18 17:19+0300\n" "POT-Creation-Date: 2025-12-21 00:38+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"

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2025.4\n" "Project-Id-Version: EVIBES 2025.4\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-12-18 17:19+0300\n" "POT-Creation-Date: 2025-12-21 00:38+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"

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2025.4\n" "Project-Id-Version: EVIBES 2025.4\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-12-18 17:19+0300\n" "POT-Creation-Date: 2025-12-21 00:38+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"

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2025.4\n" "Project-Id-Version: EVIBES 2025.4\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-12-18 17:19+0300\n" "POT-Creation-Date: 2025-12-21 00:38+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"

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2025.4\n" "Project-Id-Version: EVIBES 2025.4\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-12-18 17:19+0300\n" "POT-Creation-Date: 2025-12-21 00:38+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"

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2025.4\n" "Project-Id-Version: EVIBES 2025.4\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-12-18 17:19+0300\n" "POT-Creation-Date: 2025-12-21 00:38+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"

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2025.4\n" "Project-Id-Version: EVIBES 2025.4\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-12-18 17:19+0300\n" "POT-Creation-Date: 2025-12-21 00:38+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"

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2025.4\n" "Project-Id-Version: EVIBES 2025.4\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-12-18 17:19+0300\n" "POT-Creation-Date: 2025-12-21 00:38+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"

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2025.4\n" "Project-Id-Version: EVIBES 2025.4\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-12-18 17:19+0300\n" "POT-Creation-Date: 2025-12-21 00:38+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"

View file

@ -99,7 +99,7 @@ class Post(NiceModel):
verbose_name = _("post") verbose_name = _("post")
verbose_name_plural = _("posts") verbose_name_plural = _("posts")
def save(self, **kwargs): def save(self, *args, **kwargs):
if self.file: if self.file:
raise ValueError( raise ValueError(
_("markdown files are not supported yet - use markdown content instead") _("markdown files are not supported yet - use markdown content instead")
@ -110,7 +110,7 @@ class Post(NiceModel):
"a markdown file or markdown content must be provided - mutually exclusive" "a markdown file or markdown content must be provided - mutually exclusive"
) )
) )
super().save(**kwargs) super().save(*args, **kwargs)
class PostTag(NiceModel): class PostTag(NiceModel):

View file

@ -31,13 +31,13 @@ class NiceModel(Model):
def save( def save(
self, self,
*, *args,
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[str] | None = None, update_fields: Collection[str] | None = None,
update_modified: bool = True, update_modified: bool = True,
) -> None: ) -> None: # ty:ignore[invalid-method-override]
self.update_modified = update_modified self.update_modified = update_modified
return super().save( return super().save(
force_insert=force_insert, force_insert=force_insert,

View file

@ -1,5 +1,5 @@
from contextlib import suppress from contextlib import suppress
from typing import Any, ClassVar, Type from typing import Any, Callable, ClassVar, Type
from constance.admin import Config from constance.admin import Config
from constance.admin import ConstanceAdmin as BaseConstanceAdmin from constance.admin import ConstanceAdmin as BaseConstanceAdmin
@ -145,6 +145,7 @@ class FieldsetsMixin:
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences
class ActivationActionsMixin: class ActivationActionsMixin:
message_user: Callable
actions_on_top = True actions_on_top = True
actions_on_bottom = True actions_on_bottom = True
actions = [ actions = [
@ -466,6 +467,7 @@ class ProductAdmin(
list_filter = ( list_filter = (
"is_active", "is_active",
"is_digital", "is_digital",
"is_updatable",
"stocks__vendor", "stocks__vendor",
"tags__name", "tags__name",
"created", "created",
@ -513,6 +515,9 @@ class ProductAdmin(
"brand", "brand",
"tags", "tags",
] ]
additional_fields = [
"is_updatable",
]
def get_queryset(self, request): def get_queryset(self, request):
return ( return (
@ -1082,10 +1087,8 @@ class ConstanceConfig:
_meta = Meta() _meta = Meta()
# noinspection PyTypeChecker site.unregister([Config]) # ty:ignore[invalid-argument-type]
site.unregister([Config]) site.register([ConstanceConfig], BaseConstanceAdmin) # ty:ignore[invalid-argument-type]
# noinspection PyTypeChecker
site.register([ConstanceConfig], BaseConstanceAdmin)
site.site_title = settings.PROJECT_NAME site.site_title = settings.PROJECT_NAME
site.site_header = "eVibes" site.site_header = "eVibes"
site.index_title = settings.PROJECT_NAME site.index_title = settings.PROJECT_NAME

View file

@ -1,6 +1,6 @@
from django.conf import settings from django.conf import settings
from django.http import FileResponse
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter, extend_schema, inline_serializer from drf_spectacular.utils import OpenApiParameter, extend_schema, inline_serializer
from rest_framework import status from rest_framework import status
from rest_framework.fields import CharField, DictField, JSONField, ListField from rest_framework.fields import CharField, DictField, JSONField, ListField
@ -32,6 +32,9 @@ CUSTOM_OPENAPI_SCHEMA = {
"OpenApi3 schema for this API. Format can be selected via content negotiation. " "OpenApi3 schema for this API. Format can be selected via content negotiation. "
"Language can be selected with Accept-Language and query parameter both." "Language can be selected with Accept-Language and query parameter both."
), ),
responses={
status.HTTP_200_OK: OpenApiTypes.OBJECT,
},
) )
} }
@ -176,7 +179,7 @@ DOWNLOAD_DIGITAL_ASSET_SCHEMA = {
], ],
summary=_("download a digital asset from purchased digital order"), summary=_("download a digital asset from purchased digital order"),
responses={ responses={
status.HTTP_200_OK: FileResponse, status.HTTP_200_OK: OpenApiTypes.BINARY,
status.HTTP_400_BAD_REQUEST: error, status.HTTP_400_BAD_REQUEST: error,
}, },
) )

View file

@ -234,7 +234,7 @@ CATEGORY_SCHEMA = {
name="lookup_value", name="lookup_value",
location="path", location="path",
description=_("Category UUID or slug"), description=_("Category UUID or slug"),
type=str, type=OpenApiTypes.STR,
), ),
], ],
responses={status.HTTP_200_OK: CategoryDetailSerializer(), **BASE_ERRORS}, responses={status.HTTP_200_OK: CategoryDetailSerializer(), **BASE_ERRORS},
@ -284,7 +284,7 @@ CATEGORY_SCHEMA = {
name="lookup_value", name="lookup_value",
location="path", location="path",
description=_("Category UUID or slug"), description=_("Category UUID or slug"),
type=str, type=OpenApiTypes.STR,
), ),
], ],
responses={ responses={
@ -369,7 +369,7 @@ ORDER_SCHEMA = {
name="lookup_value", name="lookup_value",
location="path", location="path",
description=_("Order UUID or human-readable id"), description=_("Order UUID or human-readable id"),
type=str, type=OpenApiTypes.STR,
), ),
], ],
responses={status.HTTP_200_OK: OrderDetailSerializer(), **BASE_ERRORS}, responses={status.HTTP_200_OK: OrderDetailSerializer(), **BASE_ERRORS},
@ -1006,7 +1006,7 @@ BRAND_SCHEMA = {
name="lookup_value", name="lookup_value",
location="path", location="path",
description=_("Brand UUID or slug"), description=_("Brand UUID or slug"),
type=str, type=OpenApiTypes.STR,
), ),
], ],
responses={status.HTTP_200_OK: BrandDetailSerializer(), **BASE_ERRORS}, responses={status.HTTP_200_OK: BrandDetailSerializer(), **BASE_ERRORS},
@ -1049,7 +1049,7 @@ BRAND_SCHEMA = {
name="lookup_value", name="lookup_value",
location="path", location="path",
description=_("Brand UUID or slug"), description=_("Brand UUID or slug"),
type=str, type=OpenApiTypes.STR,
), ),
], ],
responses={status.HTTP_200_OK: SeoSnapshotSerializer(), **BASE_ERRORS}, responses={status.HTTP_200_OK: SeoSnapshotSerializer(), **BASE_ERRORS},

View file

@ -10,6 +10,7 @@ from django_elasticsearch_dsl import fields
from django_elasticsearch_dsl.registries import registry from django_elasticsearch_dsl.registries import registry
from elasticsearch import NotFoundError from elasticsearch import NotFoundError
from elasticsearch.dsl import Q, Search from elasticsearch.dsl import Q, Search
from elasticsearch.dsl.types import Hit
from rest_framework.request import Request from rest_framework.request import Request
from engine.core.models import Brand, Category, Product from engine.core.models import Brand, Category, Product
@ -199,8 +200,8 @@ def process_query(
minimum_should_match=1, minimum_should_match=1,
) )
def build_search(idxs: list[str], size: int) -> Search: def build_search(idxs: list[str], size: int) -> Search[Hit]:
return ( result: Search[Hit] = ( # ty: ignore[invalid-assignment]
Search(index=idxs) Search(index=idxs)
.query(query_base) .query(query_base)
.extra( .extra(
@ -222,6 +223,7 @@ def process_query(
) )
.extra(size=size, track_total_hits=True) .extra(size=size, track_total_hits=True)
) )
return result
resp_cats = None resp_cats = None
if "categories" in indexes: if "categories" in indexes:
@ -289,12 +291,12 @@ def process_query(
] ]
for qx in product_exact_sequence: for qx in product_exact_sequence:
try: try:
resp_exact = ( search_exact = (
Search(index=["products"]) Search(index=["products"])
.query(qx) .query(qx)
.extra(size=5, track_total_hits=False) .extra(size=5, track_total_hits=False)
.execute()
) )
resp_exact = search_exact.execute() # ty: ignore[possibly-missing-attribute]
except NotFoundError: except NotFoundError:
resp_exact = None resp_exact = None
if resp_exact is not None and getattr(resp_exact, "hits", None): if resp_exact is not None and getattr(resp_exact, "hits", None):
@ -309,7 +311,7 @@ def process_query(
.extra(size=5, track_total_hits=False) .extra(size=5, track_total_hits=False)
) )
try: try:
resp_exact = s_exact.execute() resp_exact = s_exact.execute() # ty: ignore[possibly-missing-attribute]
except NotFoundError: except NotFoundError:
resp_exact = None resp_exact = None
if resp_exact is not None and getattr(resp_exact, "hits", None): if resp_exact is not None and getattr(resp_exact, "hits", None):
@ -434,7 +436,7 @@ 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[misc]
def should_index_object(self, obj) -> bool: def should_index_object(self, obj) -> bool:
return getattr(obj, "is_active", False) return getattr(obj, "is_active", False)
@ -665,7 +667,7 @@ def process_system_query(
.query(mm) .query(mm)
.extra(size=size_per_index, track_total_hits=False) .extra(size=size_per_index, track_total_hits=False)
) )
resp = s.execute() resp = s.execute() # ty: ignore[possibly-missing-attribute]
for h in resp.hits: for h in resp.hits:
name = getattr(h, "name", None) or getattr(h, "title", None) or "N/A" name = getattr(h, "name", None) or getattr(h, "title", None) or "N/A"
results[idx].append( results[idx].append(

View file

@ -152,7 +152,7 @@ class ProductFilter(FilterSet):
data: dict[Any, Any] | None = None, data: dict[Any, Any] | None = None,
queryset: QuerySet[Product] | None = None, queryset: QuerySet[Product] | None = None,
*, *,
request: HttpRequest | Request | Context = None, request: HttpRequest | Request | Context | None = None,
prefix: str | None = None, prefix: str | None = None,
) -> None: ) -> None:
super().__init__(data=data, queryset=queryset, request=request, prefix=prefix) super().__init__(data=data, queryset=queryset, request=request, prefix=prefix)
@ -516,12 +516,12 @@ class CategoryFilter(FilterSet):
if not value: if not value:
return queryset return queryset
uuids = [ s_result = process_query(query=value, indexes=("categories",))
category.get("uuid")
for category in process_query(query=value, indexes=("categories",))[ if not s_result:
"categories" raise ValueError("Search is unprocessable")
]
] uuids = [category.get("uuid") for category in s_result.get("categories", [])]
return queryset.filter(uuid__in=uuids) return queryset.filter(uuid__in=uuids)
@ -650,10 +650,11 @@ class BrandFilter(FilterSet):
if not value: if not value:
return queryset return queryset
uuids = [ s_result = process_query(query=value, indexes=("brands",))
brand.get("uuid") if not s_result:
for brand in process_query(query=value, indexes=("brands",))["brands"] return queryset.none()
]
uuids = [brand.get("uuid") for brand in s_result.get("brands", [])]
return queryset.filter(uuid__in=uuids) return queryset.filter(uuid__in=uuids)

View file

@ -1,12 +0,0 @@
from typing import Any
from graphene import Mutation
class BaseMutation(Mutation):
def __init__(self, *args: list[Any], **kwargs: dict[Any, Any]) -> None:
super().__init__(*args, **kwargs)
@staticmethod
def mutate(**kwargs: Any) -> None:
pass

View file

@ -1,179 +0,0 @@
from contextlib import suppress
from django.core.exceptions import PermissionDenied
from django.utils.translation import gettext_lazy as _
from graphene import UUID, Boolean, Field, InputObjectType, List, NonNull, String
from engine.core.graphene import BaseMutation
from engine.core.graphene.object_types import ProductType
from engine.core.models import (
Attribute,
AttributeGroup,
AttributeValue,
Brand,
Category,
Product,
ProductTag,
)
from engine.core.utils.messages import permission_denied_message
def resolve_attributes(product, attributes):
for attr_input in attributes:
attribute = None
attr_uuid = attr_input.get("attribute_uuid")
if attr_uuid:
with suppress(Attribute.DoesNotExist):
attribute = Attribute.objects.get(uuid=attr_uuid)
if attribute is None:
group_name = attr_input.get("group_name")
attribute_name = attr_input.get("attribute_name")
value_type = attr_input.get("value_type") or "string"
if group_name and attribute_name:
group, _ = AttributeGroup.objects.get_or_create(name=group_name)
attribute, _ = Attribute.objects.get_or_create(
group=group,
name=attribute_name,
defaults={"value_type": value_type},
)
if attribute.value_type != value_type:
attribute.value_type = value_type
attribute.save(update_fields=["value_type"])
if attribute is not None:
AttributeValue.objects.update_or_create(
product=product,
attribute=attribute,
defaults={"value": str(attr_input.get("value", ""))},
)
def resolve_tags(product, tag_uuids):
tags = list(ProductTag.objects.filter(uuid__in=tag_uuids))
if tags:
product.tags.set(tags)
class AttributeInput(InputObjectType):
attribute_uuid = UUID(required=False, name="attributeUuid")
group_name = String(required=False, name="groupName")
attribute_name = String(required=False, name="attributeName")
value_type = String(required=False, name="valueType")
value = String(required=True)
class ProductInput(InputObjectType):
name = NonNull(String)
description = String(required=False)
is_digital = Boolean(required=False, name="isDigital")
partnumber = String(required=False)
sku = String(required=False)
category_uuid = NonNull(UUID, name="categoryUuid")
brand_uuid = UUID(required=False, name="brandUuid")
tag_uuids = List(UUID, required=False, name="tagUuids")
attributes = List(NonNull(AttributeInput), required=False)
# noinspection PyUnusedLocal,PyTypeChecker
class CreateProduct(BaseMutation):
class Meta:
description = _("create a product")
class Arguments:
product_data = NonNull(ProductInput, name="productData")
product = Field(ProductType)
@staticmethod
def mutate(parent, info, product_data):
user = info.context.user
if not user.has_perm("core.add_product"):
raise PermissionDenied(permission_denied_message)
category = Category.objects.get(uuid=product_data["category_uuid"])
brand = None
if product_data.get("brand_uuid"):
with suppress(Brand.DoesNotExist):
brand = Brand.objects.get(uuid=product_data["brand_uuid"])
product = Product.objects.create(
name=product_data["name"],
description=product_data.get("description"),
is_digital=product_data.get("is_digital") or False,
partnumber=product_data.get("partnumber"),
sku=product_data.get("sku") or None,
category=category,
brand=brand,
)
resolve_tags(product, product_data.get("tag_uuids", []))
resolve_attributes(product, product_data.get("attributes", []))
return CreateProduct(product=product)
# noinspection PyUnusedLocal,PyTypeChecker
class UpdateProduct(BaseMutation):
class Meta:
description = _("create a product")
class Arguments:
product_uuid = UUID(required=True)
product_data = NonNull(ProductInput, name="productData")
product = Field(ProductType)
@staticmethod
def mutate(parent, info, product_uuid, product_data):
user = info.context.user
if not user.has_perm("core.change_product"):
raise PermissionDenied(permission_denied_message)
product = Product.objects.get(uuid=product_uuid)
updates = {}
for field_in, model_field in (
("name", "name"),
("description", "description"),
("is_digital", "is_digital"),
("partnumber", "partnumber"),
("sku", "sku"),
):
if field_in in product_data and product_data[field_in] is not None:
updates[model_field] = product_data[field_in]
if product_data.get("category_uuid"):
product.category = Category.objects.get(uuid=product_data["category_uuid"])
if product_data.get("brand_uuid") is not None:
if product_data.get("brand_uuid"):
product.brand = Brand.objects.get(uuid=product_data["brand_uuid"])
else:
product.brand = None
for k, v in updates.items():
setattr(product, k, v)
product.save()
resolve_tags(product, product_data.get("tag_uuids", []))
resolve_attributes(product, product_data.get("attributes"))
return UpdateProduct(product=product)
# noinspection PyUnusedLocal,PyTypeChecker
class DeleteProduct(BaseMutation):
class Meta:
description = _("create a product")
class Arguments:
product_uuid = UUID(required=True)
ok = Boolean()
@staticmethod
def mutate(parent, info, product_uuid):
user = info.context.user
if not user.has_perm("core.delete_product"):
raise PermissionDenied(permission_denied_message)
Product.objects.get(uuid=product_uuid).delete()
return DeleteProduct(ok=True)

View file

@ -6,11 +6,10 @@ from django.core.cache import cache
from django.core.exceptions import BadRequest, PermissionDenied from django.core.exceptions import BadRequest, PermissionDenied
from django.http import Http404 from django.http import Http404
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from graphene import UUID, Boolean, Field, Int, List, String from graphene import UUID, Boolean, Field, Int, List, Mutation, String
from graphene.types.generic import GenericScalar from graphene.types.generic import GenericScalar
from engine.core.elasticsearch import process_query from engine.core.elasticsearch import process_query
from engine.core.graphene import BaseMutation
from engine.core.graphene.object_types import ( from engine.core.graphene.object_types import (
AddressType, AddressType,
BulkProductInput, BulkProductInput,
@ -32,7 +31,7 @@ logger = logging.getLogger(__name__)
# noinspection PyUnusedLocal # noinspection PyUnusedLocal
class CacheOperator(BaseMutation): class CacheOperator(Mutation):
class Meta: class Meta:
description = _("cache I/O") description = _("cache I/O")
@ -54,7 +53,7 @@ class CacheOperator(BaseMutation):
# noinspection PyUnusedLocal # noinspection PyUnusedLocal
class RequestCursedURL(BaseMutation): class RequestCursedURL(Mutation):
class Meta: class Meta:
description = _("request a CORSed URL") description = _("request a CORSed URL")
@ -82,7 +81,7 @@ class RequestCursedURL(BaseMutation):
# noinspection PyUnusedLocal,PyTypeChecker # noinspection PyUnusedLocal,PyTypeChecker
class AddOrderProduct(BaseMutation): class AddOrderProduct(Mutation):
class Meta: class Meta:
description = _("add a product to the order") description = _("add a product to the order")
@ -105,13 +104,13 @@ class AddOrderProduct(BaseMutation):
product_uuid=product_uuid, attributes=format_attributes(attributes) product_uuid=product_uuid, attributes=format_attributes(attributes)
) )
return AddOrderProduct(order=order) return AddOrderProduct(order=order) # ty: ignore[unknown-argument]
except Order.DoesNotExist as dne: except Order.DoesNotExist as dne:
raise Http404(_(f"order {order_uuid} not found")) from dne raise Http404(_(f"order {order_uuid} not found")) from dne
# noinspection PyUnusedLocal,PyTypeChecker # noinspection PyUnusedLocal,PyTypeChecker
class RemoveOrderProduct(BaseMutation): class RemoveOrderProduct(Mutation):
class Meta: class Meta:
description = _("remove a product from the order") description = _("remove a product from the order")
@ -134,13 +133,13 @@ class RemoveOrderProduct(BaseMutation):
product_uuid=product_uuid, attributes=format_attributes(attributes) product_uuid=product_uuid, attributes=format_attributes(attributes)
) )
return RemoveOrderProduct(order=order) return RemoveOrderProduct(order=order) # ty: ignore[unknown-argument]
except Order.DoesNotExist as dne: except Order.DoesNotExist as dne:
raise Http404(_(f"order {order_uuid} not found")) from dne raise Http404(_(f"order {order_uuid} not found")) from dne
# noinspection PyUnusedLocal,PyTypeChecker # noinspection PyUnusedLocal,PyTypeChecker
class RemoveAllOrderProducts(BaseMutation): class RemoveAllOrderProducts(Mutation):
class Meta: class Meta:
description = _("remove all products from the order") description = _("remove all products from the order")
@ -158,11 +157,11 @@ class RemoveAllOrderProducts(BaseMutation):
order = order.remove_all_products() order = order.remove_all_products()
return RemoveAllOrderProducts(order=order) return RemoveAllOrderProducts(order=order) # ty: ignore[unknown-argument]
# noinspection PyUnusedLocal,PyTypeChecker # noinspection PyUnusedLocal,PyTypeChecker
class RemoveOrderProductsOfAKind(BaseMutation): class RemoveOrderProductsOfAKind(Mutation):
class Meta: class Meta:
description = _("remove a product from the order") description = _("remove a product from the order")
@ -181,11 +180,11 @@ class RemoveOrderProductsOfAKind(BaseMutation):
order = order.remove_products_of_a_kind(product_uuid=product_uuid) order = order.remove_products_of_a_kind(product_uuid=product_uuid)
return RemoveOrderProductsOfAKind(order=order) return RemoveOrderProductsOfAKind(order=order) # ty: ignore[unknown-argument]
# noinspection PyUnusedLocal,PyTypeChecker # noinspection PyUnusedLocal,PyTypeChecker
class BuyOrder(BaseMutation): class BuyOrder(Mutation):
class Meta: class Meta:
description = _("buy an order") description = _("buy an order")
@ -230,7 +229,7 @@ class BuyOrder(BaseMutation):
elif order_hr_id: elif order_hr_id:
order = Order.objects.get(user=user, human_readable_id=order_hr_id) order = Order.objects.get(user=user, human_readable_id=order_hr_id)
instance = order.buy( instance = order.buy( # ty: ignore[possibly-missing-attribute]
force_balance=force_balance, force_balance=force_balance,
force_payment=force_payment, force_payment=force_payment,
promocode_uuid=promocode_uuid, promocode_uuid=promocode_uuid,
@ -241,9 +240,9 @@ class BuyOrder(BaseMutation):
match str(type(instance)): match str(type(instance)):
case "<class 'engine.payments.models.Transaction'>": case "<class 'engine.payments.models.Transaction'>":
return BuyOrder(transaction=instance) return BuyOrder(transaction=instance) # ty: ignore[unknown-argument]
case "<class 'engine.core.models.Order'>": case "<class 'engine.core.models.Order'>":
return BuyOrder(order=instance) return BuyOrder(order=instance) # ty: ignore[unknown-argument]
case _: case _:
raise TypeError( raise TypeError(
_( _(
@ -256,7 +255,7 @@ class BuyOrder(BaseMutation):
# noinspection PyUnusedLocal,PyTypeChecker # noinspection PyUnusedLocal,PyTypeChecker
class BulkOrderAction(BaseMutation): class BulkOrderAction(Mutation):
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")
@ -295,20 +294,20 @@ class BulkOrderAction(BaseMutation):
# noinspection PyUnreachableCode # noinspection PyUnreachableCode
match action: match action:
case "add": case "add":
order = order.bulk_add_products(products) order = order.bulk_add_products(products) # ty: ignore[possibly-missing-attribute]
case "remove": case "remove":
order = order.bulk_remove_products(products) order = order.bulk_remove_products(products) # ty: ignore[possibly-missing-attribute]
case _: case _:
raise BadRequest(_("action must be either add or remove")) raise BadRequest(_("action must be either add or remove"))
return BulkOrderAction(order=order) return BulkOrderAction(order=order) # ty: ignore[unknown-argument]
except Order.DoesNotExist as dne: except Order.DoesNotExist as dne:
raise Http404(_(f"order {order_uuid} not found")) from dne raise Http404(_(f"order {order_uuid} not found")) from dne
# noinspection PyUnusedLocal,PyTypeChecker # noinspection PyUnusedLocal,PyTypeChecker
class BulkWishlistAction(BaseMutation): class BulkWishlistAction(Mutation):
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")
@ -336,20 +335,20 @@ class BulkWishlistAction(BaseMutation):
# noinspection PyUnreachableCode # noinspection PyUnreachableCode
match action: match action:
case "add": case "add":
wishlist = wishlist.bulk_add_products(products) wishlist = wishlist.bulk_add_products(products) # ty: ignore[possibly-missing-attribute]
case "remove": case "remove":
wishlist = wishlist.bulk_remove_products(products) wishlist = wishlist.bulk_remove_products(products) # ty: ignore[possibly-missing-attribute]
case _: case _:
raise BadRequest(_("action must be either add or remove")) raise BadRequest(_("action must be either add or remove"))
return BulkWishlistAction(wishlist=wishlist) return BulkWishlistAction(wishlist=wishlist) # ty: ignore[unknown-argument]
except Wishlist.DoesNotExist as dne: except Wishlist.DoesNotExist as dne:
raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
# noinspection PyUnusedLocal # noinspection PyUnusedLocal
class BuyUnregisteredOrder(BaseMutation): class BuyUnregisteredOrder(Mutation):
class Meta: class Meta:
description = _("purchase an order without account creation") description = _("purchase an order without account creation")
@ -393,11 +392,11 @@ class BuyUnregisteredOrder(BaseMutation):
is_business=is_business, is_business=is_business,
) )
# noinspection PyTypeChecker # noinspection PyTypeChecker
return BuyUnregisteredOrder(transaction=transaction) return BuyUnregisteredOrder(transaction=transaction) # ty: ignore[unknown-argument]
# noinspection PyUnusedLocal,PyTypeChecker # noinspection PyUnusedLocal,PyTypeChecker
class AddWishlistProduct(BaseMutation): class AddWishlistProduct(Mutation):
class Meta: class Meta:
description = _("add a product to the wishlist") description = _("add a product to the wishlist")
@ -418,14 +417,14 @@ class AddWishlistProduct(BaseMutation):
wishlist.add_product(product_uuid=product_uuid) wishlist.add_product(product_uuid=product_uuid)
return AddWishlistProduct(wishlist=wishlist) return AddWishlistProduct(wishlist=wishlist) # ty: ignore[unknown-argument]
except Wishlist.DoesNotExist as dne: except Wishlist.DoesNotExist as dne:
raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
# noinspection PyUnusedLocal,PyTypeChecker # noinspection PyUnusedLocal,PyTypeChecker
class RemoveWishlistProduct(BaseMutation): class RemoveWishlistProduct(Mutation):
class Meta: class Meta:
description = _("remove a product from the wishlist") description = _("remove a product from the wishlist")
@ -446,14 +445,14 @@ class RemoveWishlistProduct(BaseMutation):
wishlist.remove_product(product_uuid=product_uuid) wishlist.remove_product(product_uuid=product_uuid)
return RemoveWishlistProduct(wishlist=wishlist) return RemoveWishlistProduct(wishlist=wishlist) # ty: ignore[unknown-argument]
except Wishlist.DoesNotExist as dne: except Wishlist.DoesNotExist as dne:
raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
# noinspection PyUnusedLocal,PyTypeChecker # noinspection PyUnusedLocal,PyTypeChecker
class RemoveAllWishlistProducts(BaseMutation): class RemoveAllWishlistProducts(Mutation):
class Meta: class Meta:
description = _("remove all products from the wishlist") description = _("remove all products from the wishlist")
@ -474,14 +473,14 @@ class RemoveAllWishlistProducts(BaseMutation):
for product in wishlist.products.all(): for product in wishlist.products.all():
wishlist.remove_product(product_uuid=product.pk) wishlist.remove_product(product_uuid=product.pk)
return RemoveAllWishlistProducts(wishlist=wishlist) return RemoveAllWishlistProducts(wishlist=wishlist) # ty: ignore[unknown-argument]
except Wishlist.DoesNotExist as dne: except Wishlist.DoesNotExist as dne:
raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
# noinspection PyUnusedLocal,PyTypeChecker # noinspection PyUnusedLocal,PyTypeChecker
class BuyWishlist(BaseMutation): class BuyWishlist(Mutation):
class Meta: class Meta:
description = _("buy all products from the wishlist") description = _("buy all products from the wishlist")
@ -516,9 +515,9 @@ class BuyWishlist(BaseMutation):
) )
match str(type(instance)): match str(type(instance)):
case "<class 'engine.payments.models.Transaction'>": case "<class 'engine.payments.models.Transaction'>":
return BuyWishlist(transaction=instance) return BuyWishlist(transaction=instance) # ty: ignore[unknown-argument]
case "<class 'engine.core.models.Order'>": case "<class 'engine.core.models.Order'>":
return BuyWishlist(order=instance) return BuyWishlist(order=instance) # ty: ignore[unknown-argument]
case _: case _:
raise TypeError( raise TypeError(
_( _(
@ -531,7 +530,7 @@ class BuyWishlist(BaseMutation):
# noinspection PyUnusedLocal,PyTypeChecker # noinspection PyUnusedLocal,PyTypeChecker
class BuyProduct(BaseMutation): class BuyProduct(Mutation):
class Meta: class Meta:
description = _("buy a product") description = _("buy a product")
@ -566,9 +565,9 @@ class BuyProduct(BaseMutation):
instance = order.buy(force_balance=force_balance, force_payment=force_payment) instance = order.buy(force_balance=force_balance, force_payment=force_payment)
match str(type(instance)): match str(type(instance)):
case "<class 'engine.payments.models.Transaction'>": case "<class 'engine.payments.models.Transaction'>":
return BuyProduct(transaction=instance) return BuyProduct(transaction=instance) # ty: ignore[unknown-argument]
case "<class 'engine.core.models.Order'>": case "<class 'engine.core.models.Order'>":
return BuyProduct(order=instance) return BuyProduct(order=instance) # ty: ignore[unknown-argument]
case _: case _:
raise TypeError( raise TypeError(
_(f"wrong type came from order.buy() method: {type(instance)!s}") _(f"wrong type came from order.buy() method: {type(instance)!s}")
@ -576,7 +575,7 @@ class BuyProduct(BaseMutation):
# noinspection PyUnusedLocal,PyTypeChecker # noinspection PyUnusedLocal,PyTypeChecker
class FeedbackProductAction(BaseMutation): class FeedbackProductAction(Mutation):
class Meta: class Meta:
description = _("add or delete a feedback for orderproduct") description = _("add or delete a feedback for orderproduct")
@ -605,13 +604,13 @@ class FeedbackProductAction(BaseMutation):
feedback = order_product.do_feedback(action="remove") feedback = order_product.do_feedback(action="remove")
case _: case _:
raise BadRequest(_("action must be either `add` or `remove`")) raise BadRequest(_("action must be either `add` or `remove`"))
return FeedbackProductAction(feedback=feedback) return FeedbackProductAction(feedback=feedback) # ty: ignore[unknown-argument]
except OrderProduct.DoesNotExist as dne: except OrderProduct.DoesNotExist as dne:
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 # noinspection PyUnusedLocal,PyTypeChecker
class CreateAddress(BaseMutation): class CreateAddress(Mutation):
class Arguments: class Arguments:
raw_data = String( raw_data = String(
required=True, description=_("original address string provided by the user") required=True, description=_("original address string provided by the user")
@ -624,11 +623,11 @@ class CreateAddress(BaseMutation):
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) # ty: ignore[unknown-argument]
# noinspection PyUnusedLocal # noinspection PyUnusedLocal
class DeleteAddress(BaseMutation): class DeleteAddress(Mutation):
class Arguments: class Arguments:
uuid = UUID(required=True) uuid = UUID(required=True)
@ -645,7 +644,7 @@ class DeleteAddress(BaseMutation):
): ):
address.delete() address.delete()
# noinspection PyTypeChecker # noinspection PyTypeChecker
return DeleteAddress(success=True) return DeleteAddress(success=True) # ty: ignore[unknown-argument]
raise PermissionDenied(permission_denied_message) raise PermissionDenied(permission_denied_message)
@ -655,7 +654,7 @@ class DeleteAddress(BaseMutation):
# noinspection PyUnusedLocal # noinspection PyUnusedLocal
class AutocompleteAddress(BaseMutation): class AutocompleteAddress(Mutation):
class Arguments: class Arguments:
q = String() q = String()
limit = Int() limit = Int()
@ -672,11 +671,11 @@ class AutocompleteAddress(BaseMutation):
raise BadRequest(f"geocoding error: {e!s}") from e raise BadRequest(f"geocoding error: {e!s}") from e
# noinspection PyTypeChecker # noinspection PyTypeChecker
return AutocompleteAddress(suggestions=suggestions) return AutocompleteAddress(suggestions=suggestions) # ty: ignore[unknown-argument]
# noinspection PyUnusedLocal # noinspection PyUnusedLocal
class ContactUs(BaseMutation): class ContactUs(Mutation):
class Arguments: class Arguments:
email = String(required=True) email = String(required=True)
name = String(required=True) name = String(required=True)
@ -700,14 +699,14 @@ class ContactUs(BaseMutation):
} }
) )
# noinspection PyTypeChecker # noinspection PyTypeChecker
return ContactUs(received=True) return ContactUs(received=True) # ty: ignore[unknown-argument]
except Exception as e: except Exception as e:
# noinspection PyTypeChecker # noinspection PyTypeChecker
return ContactUs(received=False, error=str(e)) return ContactUs(received=False, error=str(e)) # ty: ignore[unknown-argument]
# noinspection PyArgumentList PyUnusedLocal # noinspection PyArgumentList PyUnusedLocal
class Search(BaseMutation): class Search(Mutation):
class Arguments: class Arguments:
query = String(required=True) query = String(required=True)
@ -720,12 +719,15 @@ class Search(BaseMutation):
def mutate(parent, info, query): def mutate(parent, info, query):
data = process_query(query=query, request=info.context) data = process_query(query=query, request=info.context)
if not data:
return Search(results=None) # ty: ignore[unknown-argument]
# noinspection PyTypeChecker # noinspection PyTypeChecker
return Search( return Search( # ty: ignore[unknown-argument]
results=SearchResultsType( results=SearchResultsType( # ty: ignore[unknown-argument]
products=data["products"], products=data["products"], # ty: ignore[unknown-argument]
categories=data["categories"], categories=data["categories"], # ty: ignore[unknown-argument]
brands=data["brands"], brands=data["brands"], # ty: ignore[unknown-argument]
posts=data["posts"], posts=data["posts"], # ty: ignore[unknown-argument]
) )
) )

View file

@ -21,7 +21,9 @@ from graphene import (
) )
from graphene.types.generic import GenericScalar from graphene.types.generic import GenericScalar
from graphene_django import DjangoObjectType from graphene_django import DjangoObjectType
from graphene_django.filter import DjangoFilterConnectionField from graphene_django.filter import (
DjangoFilterConnectionField, # ty:ignore[possibly-missing-import]
)
from mptt.querysets import TreeQuerySet from mptt.querysets import TreeQuerySet
from engine.core.models import ( from engine.core.models import (

View file

@ -6,7 +6,9 @@ from django.core.exceptions import PermissionDenied
from django.db.models import Case, Exists, IntegerField, OuterRef, Q, Value, When from django.db.models import Case, Exists, IntegerField, OuterRef, Q, Value, When
from django.utils import timezone from django.utils import timezone
from graphene import Field, List, ObjectType, Schema from graphene import Field, List, ObjectType, Schema
from graphene_django.filter import DjangoFilterConnectionField from graphene_django.filter import (
DjangoFilterConnectionField, # ty:ignore[possibly-missing-import]
)
from engine.blog.filters import PostFilter from engine.blog.filters import PostFilter
from engine.blog.graphene.object_types import PostType from engine.blog.graphene.object_types import PostType

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

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

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

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

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

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

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

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

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

File diff suppressed because it is too large Load diff

View file

@ -6,7 +6,7 @@ from tempfile import NamedTemporaryFile
from typing import Any from typing import Any
import polib import polib
from django.apps import apps from django.apps import AppConfig, apps
from django.conf import settings from django.conf import settings
from django.core.management.base import BaseCommand, CommandError from django.core.management.base import BaseCommand, CommandError
@ -94,7 +94,7 @@ class Command(BaseCommand):
help="Root path prefix to adjust file links", help="Root path prefix to adjust file links",
) )
def handle(self, *args: list[Any], **options: dict[str, str | list[str]]) -> None: def handle(self, *args: Any, **options: Any) -> None:
langs: list[str] = options.get("target_languages", []) langs: list[str] = options.get("target_languages", [])
if "ALL" in langs: if "ALL" in langs:
langs = list(dict(settings.LANGUAGES).keys()) langs = list(dict(settings.LANGUAGES).keys())
@ -103,7 +103,7 @@ class Command(BaseCommand):
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/"
configs = list(apps.get_app_configs()) configs: list[AppConfig | RootDirectory] = list(apps.get_app_configs())
# noinspection PyTypeChecker # noinspection PyTypeChecker
configs.append(RootDirectory()) configs.append(RootDirectory())

View file

@ -106,10 +106,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: list[Any], **options: dict[Any, Any]) -> None: def handle(self, *args: Any, **options: Any) -> None:
target_langs: list[str] = options["target_languages"] target_langs = options["target_languages"]
if "ALL" in target_langs: if "ALL" in target_langs:
target_langs = DEEPL_TARGET_LANGUAGES_MAPPING.keys() target_langs = list(DEEPL_TARGET_LANGUAGES_MAPPING.keys())
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 = {
@ -122,10 +122,13 @@ class Command(BaseCommand):
raise CommandError("DEEPL_AUTH_KEY not set") raise CommandError("DEEPL_AUTH_KEY not set")
# attempt to import readline for interactive fill # attempt to import readline for interactive fill
readline: Any = None
try: try:
import readline import readline as readline_module
readline = readline_module
except ImportError: except ImportError:
readline = None pass
for target_lang in target_langs: for target_lang in target_langs:
api_code = DEEPL_TARGET_LANGUAGES_MAPPING.get(target_lang) api_code = DEEPL_TARGET_LANGUAGES_MAPPING.get(target_lang)
@ -176,16 +179,16 @@ class Command(BaseCommand):
if readline: if readline:
def hook() -> None: def hook() -> None:
readline.insert_text(default) # noqa: B023 readline.insert_text(default) # noqa: B023 # ty: ignore[unresolved-attribute]
readline.redisplay() readline.redisplay() # ty: ignore[unresolved-attribute]
readline.set_pre_input_hook(hook) readline.set_pre_input_hook(hook) # ty: ignore[unresolved-attribute]
prompt = f"Enter translation for '{e.msgid}': " prompt = f"Enter translation for '{e.msgid}': "
user_in = input(prompt).strip() user_in = input(prompt).strip()
if readline: if readline:
readline.set_pre_input_hook(None) readline.set_pre_input_hook(None) # ty: ignore[unresolved-attribute]
if user_in: if user_in:
e.msgstr = user_in e.msgstr = user_in

View file

@ -18,7 +18,7 @@ class Command(BaseCommand):
help="Chunk size to delete", help="Chunk size to delete",
) )
def handle(self, *args: list[Any], **options: dict[Any, Any]) -> None: def handle(self, *args: Any, **options: Any) -> None:
size: int = options["size"] size: int = options["size"]
while True: while True:
batch_ids = list( batch_ids = list(

View file

@ -18,7 +18,7 @@ class Command(BaseCommand):
help="Chunk size to delete", help="Chunk size to delete",
) )
def handle(self, *args: list[Any], **options: dict[Any, Any]) -> None: def handle(self, *args: Any, **options: Any) -> None:
size: int = options["size"] size: int = options["size"]
while True: while True:
batch_ids = list( batch_ids = list(

View file

@ -14,7 +14,7 @@ class AddressManager(models.Manager):
if not kwargs.get("raw_data"): if not kwargs.get("raw_data"):
raise ValueError("'raw_data' (address string) must be provided.") raise ValueError("'raw_data' (address string) must be provided.")
params: dict[str, str | int] = { params: dict[str, str | int | None] = {
"format": "json", "format": "json",
"addressdetails": 1, "addressdetails": 1,
"q": kwargs.get("raw_data"), "q": kwargs.get("raw_data"),

Some files were not shown because too many files have changed in this diff Show more