Merge branch 'main' into storefront-nuxt
This commit is contained in:
commit
408dee727e
353 changed files with 24535 additions and 18260 deletions
|
|
@ -11,6 +11,7 @@ coverage.*
|
|||
*.cover
|
||||
*.py,cover
|
||||
nosetests.xml
|
||||
desktop.ini
|
||||
|
||||
# Cache directories
|
||||
__pycache__/
|
||||
|
|
@ -37,7 +38,6 @@ __pypackages__/
|
|||
# Packaging and distribution
|
||||
# ──────────────────────────────────────────────────────────────────────────
|
||||
build/
|
||||
dist/
|
||||
dist-ssr/
|
||||
*.egg
|
||||
*.egg-info/
|
||||
|
|
|
|||
7
.gitignore
vendored
7
.gitignore
vendored
|
|
@ -64,8 +64,9 @@ htmlcov/
|
|||
.pybuilder/
|
||||
|
||||
# Storefronts
|
||||
.astro/
|
||||
.nuxt/
|
||||
.next/
|
||||
next-env.d.ts
|
||||
|
||||
# Celery
|
||||
celerybeat-schedule
|
||||
|
|
@ -141,6 +142,10 @@ cypress/screenshots/
|
|||
|
||||
# JetBrains
|
||||
.idea/
|
||||
!.idea/icon.svg
|
||||
!.idea/externalDependencies.xml
|
||||
!.idea/evibes.iml
|
||||
!.idea/evibes.ico
|
||||
|
||||
# Microsoft
|
||||
*.suo
|
||||
|
|
|
|||
BIN
.idea/evibes.ico
Normal file
BIN
.idea/evibes.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 41 KiB |
35
.idea/evibes.iml
Normal file
35
.idea/evibes.iml
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="django" name="Django">
|
||||
<configuration>
|
||||
<option name="rootFolder" value="$MODULE_DIR$" />
|
||||
<option name="settingsModule" value="evibes/settings/__init__.py" />
|
||||
<option name="manageScript" value="$MODULE_DIR$/manage.py" />
|
||||
<option name="environment" value="<map/>" />
|
||||
<option name="doNotUseTestRunner" value="false" />
|
||||
<option name="trackFilePattern" value="migrations" />
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
<component name="PyDocumentationSettings">
|
||||
<option name="format" value="PLAIN" />
|
||||
<option name="myDocStringFormat" value="Plain" />
|
||||
</component>
|
||||
<component name="TemplatesService">
|
||||
<option name="TEMPLATE_CONFIGURATION" value="Django" />
|
||||
<option name="TEMPLATE_FOLDERS">
|
||||
<list>
|
||||
<option value="$MODULE_DIR$/blog/templates" />
|
||||
<option value="$MODULE_DIR$/core/templates" />
|
||||
<option value="$MODULE_DIR$/payments/templates" />
|
||||
<option value="$MODULE_DIR$/vibes_auth/templates" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
</module>
|
||||
18
.idea/externalDependencies.xml
Normal file
18
.idea/externalDependencies.xml
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalDependencies">
|
||||
<plugin id="Docker" />
|
||||
<plugin id="Git4Idea" />
|
||||
<plugin id="Pythonid" />
|
||||
<plugin id="com.github.xepozz.gitcodeowners" />
|
||||
<plugin id="com.intellij.python.django" />
|
||||
<plugin id="com.koxudaxi.ruff" />
|
||||
<plugin id="com.leinardi.pycharm.mypy" />
|
||||
<plugin id="com.mallowigi" />
|
||||
<plugin id="com.nasller.CodeGlancePro" />
|
||||
<plugin id="dev.meanmail.plugin.nginx-intellij-plugin" />
|
||||
<plugin id="mobi.hsz.idea.gitignore" />
|
||||
<plugin id="org.jetbrains.plugins.astro" />
|
||||
<plugin id="ru.adelf.idea.dotenv" />
|
||||
</component>
|
||||
</project>
|
||||
25
.idea/icon.svg
Normal file
25
.idea/icon.svg
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="100.000000pt" height="100.000000pt" viewBox="0 0 100.000000 100.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
|
||||
<g transform="translate(0.000000,100.000000) scale(0.100000,-0.100000)"
|
||||
fill="#7965D1" stroke="none">
|
||||
<path d="M678 935 c-73 -50 -88 -121 -38 -175 29 -31 50 -35 57 -13 2 6 -5 14
|
||||
-16 18 -30 9 -26 48 9 88 63 72 130 72 149 -1 18 -67 -6 -117 -89 -182 -97
|
||||
-76 -142 -97 -235 -109 -121 -16 -324 -29 -380 -24 -48 5 -49 4 -33 -13 26
|
||||
-26 108 -34 248 -23 308 23 362 40 480 147 l65 59 0 64 c0 79 -17 114 -72 152
|
||||
-61 41 -100 44 -145 12z"/>
|
||||
<path d="M327 912 c-10 -10 -17 -27 -17 -38 0 -24 35 -64 55 -64 18 0 19 12 3
|
||||
28 -16 16 19 54 46 50 17 -2 22 -11 24 -45 4 -55 -38 -105 -105 -124 -50 -14
|
||||
-179 -17 -225 -6 -34 9 -36 -3 -6 -23 55 -35 251 -29 327 10 95 48 92 168 -6
|
||||
219 -33 17 -78 13 -96 -7z"/>
|
||||
<path d="M475 435 c-60 -8 -171 -19 -245 -25 -74 -7 -137 -14 -139 -16 -2 -2
|
||||
9 -9 25 -16 35 -15 179 -13 309 3 50 7 146 12 215 13 186 2 223 -22 185 -119
|
||||
-20 -53 -49 -78 -115 -100 -37 -12 -54 -14 -69 -5 -41 21 -16 91 36 105 27 6
|
||||
27 7 9 21 -31 22 -69 17 -99 -14 -15 -15 -27 -34 -27 -42 0 -23 52 -90 81
|
||||
-106 43 -22 73 -17 144 22 73 40 93 64 102 118 21 131 -138 193 -412 161z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
21
CODEOWNERS
21
CODEOWNERS
|
|
@ -4,8 +4,7 @@ README.md @fureunoir contact@fureunoir.com
|
|||
|
||||
LICENSE @fureunoir contact@fureunoir.com
|
||||
|
||||
Dockerfile.app @fureunoir contact@fureunoir.com
|
||||
Dockerfile.storefront @SaVBaD savbad@wiseless.xyz
|
||||
Dockerfiles @@maintainer
|
||||
docker-compose.yml @@maintainer
|
||||
.gitignore @@maintainer
|
||||
.dockerignore @@maintainer
|
||||
|
|
@ -13,14 +12,6 @@ nginx @@maintainer
|
|||
pyproject.toml @fureunoir contact@fureunoir.com
|
||||
poetry.lock @fureunoir contact@fureunoir.com
|
||||
|
||||
blog/ @fureunoir contact@fureunoir.com
|
||||
core/ @fureunoir contact@fureunoir.com
|
||||
evibes/ @fureunoir contact@fureunoir.com
|
||||
payments/ @fureunoir contact@fureunoir.com
|
||||
scripts/ @fureunoir contact@fureunoir.com
|
||||
vibes_auth/ @fureunoir contact@fureunoir.com
|
||||
storefront/ @SaVBaD savbad@wiseless.xyz
|
||||
|
||||
*.py @fureunoir contact@fureunoir.com
|
||||
*.bat @fureunoir contact@fureunoir.com
|
||||
*.sh @fureunoir contact@fureunoir.com
|
||||
|
|
@ -31,5 +22,13 @@ storefront/ @SaVBaD savbad@wiseless.xyz
|
|||
*.mjs @SaVBaD savbad@wiseless.xyz
|
||||
*.cjs @SaVBaD savbad@wiseless.xyz
|
||||
*.vue @SaVBaD savbad@wiseless.xyz
|
||||
*.astro @SaVBaD savbad@wiseless.xyz
|
||||
*.scss @SaVBaD savbad@wiseless.xyz
|
||||
|
||||
blog/ @fureunoir contact@fureunoir.com
|
||||
core/ @fureunoir contact@fureunoir.com
|
||||
evibes/ @fureunoir contact@fureunoir.com
|
||||
payments/ @fureunoir contact@fureunoir.com
|
||||
scripts/ @fureunoir contact@fureunoir.com
|
||||
vibes_auth/ @fureunoir contact@fureunoir.com
|
||||
|
||||
storefront/ @SaVBaD savbad@wiseless.xyz
|
||||
|
|
@ -26,6 +26,7 @@ RUN set -eux; \
|
|||
graphviz-dev \
|
||||
libgts-dev \
|
||||
libpq5 \
|
||||
chrony \
|
||||
graphviz \
|
||||
binutils \
|
||||
libproj-dev \
|
||||
|
|
@ -46,4 +47,4 @@ RUN chmod +x /usr/local/bin/app-entrypoint.sh
|
|||
|
||||
COPY . .
|
||||
|
||||
ENTRYPOINT ["app-entrypoint.sh"]
|
||||
ENTRYPOINT ["/usr/bin/bash", "app-entrypoint.sh"]
|
||||
|
|
@ -26,6 +26,7 @@ RUN set -eux; \
|
|||
graphviz-dev \
|
||||
libgts-dev \
|
||||
libpq5 \
|
||||
chrony \
|
||||
graphviz \
|
||||
binutils \
|
||||
libproj-dev \
|
||||
|
|
@ -46,4 +47,4 @@ RUN chmod +x /usr/local/bin/beat-entrypoint.sh
|
|||
|
||||
COPY . .
|
||||
|
||||
ENTRYPOINT ["beat-entrypoint.sh"]
|
||||
ENTRYPOINT ["/usr/bin/bash", "beat-entrypoint.sh"]
|
||||
50
Dockerfiles/Dockerfile.stock_updater
Normal file
50
Dockerfiles/Dockerfile.stock_updater
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
# syntax=docker/dockerfile:1
|
||||
FROM python:3.12-bookworm
|
||||
LABEL authors="fureunoir"
|
||||
|
||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
LANG=C.UTF-8 \
|
||||
DEBIAN_FRONTEND=noninteractive \
|
||||
PATH="/root/.local/bin:$PATH"
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN set -eux; \
|
||||
sed -i 's|https://deb.debian.org/debian|https://ftp.uk.debian.org/debian|g' /etc/apt/sources.list.d/debian.sources; \
|
||||
apt-get update; \
|
||||
apt-get install -y --no-install-recommends wget gnupg; \
|
||||
wget -qO - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -; \
|
||||
echo "deb http://apt.postgresql.org/pub/repos/apt bookworm-pgdg main" \
|
||||
> /etc/apt/sources.list.d/pgdg.list; \
|
||||
apt-get update; \
|
||||
apt-get install -y --no-install-recommends --fix-missing \
|
||||
build-essential \
|
||||
libpq-dev \
|
||||
gettext \
|
||||
libgettextpo-dev \
|
||||
graphviz-dev \
|
||||
libgts-dev \
|
||||
libpq5 \
|
||||
chrony \
|
||||
graphviz \
|
||||
binutils \
|
||||
libproj-dev \
|
||||
postgresql-client-17 \
|
||||
gdal-bin; \
|
||||
rm -rf /var/lib/apt/lists/*; \
|
||||
pip install --upgrade pip; \
|
||||
curl -sSL https://install.python-poetry.org | python3
|
||||
|
||||
COPY pyproject.toml pyproject.toml
|
||||
COPY poetry.lock poetry.lock
|
||||
|
||||
RUN poetry config virtualenvs.create false
|
||||
RUN poetry install --extras="worker openai" --no-interaction --no-ansi
|
||||
|
||||
COPY ./scripts/Docker/stock-updater-entrypoint.sh /usr/local/bin/stock-updater-entrypoint.sh
|
||||
RUN chmod +x /usr/local/bin/stock-updater-entrypoint.sh
|
||||
|
||||
COPY . .
|
||||
|
||||
ENTRYPOINT ["/usr/bin/bash", "stock-updater-entrypoint.sh"]
|
||||
|
|
@ -26,6 +26,7 @@ RUN set -eux; \
|
|||
graphviz-dev \
|
||||
libgts-dev \
|
||||
libpq5 \
|
||||
chrony \
|
||||
graphviz \
|
||||
binutils \
|
||||
libproj-dev \
|
||||
|
|
@ -46,4 +47,4 @@ RUN chmod +x /usr/local/bin/worker-entrypoint.sh
|
|||
|
||||
COPY . .
|
||||
|
||||
ENTRYPOINT ["worker-entrypoint.sh"]
|
||||
ENTRYPOINT ["/usr/bin/bash", "worker-entrypoint.sh"]
|
||||
|
|
@ -44,10 +44,11 @@ extension.
|
|||
cd eVibes
|
||||
```
|
||||
|
||||
2. Choose the storefront. By default, `main` branch has Astro one. Skip this step if you're OK with Astro.
|
||||
2. Choose the storefront. By default, `main` branch has no storefront included.
|
||||
Skip this step if you're OK with that and plan to only use API or develop your own storefront.
|
||||
|
||||
```bash
|
||||
git checkout storefront-<option: astro, nuxt, remix, svelte, solid, analog >
|
||||
git checkout storefront-<options: nuxt, next, sk, qwik >
|
||||
```
|
||||
|
||||
3. Generate your .env file. Check and confirm the contents afterward.
|
||||
|
|
|
|||
|
|
@ -1,37 +1,40 @@
|
|||
from django.contrib import admin
|
||||
from django_summernote.admin import SummernoteModelAdmin
|
||||
from django.contrib.admin import ModelAdmin, register
|
||||
from django_summernote.admin import SummernoteModelAdminMixin
|
||||
|
||||
from core.admin import ActivationActionsMixin, FieldsetsMixin
|
||||
|
||||
from .models import Post, PostTag
|
||||
|
||||
|
||||
@admin.register(Post)
|
||||
class PostAdmin(SummernoteModelAdmin):
|
||||
@register(Post)
|
||||
class PostAdmin(SummernoteModelAdminMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||
list_display = ("title", "author", "slug", "created", "modified")
|
||||
list_filter = ("author", "tags", "created", "modified")
|
||||
search_fields = ("title", "content")
|
||||
search_fields = ("title", "content", "slug")
|
||||
filter_horizontal = ("tags",)
|
||||
date_hierarchy = "created"
|
||||
autocomplete_fields = ("author", "tags")
|
||||
summernote_fields = ("content",)
|
||||
readonly_fields = (
|
||||
"uuid",
|
||||
"slug",
|
||||
"modified",
|
||||
"created",
|
||||
)
|
||||
|
||||
fieldsets = (
|
||||
(
|
||||
None,
|
||||
{
|
||||
"fields": (
|
||||
"author",
|
||||
summernote_fields = ("content",)
|
||||
general_fields = [
|
||||
"title",
|
||||
"author",
|
||||
"content",
|
||||
"file",
|
||||
]
|
||||
relation_fields = [
|
||||
"tags",
|
||||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
@admin.register(PostTag)
|
||||
class PostTagAdmin(admin.ModelAdmin):
|
||||
@register(PostTag)
|
||||
class PostTagAdmin(ModelAdmin):
|
||||
list_display = ("tag_name", "name")
|
||||
search_fields = ("tag_name", "name")
|
||||
ordering = ("tag_name",)
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
||||
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-06-21 22:42+0100\n"
|
||||
"POT-Creation-Date: 2025-07-03 18:33+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"
|
||||
|
|
@ -17,55 +17,52 @@ msgstr ""
|
|||
msgid "blog"
|
||||
msgstr "المدونة"
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "post title"
|
||||
msgstr "عنوان المنشور"
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "title"
|
||||
msgstr "العنوان"
|
||||
|
||||
#: blog/models.py:64
|
||||
#: blog/models.py:83
|
||||
msgid "post"
|
||||
msgstr "المنشور"
|
||||
|
||||
#: blog/models.py:65
|
||||
#: blog/models.py:84
|
||||
msgid "posts"
|
||||
msgstr "المنشورات"
|
||||
|
||||
#: blog/models.py:69
|
||||
#: blog/models.py:88
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr ""
|
||||
"ملفات تخفيض السعر غير مدعومة Yer - استخدم محتوى تخفيض السعر بدلاً من ذلك!"
|
||||
|
||||
#: blog/models.py:71
|
||||
#: blog/models.py:90
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr "يجب توفير ملف ترميز أو محتوى ترميز مخفض - متنافيان"
|
||||
|
||||
#: blog/models.py:82
|
||||
#: blog/models.py:122
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "معرّف العلامة الداخلي لعلامة المنشور"
|
||||
|
||||
#: blog/models.py:83
|
||||
#: blog/models.py:123
|
||||
msgid "tag name"
|
||||
msgstr "اسم العلامة"
|
||||
|
||||
#: blog/models.py:87
|
||||
#: blog/models.py:127
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "اسم سهل الاستخدام لعلامة المنشور"
|
||||
|
||||
#: blog/models.py:88
|
||||
#: blog/models.py:128
|
||||
msgid "tag display name"
|
||||
msgstr "اسم عرض العلامة"
|
||||
|
||||
#: blog/models.py:96
|
||||
#: blog/models.py:136
|
||||
msgid "post tag"
|
||||
msgstr "علامة المشاركة"
|
||||
|
||||
#: blog/models.py:97
|
||||
#: blog/models.py:137
|
||||
msgid "post tags"
|
||||
msgstr "علامات المشاركة"
|
||||
|
||||
#~ msgid "eVibes Engine"
|
||||
#~ msgstr "محرك eVibes"
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
||||
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-06-21 22:42+0100\n"
|
||||
"POT-Creation-Date: 2025-07-03 18:33+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"
|
||||
|
|
@ -17,57 +17,54 @@ msgstr ""
|
|||
msgid "blog"
|
||||
msgstr "Blog"
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "post title"
|
||||
msgstr "Název příspěvku"
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "title"
|
||||
msgstr "Název"
|
||||
|
||||
#: blog/models.py:64
|
||||
#: blog/models.py:83
|
||||
msgid "post"
|
||||
msgstr "Příspěvek"
|
||||
|
||||
#: blog/models.py:65
|
||||
#: blog/models.py:84
|
||||
msgid "posts"
|
||||
msgstr "Příspěvky"
|
||||
|
||||
#: blog/models.py:69
|
||||
#: blog/models.py:88
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr ""
|
||||
"Soubory Markdown nejsou podporovány - místo toho použijte obsah Markdown!"
|
||||
|
||||
#: blog/models.py:71
|
||||
#: blog/models.py:90
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"musí být poskytnut soubor markdown nebo obsah markdown - vzájemně se "
|
||||
"vylučují."
|
||||
|
||||
#: blog/models.py:82
|
||||
#: blog/models.py:122
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "interní identifikátor tagu pro tag příspěvku"
|
||||
|
||||
#: blog/models.py:83
|
||||
#: blog/models.py:123
|
||||
msgid "tag name"
|
||||
msgstr "Název štítku"
|
||||
|
||||
#: blog/models.py:87
|
||||
#: blog/models.py:127
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "Uživatelsky přívětivý název pro značku příspěvku"
|
||||
|
||||
#: blog/models.py:88
|
||||
#: blog/models.py:128
|
||||
msgid "tag display name"
|
||||
msgstr "Zobrazení názvu štítku"
|
||||
|
||||
#: blog/models.py:96
|
||||
#: blog/models.py:136
|
||||
msgid "post tag"
|
||||
msgstr "Označení příspěvku"
|
||||
|
||||
#: blog/models.py:97
|
||||
#: blog/models.py:137
|
||||
msgid "post tags"
|
||||
msgstr "Štítky příspěvků"
|
||||
|
||||
#~ msgid "eVibes Engine"
|
||||
#~ msgstr "Motor eVibes"
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
||||
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-06-21 22:42+0100\n"
|
||||
"POT-Creation-Date: 2025-07-03 18:33+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"
|
||||
|
|
@ -17,55 +17,52 @@ msgstr ""
|
|||
msgid "blog"
|
||||
msgstr "Blog"
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "post title"
|
||||
msgstr "Indlæggets titel"
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "title"
|
||||
msgstr "Titel"
|
||||
|
||||
#: blog/models.py:64
|
||||
#: blog/models.py:83
|
||||
msgid "post"
|
||||
msgstr "Indlæg"
|
||||
|
||||
#: blog/models.py:65
|
||||
#: blog/models.py:84
|
||||
msgid "posts"
|
||||
msgstr "Indlæg"
|
||||
|
||||
#: blog/models.py:69
|
||||
#: blog/models.py:88
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr "Markdown-filer understøttes ikke - brug markdown-indhold i stedet!"
|
||||
|
||||
#: blog/models.py:71
|
||||
#: blog/models.py:90
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"en markdown-fil eller markdown-indhold skal leveres - gensidigt udelukkende"
|
||||
|
||||
#: blog/models.py:82
|
||||
#: blog/models.py:122
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "intern tag-identifikator for indlægs-tagget"
|
||||
|
||||
#: blog/models.py:83
|
||||
#: blog/models.py:123
|
||||
msgid "tag name"
|
||||
msgstr "Tag-navn"
|
||||
|
||||
#: blog/models.py:87
|
||||
#: blog/models.py:127
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "Brugervenligt navn til posttagget"
|
||||
|
||||
#: blog/models.py:88
|
||||
#: blog/models.py:128
|
||||
msgid "tag display name"
|
||||
msgstr "Navn på tag-visning"
|
||||
|
||||
#: blog/models.py:96
|
||||
#: blog/models.py:136
|
||||
msgid "post tag"
|
||||
msgstr "Tag til indlæg"
|
||||
|
||||
#: blog/models.py:97
|
||||
#: blog/models.py:137
|
||||
msgid "post tags"
|
||||
msgstr "Tags til indlæg"
|
||||
|
||||
#~ msgid "eVibes Engine"
|
||||
#~ msgstr "eVibes-motor"
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
||||
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-06-21 22:42+0100\n"
|
||||
"POT-Creation-Date: 2025-07-03 18:33+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"
|
||||
|
|
@ -17,58 +17,55 @@ msgstr ""
|
|||
msgid "blog"
|
||||
msgstr "Blog"
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "post title"
|
||||
msgstr "Titel des Beitrags"
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "title"
|
||||
msgstr "Titel"
|
||||
|
||||
#: blog/models.py:64
|
||||
#: blog/models.py:83
|
||||
msgid "post"
|
||||
msgstr "Beitrag"
|
||||
|
||||
#: blog/models.py:65
|
||||
#: blog/models.py:84
|
||||
msgid "posts"
|
||||
msgstr "Beiträge"
|
||||
|
||||
#: blog/models.py:69
|
||||
#: blog/models.py:88
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr ""
|
||||
"Markdown-Dateien werden nicht unterstützt - verwenden Sie stattdessen "
|
||||
"Markdown-Inhalte!"
|
||||
|
||||
#: blog/models.py:71
|
||||
#: blog/models.py:90
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"eine Markdown-Datei oder ein Markdown-Inhalt muss bereitgestellt werden - "
|
||||
"beide schließen sich gegenseitig aus"
|
||||
|
||||
#: blog/models.py:82
|
||||
#: blog/models.py:122
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "interner Tag-Bezeichner für den Post-Tag"
|
||||
|
||||
#: blog/models.py:83
|
||||
#: blog/models.py:123
|
||||
msgid "tag name"
|
||||
msgstr "Tag name"
|
||||
|
||||
#: blog/models.py:87
|
||||
#: blog/models.py:127
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "Benutzerfreundlicher Name für das Post-Tag"
|
||||
|
||||
#: blog/models.py:88
|
||||
#: blog/models.py:128
|
||||
msgid "tag display name"
|
||||
msgstr "Tag-Anzeigename"
|
||||
|
||||
#: blog/models.py:96
|
||||
#: blog/models.py:136
|
||||
msgid "post tag"
|
||||
msgstr "Tag eintragen"
|
||||
|
||||
#: blog/models.py:97
|
||||
#: blog/models.py:137
|
||||
msgid "post tags"
|
||||
msgstr "Tags eintragen"
|
||||
|
||||
#~ msgid "eVibes Engine"
|
||||
#~ msgstr "eVibes Motor"
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -5,9 +5,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
||||
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-06-21 22:42+0100\n"
|
||||
"POT-Creation-Date: 2025-07-03 18:33+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"
|
||||
|
|
@ -21,61 +21,52 @@ msgstr ""
|
|||
msgid "blog"
|
||||
msgstr "Blog"
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "post title"
|
||||
msgstr "Post's title"
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "title"
|
||||
msgstr "Title"
|
||||
|
||||
#: blog/models.py:64
|
||||
#: blog/models.py:83
|
||||
msgid "post"
|
||||
msgstr "Post"
|
||||
|
||||
#: blog/models.py:65
|
||||
#: blog/models.py:84
|
||||
msgid "posts"
|
||||
msgstr "Posts"
|
||||
|
||||
#: blog/models.py:69
|
||||
#: blog/models.py:88
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr "Markdown files are not supported yer - use markdown content instead!"
|
||||
|
||||
#: blog/models.py:71
|
||||
#: blog/models.py:90
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
|
||||
#: blog/models.py:82
|
||||
#: blog/models.py:122
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "internal tag identifier for the post tag"
|
||||
|
||||
#: blog/models.py:83
|
||||
#: blog/models.py:123
|
||||
msgid "tag name"
|
||||
msgstr "Tag name"
|
||||
|
||||
#: blog/models.py:87
|
||||
#: blog/models.py:127
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "User-friendly name for the post tag"
|
||||
|
||||
#: blog/models.py:88
|
||||
#: blog/models.py:128
|
||||
msgid "tag display name"
|
||||
msgstr "Tag display name"
|
||||
|
||||
#: blog/models.py:96
|
||||
#: blog/models.py:136
|
||||
msgid "post tag"
|
||||
msgstr "Post tag"
|
||||
|
||||
#: blog/models.py:97
|
||||
#: blog/models.py:137
|
||||
msgid "post tags"
|
||||
msgstr "Post tags"
|
||||
|
||||
#~ msgid "eVibes Engine"
|
||||
#~ msgstr "eVibes Engine"
|
||||
|
||||
#~ msgid "(no content yet)"
|
||||
#~ msgstr "(no content yet)"
|
||||
|
||||
#~ msgid "rendered HTML"
|
||||
#~ msgstr "Rendered HTML"
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
||||
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-06-21 22:42+0100\n"
|
||||
"POT-Creation-Date: 2025-07-03 18:33+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"
|
||||
|
|
@ -17,55 +17,52 @@ msgstr ""
|
|||
msgid "blog"
|
||||
msgstr "Blog"
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "post title"
|
||||
msgstr "Post's title"
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "title"
|
||||
msgstr "Title"
|
||||
|
||||
#: blog/models.py:64
|
||||
#: blog/models.py:83
|
||||
msgid "post"
|
||||
msgstr "Post"
|
||||
|
||||
#: blog/models.py:65
|
||||
#: blog/models.py:84
|
||||
msgid "posts"
|
||||
msgstr "Posts"
|
||||
|
||||
#: blog/models.py:69
|
||||
#: blog/models.py:88
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr "Markdown files are not supported yer - use markdown content instead!"
|
||||
|
||||
#: blog/models.py:71
|
||||
#: blog/models.py:90
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
|
||||
#: blog/models.py:82
|
||||
#: blog/models.py:122
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "internal tag identifier for the post tag"
|
||||
|
||||
#: blog/models.py:83
|
||||
#: blog/models.py:123
|
||||
msgid "tag name"
|
||||
msgstr "Tag name"
|
||||
|
||||
#: blog/models.py:87
|
||||
#: blog/models.py:127
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "User-friendly name for the post tag"
|
||||
|
||||
#: blog/models.py:88
|
||||
#: blog/models.py:128
|
||||
msgid "tag display name"
|
||||
msgstr "Tag display name"
|
||||
|
||||
#: blog/models.py:96
|
||||
#: blog/models.py:136
|
||||
msgid "post tag"
|
||||
msgstr "Post tag"
|
||||
|
||||
#: blog/models.py:97
|
||||
#: blog/models.py:137
|
||||
msgid "post tags"
|
||||
msgstr "Post tags"
|
||||
|
||||
#~ msgid "eVibes Engine"
|
||||
#~ msgstr "eVibes Engine"
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
||||
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-06-21 22:42+0100\n"
|
||||
"POT-Creation-Date: 2025-07-03 18:33+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"
|
||||
|
|
@ -17,57 +17,54 @@ msgstr ""
|
|||
msgid "blog"
|
||||
msgstr "Blog"
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "post title"
|
||||
msgstr "Título del mensaje"
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "title"
|
||||
msgstr "Título"
|
||||
|
||||
#: blog/models.py:64
|
||||
#: blog/models.py:83
|
||||
msgid "post"
|
||||
msgstr "Publicar en"
|
||||
|
||||
#: blog/models.py:65
|
||||
#: blog/models.py:84
|
||||
msgid "posts"
|
||||
msgstr "Puestos"
|
||||
|
||||
#: blog/models.py:69
|
||||
#: blog/models.py:88
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr ""
|
||||
"No se admiten archivos Markdown - ¡utiliza contenido Markdown en su lugar!"
|
||||
|
||||
#: blog/models.py:71
|
||||
#: blog/models.py:90
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"se debe proporcionar un archivo markdown o contenido markdown - mutuamente "
|
||||
"excluyentes"
|
||||
|
||||
#: blog/models.py:82
|
||||
#: blog/models.py:122
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "identificador interno de la etiqueta post"
|
||||
|
||||
#: blog/models.py:83
|
||||
#: blog/models.py:123
|
||||
msgid "tag name"
|
||||
msgstr "Nombre de la etiqueta"
|
||||
|
||||
#: blog/models.py:87
|
||||
#: blog/models.py:127
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "Nombre fácil de usar para la etiqueta de la entrada"
|
||||
|
||||
#: blog/models.py:88
|
||||
#: blog/models.py:128
|
||||
msgid "tag display name"
|
||||
msgstr "Nombre de la etiqueta"
|
||||
|
||||
#: blog/models.py:96
|
||||
#: blog/models.py:136
|
||||
msgid "post tag"
|
||||
msgstr "Etiqueta postal"
|
||||
|
||||
#: blog/models.py:97
|
||||
#: blog/models.py:137
|
||||
msgid "post tags"
|
||||
msgstr "Etiquetas"
|
||||
|
||||
#~ msgid "eVibes Engine"
|
||||
#~ msgstr "Motor eVibes"
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
||||
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-06-21 22:42+0100\n"
|
||||
"POT-Creation-Date: 2025-07-03 18:33+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"
|
||||
|
|
@ -17,58 +17,55 @@ msgstr ""
|
|||
msgid "blog"
|
||||
msgstr "Blog"
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "post title"
|
||||
msgstr "Titre du message"
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "title"
|
||||
msgstr "Titre"
|
||||
|
||||
#: blog/models.py:64
|
||||
#: blog/models.py:83
|
||||
msgid "post"
|
||||
msgstr "Poste"
|
||||
|
||||
#: blog/models.py:65
|
||||
#: blog/models.py:84
|
||||
msgid "posts"
|
||||
msgstr "Postes"
|
||||
|
||||
#: blog/models.py:69
|
||||
#: blog/models.py:88
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr ""
|
||||
"Les fichiers Markdown ne sont pas pris en charge - utilisez plutôt du "
|
||||
"contenu Markdown !"
|
||||
|
||||
#: blog/models.py:71
|
||||
#: blog/models.py:90
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"un fichier markdown ou un contenu markdown doit être fourni - ils s'excluent "
|
||||
"mutuellement"
|
||||
|
||||
#: blog/models.py:82
|
||||
#: blog/models.py:122
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "identifiant interne de la balise post"
|
||||
|
||||
#: blog/models.py:83
|
||||
#: blog/models.py:123
|
||||
msgid "tag name"
|
||||
msgstr "Nom du jour"
|
||||
|
||||
#: blog/models.py:87
|
||||
#: blog/models.py:127
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "Nom convivial pour la balise post"
|
||||
|
||||
#: blog/models.py:88
|
||||
#: blog/models.py:128
|
||||
msgid "tag display name"
|
||||
msgstr "Nom d'affichage de l'étiquette"
|
||||
|
||||
#: blog/models.py:96
|
||||
#: blog/models.py:136
|
||||
msgid "post tag"
|
||||
msgstr "Tag de poste"
|
||||
|
||||
#: blog/models.py:97
|
||||
#: blog/models.py:137
|
||||
msgid "post tags"
|
||||
msgstr "Tags de la poste"
|
||||
|
||||
#~ msgid "eVibes Engine"
|
||||
#~ msgstr "Moteur eVibes"
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -5,9 +5,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
||||
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-06-21 22:42+0100\n"
|
||||
"POT-Creation-Date: 2025-07-03 18:33+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"
|
||||
|
|
@ -20,51 +20,51 @@ msgstr ""
|
|||
msgid "blog"
|
||||
msgstr ""
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "post title"
|
||||
msgstr ""
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "title"
|
||||
msgstr ""
|
||||
|
||||
#: blog/models.py:64
|
||||
#: blog/models.py:83
|
||||
msgid "post"
|
||||
msgstr ""
|
||||
|
||||
#: blog/models.py:65
|
||||
#: blog/models.py:84
|
||||
msgid "posts"
|
||||
msgstr ""
|
||||
|
||||
#: blog/models.py:69
|
||||
#: blog/models.py:88
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr ""
|
||||
|
||||
#: blog/models.py:71
|
||||
#: blog/models.py:90
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
|
||||
#: blog/models.py:82
|
||||
#: blog/models.py:122
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr ""
|
||||
|
||||
#: blog/models.py:83
|
||||
#: blog/models.py:123
|
||||
msgid "tag name"
|
||||
msgstr ""
|
||||
|
||||
#: blog/models.py:87
|
||||
#: blog/models.py:127
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr ""
|
||||
|
||||
#: blog/models.py:88
|
||||
#: blog/models.py:128
|
||||
msgid "tag display name"
|
||||
msgstr ""
|
||||
|
||||
#: blog/models.py:96
|
||||
#: blog/models.py:136
|
||||
msgid "post tag"
|
||||
msgstr ""
|
||||
|
||||
#: blog/models.py:97
|
||||
#: blog/models.py:137
|
||||
msgid "post tags"
|
||||
msgstr ""
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
||||
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-06-21 22:42+0100\n"
|
||||
"POT-Creation-Date: 2025-07-03 18:33+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"
|
||||
|
|
@ -17,56 +17,53 @@ msgstr ""
|
|||
msgid "blog"
|
||||
msgstr "Blog"
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "post title"
|
||||
msgstr "Titolo del post"
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "title"
|
||||
msgstr "Titolo"
|
||||
|
||||
#: blog/models.py:64
|
||||
#: blog/models.py:83
|
||||
msgid "post"
|
||||
msgstr "Posta"
|
||||
|
||||
#: blog/models.py:65
|
||||
#: blog/models.py:84
|
||||
msgid "posts"
|
||||
msgstr "Messaggi"
|
||||
|
||||
#: blog/models.py:69
|
||||
#: blog/models.py:88
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr "I file Markdown non sono supportati: usa invece i contenuti Markdown!"
|
||||
|
||||
#: blog/models.py:71
|
||||
#: blog/models.py:90
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"deve essere fornito un file markdown o un contenuto markdown - si escludono "
|
||||
"a vicenda"
|
||||
|
||||
#: blog/models.py:82
|
||||
#: blog/models.py:122
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "identificatore interno del tag post"
|
||||
|
||||
#: blog/models.py:83
|
||||
#: blog/models.py:123
|
||||
msgid "tag name"
|
||||
msgstr "Nome del tag"
|
||||
|
||||
#: blog/models.py:87
|
||||
#: blog/models.py:127
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "Nome intuitivo per il tag del post"
|
||||
|
||||
#: blog/models.py:88
|
||||
#: blog/models.py:128
|
||||
msgid "tag display name"
|
||||
msgstr "Nome del tag"
|
||||
|
||||
#: blog/models.py:96
|
||||
#: blog/models.py:136
|
||||
msgid "post tag"
|
||||
msgstr "Post tag"
|
||||
|
||||
#: blog/models.py:97
|
||||
#: blog/models.py:137
|
||||
msgid "post tags"
|
||||
msgstr "Tag dei post"
|
||||
|
||||
#~ msgid "eVibes Engine"
|
||||
#~ msgstr "Motore eVibes"
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
||||
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-06-21 22:42+0100\n"
|
||||
"POT-Creation-Date: 2025-07-03 18:33+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"
|
||||
|
|
@ -17,58 +17,55 @@ msgstr ""
|
|||
msgid "blog"
|
||||
msgstr "ブログ"
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "post title"
|
||||
msgstr "投稿タイトル"
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "title"
|
||||
msgstr "タイトル"
|
||||
|
||||
#: blog/models.py:64
|
||||
#: blog/models.py:83
|
||||
msgid "post"
|
||||
msgstr "ポスト"
|
||||
|
||||
#: blog/models.py:65
|
||||
#: blog/models.py:84
|
||||
msgid "posts"
|
||||
msgstr "投稿"
|
||||
|
||||
#: blog/models.py:69
|
||||
#: blog/models.py:88
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr ""
|
||||
"マークダウン・ファイルはサポートされていません - 代わりにマークダウン・コンテ"
|
||||
"ンツを使用してください!"
|
||||
|
||||
#: blog/models.py:71
|
||||
#: blog/models.py:90
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"マークダウン・ファイルまたはマークダウン・コンテンツを提供しなければならな"
|
||||
"い。"
|
||||
|
||||
#: blog/models.py:82
|
||||
#: blog/models.py:122
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "投稿タグの内部タグ識別子"
|
||||
|
||||
#: blog/models.py:83
|
||||
#: blog/models.py:123
|
||||
msgid "tag name"
|
||||
msgstr "タグ名"
|
||||
|
||||
#: blog/models.py:87
|
||||
#: blog/models.py:127
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "投稿タグのユーザーフレンドリーな名前"
|
||||
|
||||
#: blog/models.py:88
|
||||
#: blog/models.py:128
|
||||
msgid "tag display name"
|
||||
msgstr "タグ表示名"
|
||||
|
||||
#: blog/models.py:96
|
||||
#: blog/models.py:136
|
||||
msgid "post tag"
|
||||
msgstr "投稿タグ"
|
||||
|
||||
#: blog/models.py:97
|
||||
#: blog/models.py:137
|
||||
msgid "post tags"
|
||||
msgstr "投稿タグ"
|
||||
|
||||
#~ msgid "eVibes Engine"
|
||||
#~ msgstr "eVibesエンジン"
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -5,9 +5,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
||||
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-06-21 22:42+0100\n"
|
||||
"POT-Creation-Date: 2025-07-03 18:33+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"
|
||||
|
|
@ -20,51 +20,51 @@ msgstr ""
|
|||
msgid "blog"
|
||||
msgstr ""
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "post title"
|
||||
msgstr ""
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "title"
|
||||
msgstr ""
|
||||
|
||||
#: blog/models.py:64
|
||||
#: blog/models.py:83
|
||||
msgid "post"
|
||||
msgstr ""
|
||||
|
||||
#: blog/models.py:65
|
||||
#: blog/models.py:84
|
||||
msgid "posts"
|
||||
msgstr ""
|
||||
|
||||
#: blog/models.py:69
|
||||
#: blog/models.py:88
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr ""
|
||||
|
||||
#: blog/models.py:71
|
||||
#: blog/models.py:90
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
|
||||
#: blog/models.py:82
|
||||
#: blog/models.py:122
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr ""
|
||||
|
||||
#: blog/models.py:83
|
||||
#: blog/models.py:123
|
||||
msgid "tag name"
|
||||
msgstr ""
|
||||
|
||||
#: blog/models.py:87
|
||||
#: blog/models.py:127
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr ""
|
||||
|
||||
#: blog/models.py:88
|
||||
#: blog/models.py:128
|
||||
msgid "tag display name"
|
||||
msgstr ""
|
||||
|
||||
#: blog/models.py:96
|
||||
#: blog/models.py:136
|
||||
msgid "post tag"
|
||||
msgstr ""
|
||||
|
||||
#: blog/models.py:97
|
||||
#: blog/models.py:137
|
||||
msgid "post tags"
|
||||
msgstr ""
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
||||
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-06-21 22:42+0100\n"
|
||||
"POT-Creation-Date: 2025-07-03 18:33+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"
|
||||
|
|
@ -17,58 +17,55 @@ msgstr ""
|
|||
msgid "blog"
|
||||
msgstr "Blog"
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "post title"
|
||||
msgstr "Titel van de post"
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "title"
|
||||
msgstr "Titel"
|
||||
|
||||
#: blog/models.py:64
|
||||
#: blog/models.py:83
|
||||
msgid "post"
|
||||
msgstr "Plaats"
|
||||
|
||||
#: blog/models.py:65
|
||||
#: blog/models.py:84
|
||||
msgid "posts"
|
||||
msgstr "Berichten"
|
||||
|
||||
#: blog/models.py:69
|
||||
#: blog/models.py:88
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr ""
|
||||
"Markdown-bestanden worden niet ondersteund - gebruik in plaats daarvan "
|
||||
"markdown-inhoud!"
|
||||
|
||||
#: blog/models.py:71
|
||||
#: blog/models.py:90
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"er moet een markdown-bestand of markdown-inhoud worden geleverd - wederzijds "
|
||||
"exclusief"
|
||||
|
||||
#: blog/models.py:82
|
||||
#: blog/models.py:122
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "interne tagidentifier voor de posttag"
|
||||
|
||||
#: blog/models.py:83
|
||||
#: blog/models.py:123
|
||||
msgid "tag name"
|
||||
msgstr "Tag naam"
|
||||
|
||||
#: blog/models.py:87
|
||||
#: blog/models.py:127
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "Gebruiksvriendelijke naam voor de posttag"
|
||||
|
||||
#: blog/models.py:88
|
||||
#: blog/models.py:128
|
||||
msgid "tag display name"
|
||||
msgstr "Tag weergavenaam"
|
||||
|
||||
#: blog/models.py:96
|
||||
#: blog/models.py:136
|
||||
msgid "post tag"
|
||||
msgstr "Post tag"
|
||||
|
||||
#: blog/models.py:97
|
||||
#: blog/models.py:137
|
||||
msgid "post tags"
|
||||
msgstr "Post tags"
|
||||
|
||||
#~ msgid "eVibes Engine"
|
||||
#~ msgstr "eVibes motor"
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
||||
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-06-21 22:42+0100\n"
|
||||
"POT-Creation-Date: 2025-07-03 18:33+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"
|
||||
|
|
@ -17,57 +17,54 @@ msgstr ""
|
|||
msgid "blog"
|
||||
msgstr "Blog"
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "post title"
|
||||
msgstr "Tytuł postu"
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "title"
|
||||
msgstr "Tytuł"
|
||||
|
||||
#: blog/models.py:64
|
||||
#: blog/models.py:83
|
||||
msgid "post"
|
||||
msgstr "Post"
|
||||
|
||||
#: blog/models.py:65
|
||||
#: blog/models.py:84
|
||||
msgid "posts"
|
||||
msgstr "Posty"
|
||||
|
||||
#: blog/models.py:69
|
||||
#: blog/models.py:88
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr ""
|
||||
"Pliki Markdown nie są obsługiwane - zamiast tego użyj zawartości Markdown!"
|
||||
|
||||
#: blog/models.py:71
|
||||
#: blog/models.py:90
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"należy dostarczyć plik markdown lub zawartość markdown - wzajemnie się "
|
||||
"wykluczające"
|
||||
|
||||
#: blog/models.py:82
|
||||
#: blog/models.py:122
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "wewnętrzny identyfikator tagu posta"
|
||||
|
||||
#: blog/models.py:83
|
||||
#: blog/models.py:123
|
||||
msgid "tag name"
|
||||
msgstr "Nazwa tagu"
|
||||
|
||||
#: blog/models.py:87
|
||||
#: blog/models.py:127
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "Przyjazna dla użytkownika nazwa tagu posta"
|
||||
|
||||
#: blog/models.py:88
|
||||
#: blog/models.py:128
|
||||
msgid "tag display name"
|
||||
msgstr "Wyświetlana nazwa znacznika"
|
||||
|
||||
#: blog/models.py:96
|
||||
#: blog/models.py:136
|
||||
msgid "post tag"
|
||||
msgstr "Tag posta"
|
||||
|
||||
#: blog/models.py:97
|
||||
#: blog/models.py:137
|
||||
msgid "post tags"
|
||||
msgstr "Tagi postów"
|
||||
|
||||
#~ msgid "eVibes Engine"
|
||||
#~ msgstr "Silnik eVibes"
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
||||
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-06-21 22:42+0100\n"
|
||||
"POT-Creation-Date: 2025-07-03 18:33+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"
|
||||
|
|
@ -17,56 +17,53 @@ msgstr ""
|
|||
msgid "blog"
|
||||
msgstr "Blog"
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "post title"
|
||||
msgstr "Título da postagem"
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "title"
|
||||
msgstr "Título"
|
||||
|
||||
#: blog/models.py:64
|
||||
#: blog/models.py:83
|
||||
msgid "post"
|
||||
msgstr "Postar"
|
||||
|
||||
#: blog/models.py:65
|
||||
#: blog/models.py:84
|
||||
msgid "posts"
|
||||
msgstr "Publicações"
|
||||
|
||||
#: blog/models.py:69
|
||||
#: blog/models.py:88
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr ""
|
||||
"Os arquivos markdown não são suportados - use conteúdo markdown em vez disso!"
|
||||
|
||||
#: blog/models.py:71
|
||||
#: blog/models.py:90
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"um arquivo ou conteúdo de markdown deve ser fornecido - mutuamente exclusivo"
|
||||
|
||||
#: blog/models.py:82
|
||||
#: blog/models.py:122
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "identificador de tag interno para a tag de postagem"
|
||||
|
||||
#: blog/models.py:83
|
||||
#: blog/models.py:123
|
||||
msgid "tag name"
|
||||
msgstr "Nome da etiqueta"
|
||||
|
||||
#: blog/models.py:87
|
||||
#: blog/models.py:127
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "Nome de fácil utilização para a tag de postagem"
|
||||
|
||||
#: blog/models.py:88
|
||||
#: blog/models.py:128
|
||||
msgid "tag display name"
|
||||
msgstr "Nome de exibição da tag"
|
||||
|
||||
#: blog/models.py:96
|
||||
#: blog/models.py:136
|
||||
msgid "post tag"
|
||||
msgstr "Etiqueta de postagem"
|
||||
|
||||
#: blog/models.py:97
|
||||
#: blog/models.py:137
|
||||
msgid "post tags"
|
||||
msgstr "Tags de postagem"
|
||||
|
||||
#~ msgid "eVibes Engine"
|
||||
#~ msgstr "Motor eVibes"
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
||||
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-06-21 22:42+0100\n"
|
||||
"POT-Creation-Date: 2025-07-03 18:33+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"
|
||||
|
|
@ -17,57 +17,54 @@ msgstr ""
|
|||
msgid "blog"
|
||||
msgstr "Blog"
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "post title"
|
||||
msgstr "Titlul postului"
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "title"
|
||||
msgstr "Titlul"
|
||||
|
||||
#: blog/models.py:64
|
||||
#: blog/models.py:83
|
||||
msgid "post"
|
||||
msgstr "Post"
|
||||
|
||||
#: blog/models.py:65
|
||||
#: blog/models.py:84
|
||||
msgid "posts"
|
||||
msgstr "Mesaje"
|
||||
|
||||
#: blog/models.py:69
|
||||
#: blog/models.py:88
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr ""
|
||||
"Fișierele Markdown nu sunt acceptate - utilizați în schimb conținut Markdown!"
|
||||
|
||||
#: blog/models.py:71
|
||||
#: blog/models.py:90
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"trebuie furnizat un fișier markdown sau conținut markdown - se exclud "
|
||||
"reciproc"
|
||||
|
||||
#: blog/models.py:82
|
||||
#: blog/models.py:122
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "identificator intern de etichetă pentru eticheta postului"
|
||||
|
||||
#: blog/models.py:83
|
||||
#: blog/models.py:123
|
||||
msgid "tag name"
|
||||
msgstr "Nume etichetă"
|
||||
|
||||
#: blog/models.py:87
|
||||
#: blog/models.py:127
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "Nume ușor de utilizat pentru eticheta postului"
|
||||
|
||||
#: blog/models.py:88
|
||||
#: blog/models.py:128
|
||||
msgid "tag display name"
|
||||
msgstr "Nume afișare etichetă"
|
||||
|
||||
#: blog/models.py:96
|
||||
#: blog/models.py:136
|
||||
msgid "post tag"
|
||||
msgstr "Etichetă post"
|
||||
|
||||
#: blog/models.py:97
|
||||
#: blog/models.py:137
|
||||
msgid "post tags"
|
||||
msgstr "Etichete poștale"
|
||||
|
||||
#~ msgid "eVibes Engine"
|
||||
#~ msgstr "Motorul eVibes"
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
||||
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-06-21 22:42+0100\n"
|
||||
"POT-Creation-Date: 2025-07-03 18:33+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"
|
||||
|
|
@ -17,58 +17,55 @@ msgstr ""
|
|||
msgid "blog"
|
||||
msgstr "Блог"
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "post title"
|
||||
msgstr "Заголовок сообщения"
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "title"
|
||||
msgstr "Название"
|
||||
|
||||
#: blog/models.py:64
|
||||
#: blog/models.py:83
|
||||
msgid "post"
|
||||
msgstr "Пост"
|
||||
|
||||
#: blog/models.py:65
|
||||
#: blog/models.py:84
|
||||
msgid "posts"
|
||||
msgstr "Посты"
|
||||
|
||||
#: blog/models.py:69
|
||||
#: blog/models.py:88
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr ""
|
||||
"Файлы в формате Markdown не поддерживаются - используйте вместо них "
|
||||
"содержимое в формате Markdown!"
|
||||
|
||||
#: blog/models.py:71
|
||||
#: blog/models.py:90
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr ""
|
||||
"необходимо предоставить файл разметки или содержимое разметки - "
|
||||
"взаимоисключающие варианты"
|
||||
|
||||
#: blog/models.py:82
|
||||
#: blog/models.py:122
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "внутренний идентификатор тега для тега post"
|
||||
|
||||
#: blog/models.py:83
|
||||
#: blog/models.py:123
|
||||
msgid "tag name"
|
||||
msgstr "Название тега"
|
||||
|
||||
#: blog/models.py:87
|
||||
#: blog/models.py:127
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "Удобное для пользователя название тега поста"
|
||||
|
||||
#: blog/models.py:88
|
||||
#: blog/models.py:128
|
||||
msgid "tag display name"
|
||||
msgstr "Отображаемое имя тега"
|
||||
|
||||
#: blog/models.py:96
|
||||
#: blog/models.py:136
|
||||
msgid "post tag"
|
||||
msgstr "Тэг поста"
|
||||
|
||||
#: blog/models.py:97
|
||||
#: blog/models.py:137
|
||||
msgid "post tags"
|
||||
msgstr "Тэги постов"
|
||||
|
||||
#~ msgid "eVibes Engine"
|
||||
#~ msgstr "Движок eVibes"
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
||||
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-06-21 22:42+0100\n"
|
||||
"POT-Creation-Date: 2025-07-03 18:33+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"
|
||||
|
|
@ -17,54 +17,51 @@ msgstr ""
|
|||
msgid "blog"
|
||||
msgstr "博客"
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "post title"
|
||||
msgstr "帖子标题"
|
||||
|
||||
#: blog/models.py:17
|
||||
#: blog/models.py:36
|
||||
msgid "title"
|
||||
msgstr "标题"
|
||||
|
||||
#: blog/models.py:64
|
||||
#: blog/models.py:83
|
||||
msgid "post"
|
||||
msgstr "职位"
|
||||
|
||||
#: blog/models.py:65
|
||||
#: blog/models.py:84
|
||||
msgid "posts"
|
||||
msgstr "职位"
|
||||
|
||||
#: blog/models.py:69
|
||||
#: blog/models.py:88
|
||||
msgid "markdown files are not supported yet - use markdown content instead"
|
||||
msgstr "不支持 Markdown 文件,请使用 Markdown 内容!"
|
||||
|
||||
#: blog/models.py:71
|
||||
#: blog/models.py:90
|
||||
msgid ""
|
||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||
msgstr "必须提供标记符文件或标记符内容 - 相互排斥"
|
||||
|
||||
#: blog/models.py:82
|
||||
#: blog/models.py:122
|
||||
msgid "internal tag identifier for the post tag"
|
||||
msgstr "职位标签的内部标签标识符"
|
||||
|
||||
#: blog/models.py:83
|
||||
#: blog/models.py:123
|
||||
msgid "tag name"
|
||||
msgstr "标签名称"
|
||||
|
||||
#: blog/models.py:87
|
||||
#: blog/models.py:127
|
||||
msgid "user-friendly name for the post tag"
|
||||
msgstr "方便用户使用的帖子标签名称"
|
||||
|
||||
#: blog/models.py:88
|
||||
#: blog/models.py:128
|
||||
msgid "tag display name"
|
||||
msgstr "标签显示名称"
|
||||
|
||||
#: blog/models.py:96
|
||||
#: blog/models.py:136
|
||||
msgid "post tag"
|
||||
msgstr "职位标签"
|
||||
|
||||
#: blog/models.py:97
|
||||
#: blog/models.py:137
|
||||
msgid "post tags"
|
||||
msgstr "帖子标签"
|
||||
|
||||
#~ msgid "eVibes Engine"
|
||||
#~ msgstr "eVibes 引擎"
|
||||
|
|
|
|||
|
|
@ -18,56 +18,113 @@ class Migration(migrations.Migration):
|
|||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='PostTag',
|
||||
name="PostTag",
|
||||
fields=[
|
||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
|
||||
help_text='unique id is used to surely identify any database object',
|
||||
primary_key=True, serialize=False, verbose_name='unique id')),
|
||||
('is_active', models.BooleanField(default=True,
|
||||
(
|
||||
"uuid",
|
||||
models.UUIDField(
|
||||
default=uuid.uuid4,
|
||||
editable=False,
|
||||
help_text="unique id is used to surely identify any database object",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="unique id",
|
||||
),
|
||||
),
|
||||
(
|
||||
"is_active",
|
||||
models.BooleanField(
|
||||
default=True,
|
||||
help_text="if set to false, this object can't be seen by users without needed permission",
|
||||
verbose_name='is active')),
|
||||
('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True,
|
||||
help_text='when the object first appeared on the database',
|
||||
verbose_name='created')),
|
||||
('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True,
|
||||
help_text='when the object was last modified',
|
||||
verbose_name='modified')),
|
||||
('tag_name', models.CharField(help_text='internal tag identifier for the post tag', max_length=255,
|
||||
verbose_name='tag name')),
|
||||
('name', models.CharField(help_text='user-friendly name for the post tag', max_length=255, unique=True,
|
||||
verbose_name='tag display name')),
|
||||
verbose_name="is active",
|
||||
),
|
||||
),
|
||||
(
|
||||
"created",
|
||||
django_extensions.db.fields.CreationDateTimeField(
|
||||
auto_now_add=True,
|
||||
help_text="when the object first appeared on the database",
|
||||
verbose_name="created",
|
||||
),
|
||||
),
|
||||
(
|
||||
"modified",
|
||||
django_extensions.db.fields.ModificationDateTimeField(
|
||||
auto_now=True, help_text="when the object was last modified", verbose_name="modified"
|
||||
),
|
||||
),
|
||||
(
|
||||
"tag_name",
|
||||
models.CharField(
|
||||
help_text="internal tag identifier for the post tag", max_length=255, verbose_name="tag name"
|
||||
),
|
||||
),
|
||||
(
|
||||
"name",
|
||||
models.CharField(
|
||||
help_text="user-friendly name for the post tag",
|
||||
max_length=255,
|
||||
unique=True,
|
||||
verbose_name="tag display name",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'post tag',
|
||||
'verbose_name_plural': 'post tags',
|
||||
"verbose_name": "post tag",
|
||||
"verbose_name_plural": "post tags",
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Post',
|
||||
name="Post",
|
||||
fields=[
|
||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
|
||||
help_text='unique id is used to surely identify any database object',
|
||||
primary_key=True, serialize=False, verbose_name='unique id')),
|
||||
('is_active', models.BooleanField(default=True,
|
||||
(
|
||||
"uuid",
|
||||
models.UUIDField(
|
||||
default=uuid.uuid4,
|
||||
editable=False,
|
||||
help_text="unique id is used to surely identify any database object",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="unique id",
|
||||
),
|
||||
),
|
||||
(
|
||||
"is_active",
|
||||
models.BooleanField(
|
||||
default=True,
|
||||
help_text="if set to false, this object can't be seen by users without needed permission",
|
||||
verbose_name='is active')),
|
||||
('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True,
|
||||
help_text='when the object first appeared on the database',
|
||||
verbose_name='created')),
|
||||
('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True,
|
||||
help_text='when the object was last modified',
|
||||
verbose_name='modified')),
|
||||
('title', models.CharField()),
|
||||
('content', markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name='content')),
|
||||
('file', models.FileField(blank=True, null=True, upload_to='posts/')),
|
||||
('slug', models.SlugField(allow_unicode=True)),
|
||||
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='posts',
|
||||
to=settings.AUTH_USER_MODEL)),
|
||||
('tags', models.ManyToManyField(to='blog.posttag')),
|
||||
verbose_name="is active",
|
||||
),
|
||||
),
|
||||
(
|
||||
"created",
|
||||
django_extensions.db.fields.CreationDateTimeField(
|
||||
auto_now_add=True,
|
||||
help_text="when the object first appeared on the database",
|
||||
verbose_name="created",
|
||||
),
|
||||
),
|
||||
(
|
||||
"modified",
|
||||
django_extensions.db.fields.ModificationDateTimeField(
|
||||
auto_now=True, help_text="when the object was last modified", verbose_name="modified"
|
||||
),
|
||||
),
|
||||
("title", models.CharField()),
|
||||
("content", markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content")),
|
||||
("file", models.FileField(blank=True, null=True, upload_to="posts/")),
|
||||
("slug", models.SlugField(allow_unicode=True)),
|
||||
(
|
||||
"author",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE, related_name="posts", to=settings.AUTH_USER_MODEL
|
||||
),
|
||||
),
|
||||
("tags", models.ManyToManyField(to="blog.posttag")),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'post',
|
||||
'verbose_name_plural': 'posts',
|
||||
"verbose_name": "post",
|
||||
"verbose_name_plural": "posts",
|
||||
},
|
||||
),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -5,20 +5,21 @@ from django.db import migrations, models
|
|||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('blog', '0001_initial'),
|
||||
("blog", "0001_initial"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='post',
|
||||
name='slug',
|
||||
field=django_extensions.db.fields.AutoSlugField(allow_unicode=True, blank=True, editable=False, populate_from='title', unique=True),
|
||||
model_name="post",
|
||||
name="slug",
|
||||
field=django_extensions.db.fields.AutoSlugField(
|
||||
allow_unicode=True, blank=True, editable=False, populate_from="title", unique=True
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='post',
|
||||
name='title',
|
||||
field=models.CharField(help_text='post title', max_length=128, unique=True, verbose_name='title'),
|
||||
model_name="post",
|
||||
name="title",
|
||||
field=models.CharField(help_text="post title", max_length=128, unique=True, verbose_name="title"),
|
||||
),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -4,15 +4,14 @@ from django.db import migrations, models
|
|||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('blog', '0002_alter_post_slug_alter_post_title'),
|
||||
("blog", "0002_alter_post_slug_alter_post_title"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='post',
|
||||
name='tags',
|
||||
field=models.ManyToManyField(blank=True, related_name='posts', to='blog.posttag'),
|
||||
model_name="post",
|
||||
name="tags",
|
||||
field=models.ManyToManyField(blank=True, related_name="posts", to="blog.posttag"),
|
||||
),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,301 @@
|
|||
# Generated by Django 5.2 on 2025-06-29 13:09
|
||||
|
||||
import markdown_field.fields
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("blog", "0003_alter_post_tags"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="content_ar_ar",
|
||||
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="content_cs_cz",
|
||||
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="content_da_dk",
|
||||
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="content_de_de",
|
||||
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="content_en_gb",
|
||||
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="content_en_us",
|
||||
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="content_es_es",
|
||||
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="content_fr_fr",
|
||||
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="content_hi_in",
|
||||
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="content_it_it",
|
||||
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="content_ja_jp",
|
||||
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="content_kk_kz",
|
||||
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="content_nl_nl",
|
||||
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="content_pl_pl",
|
||||
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="content_pt_br",
|
||||
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="content_ro_ro",
|
||||
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="content_ru_ru",
|
||||
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="content_zh_hans",
|
||||
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="title_ar_ar",
|
||||
field=models.CharField(
|
||||
help_text="post title",
|
||||
max_length=128,
|
||||
null=True,
|
||||
unique=True,
|
||||
verbose_name="title",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="title_cs_cz",
|
||||
field=models.CharField(
|
||||
help_text="post title",
|
||||
max_length=128,
|
||||
null=True,
|
||||
unique=True,
|
||||
verbose_name="title",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="title_da_dk",
|
||||
field=models.CharField(
|
||||
help_text="post title",
|
||||
max_length=128,
|
||||
null=True,
|
||||
unique=True,
|
||||
verbose_name="title",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="title_de_de",
|
||||
field=models.CharField(
|
||||
help_text="post title",
|
||||
max_length=128,
|
||||
null=True,
|
||||
unique=True,
|
||||
verbose_name="title",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="title_en_gb",
|
||||
field=models.CharField(
|
||||
help_text="post title",
|
||||
max_length=128,
|
||||
null=True,
|
||||
unique=True,
|
||||
verbose_name="title",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="title_en_us",
|
||||
field=models.CharField(
|
||||
help_text="post title",
|
||||
max_length=128,
|
||||
null=True,
|
||||
unique=True,
|
||||
verbose_name="title",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="title_es_es",
|
||||
field=models.CharField(
|
||||
help_text="post title",
|
||||
max_length=128,
|
||||
null=True,
|
||||
unique=True,
|
||||
verbose_name="title",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="title_fr_fr",
|
||||
field=models.CharField(
|
||||
help_text="post title",
|
||||
max_length=128,
|
||||
null=True,
|
||||
unique=True,
|
||||
verbose_name="title",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="title_hi_in",
|
||||
field=models.CharField(
|
||||
help_text="post title",
|
||||
max_length=128,
|
||||
null=True,
|
||||
unique=True,
|
||||
verbose_name="title",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="title_it_it",
|
||||
field=models.CharField(
|
||||
help_text="post title",
|
||||
max_length=128,
|
||||
null=True,
|
||||
unique=True,
|
||||
verbose_name="title",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="title_ja_jp",
|
||||
field=models.CharField(
|
||||
help_text="post title",
|
||||
max_length=128,
|
||||
null=True,
|
||||
unique=True,
|
||||
verbose_name="title",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="title_kk_kz",
|
||||
field=models.CharField(
|
||||
help_text="post title",
|
||||
max_length=128,
|
||||
null=True,
|
||||
unique=True,
|
||||
verbose_name="title",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="title_nl_nl",
|
||||
field=models.CharField(
|
||||
help_text="post title",
|
||||
max_length=128,
|
||||
null=True,
|
||||
unique=True,
|
||||
verbose_name="title",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="title_pl_pl",
|
||||
field=models.CharField(
|
||||
help_text="post title",
|
||||
max_length=128,
|
||||
null=True,
|
||||
unique=True,
|
||||
verbose_name="title",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="title_pt_br",
|
||||
field=models.CharField(
|
||||
help_text="post title",
|
||||
max_length=128,
|
||||
null=True,
|
||||
unique=True,
|
||||
verbose_name="title",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="title_ro_ro",
|
||||
field=models.CharField(
|
||||
help_text="post title",
|
||||
max_length=128,
|
||||
null=True,
|
||||
unique=True,
|
||||
verbose_name="title",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="title_ru_ru",
|
||||
field=models.CharField(
|
||||
help_text="post title",
|
||||
max_length=128,
|
||||
null=True,
|
||||
unique=True,
|
||||
verbose_name="title",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="post",
|
||||
name="title_zh_hans",
|
||||
field=models.CharField(
|
||||
help_text="post title",
|
||||
max_length=128,
|
||||
null=True,
|
||||
unique=True,
|
||||
verbose_name="title",
|
||||
),
|
||||
),
|
||||
]
|
||||
|
|
@ -7,13 +7,32 @@ from markdown_field import MarkdownField
|
|||
from core.abstract import NiceModel
|
||||
|
||||
|
||||
class Post(NiceModel):
|
||||
class Post(NiceModel): # type: ignore [django-manager-missing]
|
||||
"""
|
||||
Represents a blog post model extending NiceModel.
|
||||
|
||||
The Post class defines the structure and behavior of a blog post. It includes
|
||||
attributes for author, title, content, optional file attachment, slug,
|
||||
and associated tags. The class enforces constraints such as requiring either
|
||||
content or a file attachment but not both simultaneously. It also supports
|
||||
automatic slug generation based on the title. This model can be used in
|
||||
a blogging platform to manage posts created by users.
|
||||
|
||||
Attributes:
|
||||
is_publicly_visible (bool): Specifies whether the post is visible to the public.
|
||||
author (ForeignKey): A reference to the user who authored the post.
|
||||
title (CharField): The title of the post. Must be unique and non-empty.
|
||||
content (MarkdownField): The content of the post written in Markdown format.
|
||||
file (FileField): An optional file attachment for the post.
|
||||
slug (AutoSlugField): A unique, automatically generated slug based on the title.
|
||||
tags (ManyToManyField): Tags associated with the post for categorization.
|
||||
|
||||
"""
|
||||
|
||||
is_publicly_visible = True
|
||||
|
||||
author: ForeignKey = ForeignKey(
|
||||
to="vibes_auth.User", on_delete=CASCADE, blank=False, null=False, related_name="posts"
|
||||
)
|
||||
title: CharField = CharField(
|
||||
author = ForeignKey(to="vibes_auth.User", on_delete=CASCADE, blank=False, null=False, related_name="posts")
|
||||
title = CharField(
|
||||
unique=True, max_length=128, blank=False, null=False, help_text=_("post title"), verbose_name=_("title")
|
||||
)
|
||||
content: MarkdownField = MarkdownField(
|
||||
|
|
@ -53,9 +72,9 @@ class Post(NiceModel):
|
|||
blank=True,
|
||||
null=True,
|
||||
)
|
||||
file: FileField = FileField(upload_to="posts/", blank=True, null=True)
|
||||
slug: AutoSlugField = AutoSlugField(populate_from="title", allow_unicode=True, unique=True, editable=False)
|
||||
tags: ManyToManyField = ManyToManyField(to="blog.PostTag", blank=True, related_name="posts")
|
||||
file = FileField(upload_to="posts/", blank=True, null=True)
|
||||
slug = AutoSlugField(populate_from="title", allow_unicode=True, unique=True, editable=False)
|
||||
tags = ManyToManyField(to="blog.PostTag", blank=True, related_name="posts")
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.title} | {self.author.first_name} {self.author.last_name}"
|
||||
|
|
@ -73,16 +92,37 @@ class Post(NiceModel):
|
|||
|
||||
|
||||
class PostTag(NiceModel):
|
||||
is_publicly_visible = True
|
||||
"""
|
||||
Represents a tag associated with a post.
|
||||
|
||||
tag_name: CharField = CharField(
|
||||
The PostTag class is used to define and manage tags that can be assigned
|
||||
to posts. These tags include an internal identifier and a user-friendly
|
||||
display name. The class supports internationalization for both the internal
|
||||
identifier and the display name.
|
||||
|
||||
Attributes:
|
||||
is_publicly_visible (bool): Determines if the tag is visible publicly.
|
||||
tag_name (CharField): An internal tag identifier for the post's tag. It is a required
|
||||
field with a maximum length of 255 characters.
|
||||
name (CharField): A user-friendly, unique display name for the post's tag
|
||||
with a maximum length of 255 characters.
|
||||
|
||||
Meta:
|
||||
verbose_name (str): Human-readable singular name of the PostTag model.
|
||||
verbose_name_plural (str): Human-readable plural name of the PostTag model.
|
||||
"""
|
||||
|
||||
is_publicly_visible = True
|
||||
posts: "Post"
|
||||
|
||||
tag_name = CharField(
|
||||
blank=False,
|
||||
null=False,
|
||||
max_length=255,
|
||||
help_text=_("internal tag identifier for the post tag"),
|
||||
verbose_name=_("tag name"),
|
||||
)
|
||||
name: CharField = CharField(
|
||||
name = CharField(
|
||||
max_length=255,
|
||||
help_text=_("user-friendly name for the post tag"),
|
||||
verbose_name=_("tag display name"),
|
||||
|
|
|
|||
9
blog/translation.py
Normal file
9
blog/translation.py
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
from modeltranslation.decorators import register
|
||||
from modeltranslation.translator import TranslationOptions
|
||||
|
||||
from blog.models import Post
|
||||
|
||||
|
||||
@register(Post)
|
||||
class PostOptions(TranslationOptions):
|
||||
fields = ("title", "content")
|
||||
|
|
@ -3,6 +3,8 @@ from rest_framework.routers import DefaultRouter
|
|||
|
||||
from blog.viewsets import PostViewSet
|
||||
|
||||
app_name = "blog"
|
||||
|
||||
payment_router = DefaultRouter()
|
||||
payment_router.register(prefix=r"posts", viewset=PostViewSet, basename="posts")
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logger = logging.getLogger("django")
|
||||
|
|
|
|||
|
|
@ -8,6 +8,22 @@ from core.permissions import EvibesPermission
|
|||
|
||||
|
||||
class PostViewSet(ReadOnlyModelViewSet):
|
||||
"""
|
||||
Encapsulates operations for managing and retrieving Post entities in a read-only model view set.
|
||||
|
||||
This class is tailored to handle Post objects that are active and allows filtration based on defined
|
||||
filters. It integrates with Django's backend filtering system and ensures operations align with the
|
||||
defined permissions. The view set also includes an additional "retrieve" permission configuration.
|
||||
|
||||
Attributes:
|
||||
serializer_class: Specifies the serializer to be used for Post objects.
|
||||
permission_classes: Defines the permissions required to interact with this view set.
|
||||
queryset: Determines the initial queryset, filtered to include only active Post objects.
|
||||
filter_backends: Lists the backends to be used for filtering querysets.
|
||||
filterset_class: Defines the set of filters used for filtering Post objects.
|
||||
additional: Contains additional configuration, such as specific action permissions.
|
||||
"""
|
||||
|
||||
serializer_class = PostSerializer
|
||||
permission_classes = (EvibesPermission,)
|
||||
queryset = Post.objects.filter(is_active=True)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import uuid
|
||||
from datetime import datetime
|
||||
|
||||
from django.db.models import BooleanField, Model, UUIDField
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
|
@ -7,32 +6,24 @@ from django_extensions.db.fields import CreationDateTimeField, ModificationDateT
|
|||
|
||||
|
||||
class NiceModel(Model):
|
||||
id = None
|
||||
uuid: uuid = UUIDField( # type: ignore
|
||||
id: None = None
|
||||
uuid = UUIDField(
|
||||
verbose_name=_("unique id"),
|
||||
help_text=_("unique id is used to surely identify any database object"),
|
||||
primary_key=True,
|
||||
default=uuid.uuid4,
|
||||
editable=False,
|
||||
)
|
||||
is_active: bool = BooleanField( # type: ignore
|
||||
is_active = BooleanField(
|
||||
default=True,
|
||||
verbose_name=_("is active"),
|
||||
help_text=_(
|
||||
"if set to false, this object can't be seen by users without needed permission"
|
||||
),
|
||||
)
|
||||
created: datetime = CreationDateTimeField( # type: ignore
|
||||
_("created"), help_text=_("when the object first appeared on the database")
|
||||
)
|
||||
modified: datetime = ModificationDateTimeField( # type: ignore
|
||||
_("modified"), help_text=_("when the object was last modified")
|
||||
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"))
|
||||
|
||||
def save(self, **kwargs):
|
||||
self.update_modified = kwargs.pop(
|
||||
"update_modified", getattr(self, "update_modified", True)
|
||||
)
|
||||
self.update_modified = kwargs.pop("update_modified", getattr(self, "update_modified", True))
|
||||
super().save(**kwargs)
|
||||
|
||||
class Meta:
|
||||
|
|
|
|||
241
core/admin.py
241
core/admin.py
|
|
@ -1,21 +1,20 @@
|
|||
from contextlib import suppress
|
||||
from typing import ClassVar, Type
|
||||
|
||||
from constance.admin import Config
|
||||
from constance.admin import ConstanceAdmin as BaseConstanceAdmin
|
||||
from django.apps import apps
|
||||
from django.contrib import admin
|
||||
from django.contrib.admin import ModelAdmin, TabularInline
|
||||
from django.contrib.admin import ModelAdmin, TabularInline, action, register, site
|
||||
from django.contrib.gis.admin import GISModelAdmin
|
||||
from django.contrib.messages import constants as messages
|
||||
from django.db.models import Model
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from modeltranslation.translator import NotRegistered, translator
|
||||
from modeltranslation.utils import get_translation_fields
|
||||
from mptt.admin import DraggableMPTTAdmin
|
||||
|
||||
from evibes.settings import CONSTANCE_CONFIG
|
||||
|
||||
from .forms import OrderForm, OrderProductForm, VendorForm
|
||||
from .models import (
|
||||
from core.forms import OrderForm, OrderProductForm, VendorForm
|
||||
from core.models import (
|
||||
Address,
|
||||
Attribute,
|
||||
AttributeGroup,
|
||||
|
|
@ -35,14 +34,21 @@ from .models import (
|
|||
Vendor,
|
||||
Wishlist,
|
||||
)
|
||||
from evibes.settings import CONSTANCE_CONFIG
|
||||
|
||||
|
||||
class FieldsetsMixin:
|
||||
general_fields: list = []
|
||||
relation_fields: list = []
|
||||
model: Model
|
||||
model: ClassVar[Type[Model]]
|
||||
|
||||
def get_fieldsets(self, request, obj=None):
|
||||
if request:
|
||||
pass
|
||||
|
||||
if obj:
|
||||
pass
|
||||
|
||||
fieldsets = []
|
||||
|
||||
def add_translations_fieldset(fss):
|
||||
|
|
@ -52,9 +58,7 @@ class FieldsetsMixin:
|
|||
for orig in transoptions.local_fields:
|
||||
translation_fields += get_translation_fields(orig)
|
||||
if translation_fields:
|
||||
fss = list(fss) + [
|
||||
(_("translations"), {"fields": translation_fields})
|
||||
]
|
||||
fss = list(fss) + [(_("translations"), {"fields": translation_fields})]
|
||||
return fss
|
||||
|
||||
if self.general_fields:
|
||||
|
|
@ -79,34 +83,37 @@ class FieldsetsMixin:
|
|||
return fieldsets
|
||||
|
||||
|
||||
class BasicModelAdmin(ModelAdmin):
|
||||
@admin.action(description=str(_("activate selected %(verbose_name_plural)s")))
|
||||
def activate_selected(self, request, queryset) -> str:
|
||||
if request:
|
||||
pass
|
||||
queryset.update(is_active=True)
|
||||
return str(_("%(verbose_name_plural)s activated successfully!"))
|
||||
|
||||
@admin.action(description=str(_("deactivate selected %(verbose_name_plural)s")))
|
||||
def deactivate_selected(self, request, queryset) -> str:
|
||||
if request:
|
||||
pass
|
||||
queryset.update(is_active=False)
|
||||
return str(_("%(verbose_name_plural)s deactivated successfully."))
|
||||
|
||||
def get_actions(self, request):
|
||||
actions = super().get_actions(request)
|
||||
actions["activate_selected"] = (
|
||||
self.activate_selected,
|
||||
# noinspection PyUnresolvedReferences
|
||||
class ActivationActionsMixin:
|
||||
actions_on_top = True
|
||||
actions_on_bottom = True
|
||||
actions = [
|
||||
"delete_selected",
|
||||
"activate_selected",
|
||||
str(_("activate selected %(verbose_name_plural)s")),
|
||||
)
|
||||
actions["deactivate_selected"] = (
|
||||
self.deactivate_selected,
|
||||
"deactivate_selected",
|
||||
str(_("deactivate selected %(verbose_name_plural)s")),
|
||||
]
|
||||
|
||||
@action(description=_("activate selected %(verbose_name_plural)s").lower(), permissions=["change"])
|
||||
def activate_selected(self, request, queryset):
|
||||
try:
|
||||
queryset.update(is_active=True)
|
||||
self.message_user(
|
||||
request=request, message=_("selected items have been activated.").lower(), level=messages.SUCCESS
|
||||
)
|
||||
return actions
|
||||
|
||||
except Exception as e:
|
||||
self.message_user(request=request, message=str(e), level=messages.ERROR)
|
||||
|
||||
@action(description=_("deactivate selected %(verbose_name_plural)s").lower(), permissions=["change"])
|
||||
def deactivate_selected(self, request, queryset):
|
||||
try:
|
||||
queryset.update(is_active=False)
|
||||
self.message_user(
|
||||
request=request, message=_("selected items have been deactivated.").lower(), level=messages.SUCCESS
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
self.message_user(request=request, message=str(e), level=messages.ERROR)
|
||||
|
||||
|
||||
class AttributeValueInline(TabularInline):
|
||||
|
|
@ -148,12 +155,7 @@ class OrderProductInline(TabularInline):
|
|||
icon = "fa-solid fa-boxes-packing"
|
||||
|
||||
def get_queryset(self, request):
|
||||
return (
|
||||
super()
|
||||
.get_queryset(request)
|
||||
.select_related("product")
|
||||
.only("product__name")
|
||||
)
|
||||
return super().get_queryset(request).select_related("product").only("product__name")
|
||||
|
||||
|
||||
class CategoryChildrenInline(TabularInline):
|
||||
|
|
@ -167,9 +169,10 @@ class CategoryChildrenInline(TabularInline):
|
|||
icon = "fa-solid fa-leaf"
|
||||
|
||||
|
||||
@admin.register(AttributeGroup)
|
||||
class AttributeGroupAdmin(FieldsetsMixin, BasicModelAdmin):
|
||||
model = AttributeGroup # type: ignore
|
||||
@register(AttributeGroup)
|
||||
class AttributeGroupAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||
# noinspection PyClassVar
|
||||
model = AttributeGroup # type: ignore [misc]
|
||||
list_display = ("name", "modified")
|
||||
search_fields = ("uuid", "name")
|
||||
readonly_fields = ("uuid", "modified", "created")
|
||||
|
|
@ -178,9 +181,10 @@ class AttributeGroupAdmin(FieldsetsMixin, BasicModelAdmin):
|
|||
relation_fields = []
|
||||
|
||||
|
||||
@admin.register(Attribute)
|
||||
class AttributeAdmin(FieldsetsMixin, BasicModelAdmin):
|
||||
model = Attribute # type: ignore
|
||||
@register(Attribute)
|
||||
class AttributeAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||
# noinspection PyClassVar
|
||||
model = Attribute # type: ignore [misc]
|
||||
list_display = ("name", "group", "value_type", "modified")
|
||||
list_filter = ("value_type", "group", "is_active")
|
||||
search_fields = ("uuid", "name", "group__name")
|
||||
|
|
@ -191,9 +195,10 @@ class AttributeAdmin(FieldsetsMixin, BasicModelAdmin):
|
|||
relation_fields = ["group", "categories"]
|
||||
|
||||
|
||||
@admin.register(AttributeValue)
|
||||
class AttributeValueAdmin(FieldsetsMixin, BasicModelAdmin):
|
||||
model = AttributeValue # type: ignore
|
||||
@register(AttributeValue)
|
||||
class AttributeValueAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||
# noinspection PyClassVar
|
||||
model = AttributeValue # type: ignore [misc]
|
||||
list_display = ("attribute", "value", "modified")
|
||||
list_filter = ("attribute__group", "is_active")
|
||||
search_fields = ("uuid", "value", "attribute__name")
|
||||
|
|
@ -204,35 +209,39 @@ class AttributeValueAdmin(FieldsetsMixin, BasicModelAdmin):
|
|||
relation_fields = ["attribute", "product"]
|
||||
|
||||
|
||||
@admin.register(Category)
|
||||
class CategoryAdmin(FieldsetsMixin, DraggableMPTTAdmin, BasicModelAdmin):
|
||||
model = Category # type: ignore
|
||||
@register(Category)
|
||||
class CategoryAdmin(FieldsetsMixin, ActivationActionsMixin, DraggableMPTTAdmin):
|
||||
# noinspection PyClassVar
|
||||
model = Category
|
||||
list_display = ("indented_title", "parent", "is_active", "modified")
|
||||
# noinspection PyUnresolvedReferences
|
||||
list_filter = ("is_active", "level", "created", "modified")
|
||||
search_fields = ("uuid", "name")
|
||||
inlines = [CategoryChildrenInline]
|
||||
autocomplete_fields = ["parent", "tags"]
|
||||
readonly_fields = ("slug", "uuid", "modified", "created")
|
||||
|
||||
general_fields = ["is_active", "name", "description", "image", "markup_percent"]
|
||||
general_fields = ["is_active", "name", "description", "image", "markup_percent", "priority"]
|
||||
relation_fields = ["parent", "tags"]
|
||||
|
||||
|
||||
@admin.register(Brand)
|
||||
class BrandAdmin(FieldsetsMixin, BasicModelAdmin):
|
||||
model = Brand # type: ignore
|
||||
@register(Brand)
|
||||
class BrandAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||
# noinspection PyClassVar
|
||||
model = Brand # type: ignore [misc]
|
||||
list_display = ("name",)
|
||||
list_filter = ("categories", "is_active")
|
||||
search_fields = ("uuid", "name", "categories__name")
|
||||
readonly_fields = ("uuid", "modified", "created")
|
||||
readonly_fields = ("uuid", "slug", "modified", "created")
|
||||
|
||||
general_fields = ["is_active", "name", "description"]
|
||||
general_fields = ["is_active", "name", "description", "priority"]
|
||||
relation_fields = ["small_logo", "big_logo", "categories"]
|
||||
|
||||
|
||||
@admin.register(Product)
|
||||
class ProductAdmin(FieldsetsMixin, BasicModelAdmin):
|
||||
model = Product # type: ignore
|
||||
@register(Product)
|
||||
class ProductAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||
# noinspection PyClassVar
|
||||
model = Product # type: ignore [misc]
|
||||
list_display = (
|
||||
"name",
|
||||
"partnumber",
|
||||
|
|
@ -246,8 +255,8 @@ class ProductAdmin(FieldsetsMixin, BasicModelAdmin):
|
|||
list_filter = (
|
||||
"is_active",
|
||||
"is_digital",
|
||||
("tags", admin.RelatedOnlyFieldListFilter),
|
||||
("stocks__vendor", admin.RelatedOnlyFieldListFilter),
|
||||
"stocks__vendor",
|
||||
"tags__name",
|
||||
"created",
|
||||
"modified",
|
||||
)
|
||||
|
|
@ -255,7 +264,9 @@ class ProductAdmin(FieldsetsMixin, BasicModelAdmin):
|
|||
"name",
|
||||
"partnumber",
|
||||
"brand__name",
|
||||
"brand__slug",
|
||||
"category__name",
|
||||
"category__slug",
|
||||
"uuid",
|
||||
"slug",
|
||||
)
|
||||
|
|
@ -263,13 +274,14 @@ class ProductAdmin(FieldsetsMixin, BasicModelAdmin):
|
|||
autocomplete_fields = ("category", "brand", "tags")
|
||||
inlines = [AttributeValueInline, ProductImageInline, StockInline]
|
||||
|
||||
general_fields = ["is_active", "name", "partnumber", "is_active", "is_digital"]
|
||||
general_fields = ["is_active", "name", "partnumber", "is_digital"]
|
||||
relation_fields = ["category", "brand", "tags"]
|
||||
|
||||
|
||||
@admin.register(ProductTag)
|
||||
class ProductTagAdmin(FieldsetsMixin, BasicModelAdmin):
|
||||
model = ProductTag # type: ignore
|
||||
@register(ProductTag)
|
||||
class ProductTagAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||
# noinspection PyClassVar
|
||||
model = ProductTag # type: ignore [misc]
|
||||
list_display = ("tag_name",)
|
||||
search_fields = ("tag_name",)
|
||||
readonly_fields = ("uuid", "modified", "created")
|
||||
|
|
@ -278,9 +290,10 @@ class ProductTagAdmin(FieldsetsMixin, BasicModelAdmin):
|
|||
relation_fields = []
|
||||
|
||||
|
||||
@admin.register(CategoryTag)
|
||||
class CategoryTagAdmin(FieldsetsMixin, BasicModelAdmin):
|
||||
model = CategoryTag # type: ignore
|
||||
@register(CategoryTag)
|
||||
class CategoryTagAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||
# noinspection PyClassVar
|
||||
model = CategoryTag # type: ignore [misc]
|
||||
list_display = ("tag_name",)
|
||||
search_fields = ("tag_name",)
|
||||
readonly_fields = ("uuid", "modified", "created")
|
||||
|
|
@ -289,22 +302,24 @@ class CategoryTagAdmin(FieldsetsMixin, BasicModelAdmin):
|
|||
relation_fields = []
|
||||
|
||||
|
||||
@admin.register(Vendor)
|
||||
class VendorAdmin(FieldsetsMixin, BasicModelAdmin):
|
||||
model = Vendor # type: ignore
|
||||
@register(Vendor)
|
||||
class VendorAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||
# noinspection PyClassVar
|
||||
model = Vendor # type: ignore [misc]
|
||||
list_display = ("name", "markup_percent", "modified")
|
||||
list_filter = ("markup_percent", "is_active")
|
||||
search_fields = ("name",)
|
||||
readonly_fields = ("uuid", "modified", "created")
|
||||
form = VendorForm
|
||||
|
||||
general_fields = ["is_active", "name", "markup_percent", "authentication"]
|
||||
relation_fields = []
|
||||
general_fields = ["is_active", "name", "markup_percent", "authentication", "b2b_auth_token"]
|
||||
relation_fields = ["users"]
|
||||
|
||||
|
||||
@admin.register(Feedback)
|
||||
class FeedbackAdmin(FieldsetsMixin, BasicModelAdmin):
|
||||
model = Feedback # type: ignore
|
||||
@register(Feedback)
|
||||
class FeedbackAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||
# noinspection PyClassVar
|
||||
model = Feedback # type: ignore [misc]
|
||||
list_display = ("order_product", "rating", "comment", "modified")
|
||||
list_filter = ("rating", "is_active")
|
||||
search_fields = ("order_product__product__name", "comment")
|
||||
|
|
@ -314,9 +329,10 @@ class FeedbackAdmin(FieldsetsMixin, BasicModelAdmin):
|
|||
relation_fields = ["order_product"]
|
||||
|
||||
|
||||
@admin.register(Order)
|
||||
class OrderAdmin(FieldsetsMixin, BasicModelAdmin):
|
||||
model = Order # type: ignore
|
||||
@register(Order)
|
||||
class OrderAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||
# noinspection PyClassVar
|
||||
model = Order # type: ignore [misc]
|
||||
list_display = (
|
||||
"human_readable_id",
|
||||
"user",
|
||||
|
|
@ -338,13 +354,14 @@ class OrderAdmin(FieldsetsMixin, BasicModelAdmin):
|
|||
inlines = [OrderProductInline]
|
||||
form = OrderForm
|
||||
|
||||
general_fields = ["is_active", "user", "status"]
|
||||
general_fields = ["is_active", "user", "status", "notifications", "attributes", "buy_time"]
|
||||
relation_fields = ["promo_code", "billing_address", "shipping_address"]
|
||||
|
||||
|
||||
@admin.register(OrderProduct)
|
||||
class OrderProductAdmin(FieldsetsMixin, BasicModelAdmin):
|
||||
model = OrderProduct # type: ignore
|
||||
@register(OrderProduct)
|
||||
class OrderProductAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||
# noinspection PyClassVar
|
||||
model = OrderProduct # type: ignore [misc]
|
||||
list_display = ("order", "product", "quantity", "buy_price", "status", "modified")
|
||||
list_filter = ("status",)
|
||||
search_fields = ("order__user__email", "product__name")
|
||||
|
|
@ -355,9 +372,10 @@ class OrderProductAdmin(FieldsetsMixin, BasicModelAdmin):
|
|||
relation_fields = ["order", "product"]
|
||||
|
||||
|
||||
@admin.register(PromoCode)
|
||||
class PromoCodeAdmin(FieldsetsMixin, BasicModelAdmin):
|
||||
model = PromoCode # type: ignore
|
||||
@register(PromoCode)
|
||||
class PromoCodeAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||
# noinspection PyClassVar
|
||||
model = PromoCode # type: ignore [misc]
|
||||
list_display = (
|
||||
"code",
|
||||
"discount_percent",
|
||||
|
|
@ -383,9 +401,10 @@ class PromoCodeAdmin(FieldsetsMixin, BasicModelAdmin):
|
|||
relation_fields = ["user"]
|
||||
|
||||
|
||||
@admin.register(Promotion)
|
||||
class PromotionAdmin(FieldsetsMixin, BasicModelAdmin):
|
||||
model = Promotion # type: ignore
|
||||
@register(Promotion)
|
||||
class PromotionAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||
# noinspection PyClassVar
|
||||
model = Promotion # type: ignore [misc]
|
||||
list_display = ("name", "discount_percent", "modified")
|
||||
search_fields = ("name",)
|
||||
readonly_fields = ("uuid", "modified", "created")
|
||||
|
|
@ -395,9 +414,10 @@ class PromotionAdmin(FieldsetsMixin, BasicModelAdmin):
|
|||
relation_fields = ["products"]
|
||||
|
||||
|
||||
@admin.register(Stock)
|
||||
class StockAdmin(FieldsetsMixin, BasicModelAdmin):
|
||||
model = Stock # type: ignore
|
||||
@register(Stock)
|
||||
class StockAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||
# noinspection PyClassVar
|
||||
model = Stock # type: ignore [misc]
|
||||
list_display = ("product", "vendor", "sku", "quantity", "price", "modified")
|
||||
list_filter = ("vendor", "quantity")
|
||||
search_fields = ("product__name", "vendor__name", "sku")
|
||||
|
|
@ -415,9 +435,10 @@ class StockAdmin(FieldsetsMixin, BasicModelAdmin):
|
|||
relation_fields = ["product", "vendor"]
|
||||
|
||||
|
||||
@admin.register(Wishlist)
|
||||
class WishlistAdmin(FieldsetsMixin, BasicModelAdmin):
|
||||
model = Wishlist # type: ignore
|
||||
@register(Wishlist)
|
||||
class WishlistAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||
# noinspection PyClassVar
|
||||
model = Wishlist # type: ignore [misc]
|
||||
list_display = ("user", "modified")
|
||||
search_fields = ("user__email",)
|
||||
readonly_fields = ("uuid", "modified", "created")
|
||||
|
|
@ -426,9 +447,10 @@ class WishlistAdmin(FieldsetsMixin, BasicModelAdmin):
|
|||
relation_fields = ["products"]
|
||||
|
||||
|
||||
@admin.register(ProductImage)
|
||||
class ProductImageAdmin(FieldsetsMixin, BasicModelAdmin):
|
||||
model = ProductImage # type: ignore
|
||||
@register(ProductImage)
|
||||
class ProductImageAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||
# noinspection PyClassVar
|
||||
model = ProductImage # type: ignore [misc]
|
||||
list_display = ("alt", "product", "priority", "modified")
|
||||
list_filter = ("priority",)
|
||||
search_fields = ("alt", "product__name")
|
||||
|
|
@ -439,9 +461,10 @@ class ProductImageAdmin(FieldsetsMixin, BasicModelAdmin):
|
|||
relation_fields = ["product"]
|
||||
|
||||
|
||||
@admin.register(Address)
|
||||
@register(Address)
|
||||
class AddressAdmin(FieldsetsMixin, GISModelAdmin):
|
||||
model = Address # type: ignore
|
||||
# noinspection PyClassVar
|
||||
model = Address # type: ignore [misc]
|
||||
list_display = ("street", "city", "region", "country", "user")
|
||||
list_filter = ("country", "region")
|
||||
search_fields = ("street", "city", "postal_code", "user__email")
|
||||
|
|
@ -501,8 +524,10 @@ class ConstanceConfig:
|
|||
_meta = Meta()
|
||||
|
||||
|
||||
admin.site.unregister([Config]) # type: ignore
|
||||
admin.site.register([ConstanceConfig], BaseConstanceAdmin) # type: ignore
|
||||
admin.site.site_title = CONSTANCE_CONFIG["PROJECT_NAME"][0] # type: ignore
|
||||
admin.site.site_header = "eVibes"
|
||||
admin.site.index_title = CONSTANCE_CONFIG["PROJECT_NAME"][0] # type: ignore
|
||||
# noinspection PyTypeChecker
|
||||
site.unregister([Config])
|
||||
# noinspection PyTypeChecker
|
||||
site.register([ConstanceConfig], BaseConstanceAdmin) # type: ignore [list-item]
|
||||
site.site_title = CONSTANCE_CONFIG["PROJECT_NAME"][0] # type: ignore [assignment]
|
||||
site.site_header = "eVibes"
|
||||
site.index_title = CONSTANCE_CONFIG["PROJECT_NAME"][0] # type: ignore [assignment]
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ from core.viewsets import (
|
|||
WishlistViewSet,
|
||||
)
|
||||
|
||||
app_name = "core"
|
||||
|
||||
core_router = DefaultRouter()
|
||||
core_router.register(r"products", ProductViewSet, basename="products")
|
||||
core_router.register(r"orders", OrderViewSet, basename="orders")
|
||||
|
|
@ -55,10 +57,26 @@ sitemaps = {
|
|||
urlpatterns = [
|
||||
path("core/", include(core_router.urls)),
|
||||
path(
|
||||
"sitemap.xml", sitemap_index, {"sitemaps": sitemaps, "sitemap_url_name": "sitemap-detail"}, name="sitemap-index"
|
||||
"sitemap.xml",
|
||||
sitemap_index,
|
||||
{
|
||||
"sitemaps": sitemaps,
|
||||
"sitemap_url_name": "core:sitemap-detail",
|
||||
},
|
||||
name="sitemap-index",
|
||||
),
|
||||
path(
|
||||
"sitemap-<section>.xml",
|
||||
sitemap_detail,
|
||||
{"sitemaps": sitemaps},
|
||||
name="sitemap-detail",
|
||||
),
|
||||
path(
|
||||
"sitemap-<section>-<int:page>.xml",
|
||||
sitemap_detail,
|
||||
{"sitemaps": sitemaps},
|
||||
name="sitemap-detail",
|
||||
),
|
||||
path("sitemap-<section>.xml", sitemap_detail, {"sitemaps": sitemaps}, name="sitemap-detail"),
|
||||
path("sitemap-<section>-<int:page>.xml", sitemap_detail, {"sitemaps": sitemaps}, name="sitemap-detail"),
|
||||
path("download/<str:order_product_uuid>/", download_digital_asset_view, name="download_digital_asset"),
|
||||
path("search/", GlobalSearchView.as_view(), name="global_search"),
|
||||
path("app/cache/", CacheOperatorView.as_view(), name="cache_operator"),
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ from core.views import (
|
|||
GlobalSearchView,
|
||||
)
|
||||
|
||||
app_name = "core"
|
||||
|
||||
urlpatterns = [
|
||||
path("search/", GlobalSearchView.as_view(), name="global_search"),
|
||||
path("orders/buy_as_business/", BuyAsBusinessView.as_view(), name="request_cursed_url"),
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ from core.serializers import (
|
|||
WishlistDetailSerializer,
|
||||
WishlistSimpleSerializer,
|
||||
)
|
||||
from core.serializers.seo import SeoSnapshotSerializer
|
||||
from core.serializers.utility import AddressCreateSerializer, AddressSuggestionSerializer, DoFeedbackSerializer
|
||||
from payments.serializers import TransactionProcessSerializer
|
||||
|
||||
|
|
@ -122,28 +123,50 @@ ATTRIBUTE_VALUE_SCHEMA = {
|
|||
CATEGORY_SCHEMA = {
|
||||
"list": extend_schema(
|
||||
summary=_("list all categories (simple view)"),
|
||||
description=_("list all categories (simple view)"),
|
||||
responses={status.HTTP_200_OK: CategorySimpleSerializer(many=True), **BASE_ERRORS},
|
||||
),
|
||||
"retrieve": extend_schema(
|
||||
summary=_("retrieve a single category (detailed view)"),
|
||||
description=_("retrieve a single category (detailed view)"),
|
||||
responses={status.HTTP_200_OK: CategoryDetailSerializer(), **BASE_ERRORS},
|
||||
),
|
||||
"create": extend_schema(
|
||||
summary=_("create a category"),
|
||||
description=_("create a category"),
|
||||
responses={status.HTTP_201_CREATED: CategoryDetailSerializer(), **BASE_ERRORS},
|
||||
),
|
||||
"destroy": extend_schema(
|
||||
summary=_("delete a category"),
|
||||
description=_("delete a category"),
|
||||
responses={status.HTTP_204_NO_CONTENT: {}, **BASE_ERRORS},
|
||||
),
|
||||
"update": extend_schema(
|
||||
summary=_("rewrite an existing category saving non-editables"),
|
||||
description=_("rewrite an existing category saving non-editables"),
|
||||
responses={status.HTTP_200_OK: CategoryDetailSerializer(), **BASE_ERRORS},
|
||||
),
|
||||
"partial_update": extend_schema(
|
||||
summary=_("rewrite some fields of an existing category saving non-editables"),
|
||||
description=_("rewrite some fields of an existing category saving non-editables"),
|
||||
responses={status.HTTP_200_OK: CategoryDetailSerializer(), **BASE_ERRORS},
|
||||
),
|
||||
"seo": extend_schema(
|
||||
summary=_("SEO Meta Snapshot"),
|
||||
description=_("returns a snapshot of the category's SEO meta data"),
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="lookup",
|
||||
location="path",
|
||||
description=_("Category UUID or slug"),
|
||||
type=str,
|
||||
),
|
||||
],
|
||||
responses={
|
||||
status.HTTP_200_OK: SeoSnapshotSerializer(),
|
||||
**BASE_ERRORS,
|
||||
},
|
||||
),
|
||||
}
|
||||
|
||||
ORDER_SCHEMA = {
|
||||
|
|
@ -347,6 +370,7 @@ ATTRIBUTES_DESC = _(
|
|||
PRODUCT_SCHEMA = {
|
||||
"list": extend_schema(
|
||||
summary=_("list all products (simple view)"),
|
||||
description=_("list all products (simple view)"),
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="uuid",
|
||||
|
|
@ -439,6 +463,7 @@ PRODUCT_SCHEMA = {
|
|||
),
|
||||
"retrieve": extend_schema(
|
||||
summary=_("retrieve a single product (detailed view)"),
|
||||
description=_("retrieve a single product (detailed view)"),
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="lookup_value",
|
||||
|
|
@ -454,6 +479,7 @@ PRODUCT_SCHEMA = {
|
|||
),
|
||||
"create": extend_schema(
|
||||
summary=_("create a product"),
|
||||
description=_("create a product"),
|
||||
responses={
|
||||
status.HTTP_201_CREATED: ProductDetailSerializer(),
|
||||
**BASE_ERRORS,
|
||||
|
|
@ -461,6 +487,7 @@ PRODUCT_SCHEMA = {
|
|||
),
|
||||
"update": extend_schema(
|
||||
summary=_("rewrite an existing product, preserving non-editable fields"),
|
||||
description=_("rewrite an existing product, preserving non-editable fields"),
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="lookup",
|
||||
|
|
@ -476,6 +503,7 @@ PRODUCT_SCHEMA = {
|
|||
),
|
||||
"partial_update": extend_schema(
|
||||
summary=_("update some fields of an existing product, preserving non-editable fields"),
|
||||
description=_("update some fields of an existing product, preserving non-editable fields"),
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="lookup",
|
||||
|
|
@ -491,6 +519,7 @@ PRODUCT_SCHEMA = {
|
|||
),
|
||||
"destroy": extend_schema(
|
||||
summary=_("delete a product"),
|
||||
description=_("delete a product"),
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="lookup",
|
||||
|
|
@ -506,6 +535,7 @@ PRODUCT_SCHEMA = {
|
|||
),
|
||||
"feedbacks": extend_schema(
|
||||
summary=_("lists all permitted feedbacks for a product"),
|
||||
description=_("lists all permitted feedbacks for a product"),
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="lookup",
|
||||
|
|
@ -519,6 +549,22 @@ PRODUCT_SCHEMA = {
|
|||
**BASE_ERRORS,
|
||||
},
|
||||
),
|
||||
"seo": extend_schema(
|
||||
summary=_("SEO Meta Snapshot"),
|
||||
description=_("returns a snapshot of the product's SEO meta data"),
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="lookup",
|
||||
location="path",
|
||||
description=_("Product UUID or slug"),
|
||||
type=str,
|
||||
),
|
||||
],
|
||||
responses={
|
||||
status.HTTP_200_OK: SeoSnapshotSerializer(),
|
||||
**BASE_ERRORS,
|
||||
},
|
||||
),
|
||||
}
|
||||
|
||||
ADDRESS_SCHEMA = {
|
||||
|
|
|
|||
|
|
@ -15,19 +15,15 @@ SMART_FIELDS = [
|
|||
"name^6",
|
||||
"name.ngram^5",
|
||||
"name.phonetic",
|
||||
|
||||
"title^4",
|
||||
"title.ngram^3",
|
||||
"title.phonetic",
|
||||
|
||||
"description^2",
|
||||
"description.ngram",
|
||||
"description.phonetic",
|
||||
|
||||
"brand__name^3",
|
||||
"brand__name.ngram",
|
||||
"brand__name.auto",
|
||||
|
||||
"category__name^2",
|
||||
"category__name.ngram",
|
||||
"category__name.auto",
|
||||
|
|
@ -71,7 +67,6 @@ functions = [
|
|||
"missing": 0,
|
||||
},
|
||||
},
|
||||
|
||||
# category-level boost when searching for categories
|
||||
{
|
||||
"filter": Q("term", **{"_index": "categories"}),
|
||||
|
|
@ -82,7 +77,6 @@ functions = [
|
|||
"missing": 0,
|
||||
},
|
||||
},
|
||||
|
||||
# brand-level boost when searching for brands
|
||||
{
|
||||
"filter": Q("term", **{"_index": "brands"}),
|
||||
|
|
@ -191,8 +185,8 @@ def process_query(query: str = "", request: Request | None = None) -> dict[str,
|
|||
results[idx].append(hit_result)
|
||||
|
||||
return results
|
||||
except NotFoundError:
|
||||
raise Http404
|
||||
except NotFoundError as nfe:
|
||||
raise Http404 from nfe
|
||||
|
||||
|
||||
LANGUAGE_ANALYZER_MAP = {
|
||||
|
|
|
|||
|
|
@ -12,13 +12,9 @@ class _BaseDoc(ActiveOnlyMixin, Document):
|
|||
analyzer="standard",
|
||||
fields={
|
||||
"raw": fields.KeywordField(ignore_above=256),
|
||||
"ngram": fields.TextField(
|
||||
analyzer="name_ngram", search_analyzer="query_lc"
|
||||
),
|
||||
"ngram": fields.TextField(analyzer="name_ngram", search_analyzer="query_lc"),
|
||||
"phonetic": fields.TextField(analyzer="name_phonetic"),
|
||||
"auto": fields.TextField(
|
||||
analyzer="autocomplete", search_analyzer="autocomplete_search"
|
||||
),
|
||||
"auto": fields.TextField(analyzer="autocomplete", search_analyzer="autocomplete_search"),
|
||||
},
|
||||
)
|
||||
description = fields.TextField(
|
||||
|
|
@ -26,13 +22,9 @@ class _BaseDoc(ActiveOnlyMixin, Document):
|
|||
analyzer="standard",
|
||||
fields={
|
||||
"raw": fields.KeywordField(ignore_above=256),
|
||||
"ngram": fields.TextField(
|
||||
analyzer="name_ngram", search_analyzer="query_lc"
|
||||
),
|
||||
"ngram": fields.TextField(analyzer="name_ngram", search_analyzer="query_lc"),
|
||||
"phonetic": fields.TextField(analyzer="name_phonetic"),
|
||||
"auto": fields.TextField(
|
||||
analyzer="autocomplete", search_analyzer="autocomplete_search"
|
||||
),
|
||||
"auto": fields.TextField(analyzer="autocomplete", search_analyzer="autocomplete_search"),
|
||||
},
|
||||
)
|
||||
slug = fields.KeywordField(attr="slug", index=False)
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ from django_filters import (
|
|||
from core.elasticsearch import process_query
|
||||
from core.models import Address, Brand, Category, Feedback, Order, Product, Wishlist
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logger = logging.getLogger("django")
|
||||
|
||||
|
||||
class CaseInsensitiveListFilter(BaseInFilter, CharFilter):
|
||||
|
|
@ -363,6 +363,7 @@ class CategoryFilter(FilterSet):
|
|||
|
||||
order_by = OrderingFilter(
|
||||
fields=(
|
||||
("priority", "priority"),
|
||||
("uuid", "uuid"),
|
||||
("name", "name"),
|
||||
("?", "random"),
|
||||
|
|
@ -430,6 +431,7 @@ class BrandFilter(FilterSet):
|
|||
|
||||
order_by = OrderingFilter(
|
||||
fields=(
|
||||
("priority", "priority"),
|
||||
("uuid", "uuid"),
|
||||
("name", "name"),
|
||||
("?", "random"),
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
from graphene import Mutation
|
||||
|
||||
|
||||
class BaseMutation(Mutation):
|
||||
def __init__(self, *args, **kwargs):
|
||||
class BaseMutation(Mutation): # type: ignore [misc]
|
||||
def __init__(self, *args, **kwargs) -> None:
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def mutate(**kwargs):
|
||||
def mutate(**kwargs) -> None:
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -13,13 +13,14 @@ from core.elasticsearch import process_query
|
|||
from core.graphene import BaseMutation
|
||||
from core.graphene.object_types import (
|
||||
AddressType,
|
||||
BulkActionOrderProductInput,
|
||||
BulkProductInput,
|
||||
OrderType,
|
||||
ProductType,
|
||||
SearchResultsType,
|
||||
WishlistType,
|
||||
FeedbackType,
|
||||
)
|
||||
from core.models import Address, Category, Order, Product, Wishlist
|
||||
from core.models import Address, Category, Order, Product, Wishlist, OrderProduct
|
||||
from core.utils import format_attributes, is_url_safe
|
||||
from core.utils.caching import web_cache
|
||||
from core.utils.emailing import contact_us_email
|
||||
|
|
@ -27,7 +28,7 @@ from core.utils.messages import permission_denied_message
|
|||
from core.utils.nominatim import fetch_address_suggestions
|
||||
from payments.graphene.object_types import TransactionType
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logger = logging.getLogger("django")
|
||||
|
||||
|
||||
class CacheOperator(BaseMutation):
|
||||
|
|
@ -96,8 +97,8 @@ class AddOrderProduct(BaseMutation):
|
|||
order = order.add_product(product_uuid=product_uuid, attributes=format_attributes(attributes))
|
||||
|
||||
return AddOrderProduct(order=order)
|
||||
except Order.DoesNotExist:
|
||||
raise Http404(_(f"order {order_uuid} not found"))
|
||||
except Order.DoesNotExist as dne:
|
||||
raise Http404(_(f"order {order_uuid} not found")) from dne
|
||||
|
||||
|
||||
class RemoveOrderProduct(BaseMutation):
|
||||
|
|
@ -122,8 +123,8 @@ class RemoveOrderProduct(BaseMutation):
|
|||
order = order.remove_product(product_uuid=product_uuid, attributes=format_attributes(attributes))
|
||||
|
||||
return AddOrderProduct(order=order)
|
||||
except Order.DoesNotExist:
|
||||
raise Http404(_(f"order {order_uuid} not found"))
|
||||
except Order.DoesNotExist as dne:
|
||||
raise Http404(_(f"order {order_uuid} not found")) from dne
|
||||
|
||||
|
||||
class RemoveAllOrderProducts(BaseMutation):
|
||||
|
|
@ -174,13 +175,14 @@ class BuyOrder(BaseMutation):
|
|||
description = _("buy an order")
|
||||
|
||||
class Arguments:
|
||||
order_uuid = UUID(required=False)
|
||||
order_uuid = String(required=False)
|
||||
order_hr_id = String(required=False)
|
||||
force_balance = Boolean(required=False)
|
||||
force_payment = Boolean(required=False)
|
||||
promocode_uuid = UUID(required=False)
|
||||
shipping_address = UUID(required=False)
|
||||
billing_address = UUID(required=False)
|
||||
promocode_uuid = String(required=False)
|
||||
shipping_address = String(required=False)
|
||||
billing_address = String(required=False)
|
||||
chosen_products = List(BulkProductInput, required=False)
|
||||
|
||||
order = Field(OrderType, required=False)
|
||||
transaction = Field(TransactionType, required=False)
|
||||
|
|
@ -196,6 +198,7 @@ class BuyOrder(BaseMutation):
|
|||
promocode_uuid=None,
|
||||
shipping_address=None,
|
||||
billing_address=None,
|
||||
chosen_products=None,
|
||||
):
|
||||
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"))
|
||||
|
|
@ -214,6 +217,7 @@ class BuyOrder(BaseMutation):
|
|||
promocode_uuid=promocode_uuid,
|
||||
shipping_address=shipping_address,
|
||||
billing_address=billing_address,
|
||||
chosen_products=chosen_products,
|
||||
)
|
||||
|
||||
match str(type(instance)):
|
||||
|
|
@ -224,8 +228,8 @@ class BuyOrder(BaseMutation):
|
|||
case _:
|
||||
raise TypeError(_(f"wrong type came from order.buy() method: {type(instance)!s}"))
|
||||
|
||||
except Order.DoesNotExist:
|
||||
raise Http404(_(f"order {order_uuid} not found"))
|
||||
except Order.DoesNotExist as dne:
|
||||
raise Http404(_(f"order {order_uuid} not found")) from dne
|
||||
|
||||
|
||||
class BulkOrderAction(BaseMutation):
|
||||
|
|
@ -236,7 +240,7 @@ class BulkOrderAction(BaseMutation):
|
|||
order_uuid = UUID(required=False)
|
||||
order_hr_id = String(required=False)
|
||||
action = String(required=True, description=_("remove/add"))
|
||||
products = List(BulkActionOrderProductInput, required=True)
|
||||
products = List(BulkProductInput, required=True)
|
||||
|
||||
order = Field(OrderType, required=False)
|
||||
|
||||
|
|
@ -271,8 +275,48 @@ class BulkOrderAction(BaseMutation):
|
|||
|
||||
return BulkOrderAction(order=order)
|
||||
|
||||
except Order.DoesNotExist:
|
||||
raise Http404(_(f"order {order_uuid} not found"))
|
||||
except Order.DoesNotExist as dne:
|
||||
raise Http404(_(f"order {order_uuid} not found")) from dne
|
||||
|
||||
|
||||
class BulkWishlistAction(BaseMutation):
|
||||
class Meta:
|
||||
description = _("perform an action on a list of products in the wishlist")
|
||||
|
||||
class Arguments:
|
||||
wishlist_uuid = UUID(required=False)
|
||||
action = String(required=True, description="remove/add")
|
||||
products = List(BulkProductInput, required=True)
|
||||
|
||||
wishlist = Field(WishlistType, required=False)
|
||||
|
||||
@staticmethod
|
||||
def mutate(
|
||||
_parent,
|
||||
info,
|
||||
action,
|
||||
products,
|
||||
wishlist_uuid=None,
|
||||
):
|
||||
if not wishlist_uuid:
|
||||
raise BadRequest(_("please provide wishlist_uuid value"))
|
||||
user = info.context.user
|
||||
try:
|
||||
wishlist = Wishlist.objects.get(user=user, uuid=wishlist_uuid)
|
||||
|
||||
# noinspection PyUnreachableCode
|
||||
match action:
|
||||
case "add":
|
||||
wishlist = wishlist.bulk_add_products(products)
|
||||
case "remove":
|
||||
wishlist = wishlist.bulk_remove_products(products)
|
||||
case _:
|
||||
raise BadRequest(_("action must be either add or remove"))
|
||||
|
||||
return BulkWishlistAction(wishlist=wishlist)
|
||||
|
||||
except Wishlist.DoesNotExist as dne:
|
||||
raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
|
||||
|
||||
|
||||
class BuyUnregisteredOrder(BaseMutation):
|
||||
|
|
@ -344,8 +388,8 @@ class AddWishlistProduct(BaseMutation):
|
|||
|
||||
return AddWishlistProduct(wishlist=wishlist)
|
||||
|
||||
except Wishlist.DoesNotExist:
|
||||
raise Http404(_(f"wishlist {wishlist_uuid} not found"))
|
||||
except Wishlist.DoesNotExist as dne:
|
||||
raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
|
||||
|
||||
|
||||
class RemoveWishlistProduct(BaseMutation):
|
||||
|
|
@ -371,8 +415,8 @@ class RemoveWishlistProduct(BaseMutation):
|
|||
|
||||
return RemoveWishlistProduct(wishlist=wishlist)
|
||||
|
||||
except Wishlist.DoesNotExist:
|
||||
raise Http404(_(f"wishlist {wishlist_uuid} not found"))
|
||||
except Wishlist.DoesNotExist as dne:
|
||||
raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
|
||||
|
||||
|
||||
class RemoveAllWishlistProducts(BaseMutation):
|
||||
|
|
@ -398,8 +442,8 @@ class RemoveAllWishlistProducts(BaseMutation):
|
|||
|
||||
return RemoveAllWishlistProducts(wishlist=wishlist)
|
||||
|
||||
except Wishlist.DoesNotExist:
|
||||
raise Http404(_(f"wishlist {wishlist_uuid} not found"))
|
||||
except Wishlist.DoesNotExist as dne:
|
||||
raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
|
||||
|
||||
|
||||
class BuyWishlist(BaseMutation):
|
||||
|
|
@ -441,8 +485,8 @@ class BuyWishlist(BaseMutation):
|
|||
case _:
|
||||
raise TypeError(_(f"wrong type came from order.buy() method: {type(instance)!s}"))
|
||||
|
||||
except Wishlist.DoesNotExist:
|
||||
raise Http404(_(f"wishlist {wishlist_uuid} not found"))
|
||||
except Wishlist.DoesNotExist as dne:
|
||||
raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
|
||||
|
||||
|
||||
class BuyProduct(BaseMutation):
|
||||
|
|
@ -483,6 +527,37 @@ class BuyProduct(BaseMutation):
|
|||
raise TypeError(_(f"wrong type came from order.buy() method: {type(instance)!s}"))
|
||||
|
||||
|
||||
class FeedbackProductAction(BaseMutation):
|
||||
class Meta:
|
||||
description = _("add or delete a feedback for orderproduct")
|
||||
|
||||
class Arguments:
|
||||
order_product_uuid = UUID(required=True)
|
||||
action = String(required=True, description="add/remove")
|
||||
comment = String(required=False)
|
||||
rating = Int(required=False)
|
||||
|
||||
feedback = Field(FeedbackType, required=False)
|
||||
|
||||
@staticmethod
|
||||
def mutate(_parent, info, order_product_uuid, action, comment=None, rating=None):
|
||||
user = info.context.user
|
||||
try:
|
||||
order_product = OrderProduct.objects.get(uuid=order_product_uuid)
|
||||
if user != order_product.order.user or not user.has_perm("core.change_orderproduct"):
|
||||
raise PermissionDenied(permission_denied_message)
|
||||
match action:
|
||||
case "add":
|
||||
feedback = order_product.do_feedback(comment=comment, rating=rating, action="add")
|
||||
case "remove":
|
||||
feedback = order_product.do_feedback(action="remove")
|
||||
case _:
|
||||
raise BadRequest(_("action must be either `add` or `remove`"))
|
||||
return FeedbackProductAction(feedback=feedback)
|
||||
except OrderProduct.DoesNotExist as dne:
|
||||
raise Http404(_(f"order product {order_product_uuid} not found")) from dne
|
||||
|
||||
|
||||
class CreateProduct(BaseMutation):
|
||||
class Arguments:
|
||||
name = String(required=True)
|
||||
|
|
@ -575,9 +650,9 @@ class DeleteAddress(BaseMutation):
|
|||
|
||||
raise PermissionDenied(permission_denied_message)
|
||||
|
||||
except Address.DoesNotExist:
|
||||
except Address.DoesNotExist as dne:
|
||||
name = "Address"
|
||||
raise Http404(_(f"{name} does not exist: {uuid}"))
|
||||
raise Http404(_(f"{name} does not exist: {uuid}")) from dne
|
||||
|
||||
|
||||
class AutocompleteAddress(BaseMutation):
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
import logging
|
||||
|
||||
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 (
|
||||
|
|
@ -13,6 +16,7 @@ from graphene import (
|
|||
ObjectType,
|
||||
String,
|
||||
relay,
|
||||
Boolean,
|
||||
)
|
||||
from graphene.types.generic import GenericScalar
|
||||
from graphene_django import DjangoObjectType
|
||||
|
|
@ -40,8 +44,31 @@ from core.models import (
|
|||
Vendor,
|
||||
Wishlist,
|
||||
)
|
||||
from core.utils import graphene_current_lang, graphene_abs
|
||||
from core.utils.seo_builders import (
|
||||
org_schema,
|
||||
breadcrumb_schema,
|
||||
brand_schema,
|
||||
website_schema,
|
||||
category_schema,
|
||||
item_list_schema,
|
||||
product_schema,
|
||||
)
|
||||
from payments.graphene.object_types import TransactionType
|
||||
from payments.models import Transaction
|
||||
|
||||
logger = __import__("logging").getLogger(__name__)
|
||||
logger = logging.getLogger("django")
|
||||
|
||||
|
||||
class SEOMetaType(ObjectType):
|
||||
title = String()
|
||||
description = String()
|
||||
canonical = String()
|
||||
robots = String()
|
||||
open_graph = GenericScalar()
|
||||
twitter = GenericScalar()
|
||||
json_ld = List(GenericScalar)
|
||||
hreflang = List(GenericScalar)
|
||||
|
||||
|
||||
class AttributeType(DjangoObjectType):
|
||||
|
|
@ -87,6 +114,7 @@ class AttributeGroupType(DjangoObjectType):
|
|||
|
||||
class BrandType(DjangoObjectType):
|
||||
categories = List(lambda: CategoryType, description=_("categories"))
|
||||
seo_meta = Field(SEOMetaType, description=_("SEO meta snapshot"))
|
||||
|
||||
class Meta:
|
||||
model = Brand
|
||||
|
|
@ -106,6 +134,48 @@ class BrandType(DjangoObjectType):
|
|||
def resolve_small_logo(self: Brand, info):
|
||||
return info.context.build_absolute_uri(self.small_logo.url) if self.small_logo else ""
|
||||
|
||||
def resolve_seo_meta(self: Brand, info):
|
||||
lang = graphene_current_lang()
|
||||
base = f"https://{config.BASE_DOMAIN}"
|
||||
canonical = f"{base}/{lang}/brand/{self.slug}"
|
||||
title = f"{self.name} | {config.PROJECT_NAME}"
|
||||
description = (self.description or "")[:180]
|
||||
|
||||
logo_url = None
|
||||
if getattr(self, "big_logo", None):
|
||||
logo_url = graphene_abs(info.context, self.big_logo.url)
|
||||
elif getattr(self, "small_logo", None):
|
||||
logo_url = graphene_abs(info.context, self.small_logo.url)
|
||||
|
||||
og = {
|
||||
"title": title,
|
||||
"description": description,
|
||||
"type": "website",
|
||||
"url": canonical,
|
||||
"image": logo_url or "",
|
||||
}
|
||||
tw = {"card": "summary_large_image", "title": title, "description": description, "image": logo_url or ""}
|
||||
|
||||
crumbs = [("Home", f"{base}/"), (self.name, canonical)]
|
||||
|
||||
json_ld = [
|
||||
org_schema(),
|
||||
website_schema(),
|
||||
breadcrumb_schema(crumbs),
|
||||
brand_schema(self, canonical, logo_url=logo_url),
|
||||
]
|
||||
|
||||
return {
|
||||
"title": title,
|
||||
"description": description,
|
||||
"canonical": canonical,
|
||||
"robots": "index,follow",
|
||||
"open_graph": og,
|
||||
"twitter": tw,
|
||||
"json_ld": json_ld,
|
||||
"hreflang": [],
|
||||
}
|
||||
|
||||
|
||||
class FilterableAttributeType(ObjectType):
|
||||
attribute_name = String(required=True)
|
||||
|
|
@ -134,6 +204,7 @@ class CategoryType(DjangoObjectType):
|
|||
)
|
||||
tags = DjangoFilterConnectionField(lambda: CategoryTagType, description=_("tags for this category"))
|
||||
products = DjangoFilterConnectionField(lambda: ProductType, description=_("products in this category"))
|
||||
seo_meta = Field(SEOMetaType, description=_("SEO meta snapshot"))
|
||||
|
||||
class Meta:
|
||||
model = Category
|
||||
|
|
@ -216,6 +287,58 @@ class CategoryType(DjangoObjectType):
|
|||
"max_price": min_max_prices["max_price"],
|
||||
}
|
||||
|
||||
def resolve_seo_meta(self: Category, info):
|
||||
lang = graphene_current_lang()
|
||||
base = f"https://{config.BASE_DOMAIN}"
|
||||
canonical = f"{base}/{lang}/catalog/{self.slug}"
|
||||
title = f"{self.name} | {config.PROJECT_NAME}"
|
||||
description = (self.description or "")[:180]
|
||||
|
||||
og_image = graphene_abs(info.context, self.image.url) if getattr(self, "image", None) else ""
|
||||
|
||||
og = {
|
||||
"title": title,
|
||||
"description": description,
|
||||
"type": "website",
|
||||
"url": canonical,
|
||||
"image": og_image,
|
||||
}
|
||||
tw = {"card": "summary_large_image", "title": title, "description": description, "image": og_image}
|
||||
|
||||
crumbs = [("Home", f"{base}/")]
|
||||
for c in self.get_ancestors():
|
||||
crumbs.append((c.name, f"{base}/{lang}/catalog/{c.slug}"))
|
||||
crumbs.append((self.name, canonical))
|
||||
|
||||
json_ld = [org_schema(), website_schema(), breadcrumb_schema(crumbs), category_schema(self, canonical)]
|
||||
|
||||
product_urls = []
|
||||
qs = (
|
||||
Product.objects.filter(
|
||||
is_active=True,
|
||||
category=self,
|
||||
brand__is_active=True,
|
||||
stocks__vendor__is_active=True,
|
||||
)
|
||||
.only("slug")
|
||||
.distinct()[:24]
|
||||
)
|
||||
for p in qs:
|
||||
product_urls.append(f"{base}/{lang}/product/{p.slug}")
|
||||
if product_urls:
|
||||
json_ld.append(item_list_schema(product_urls))
|
||||
|
||||
return {
|
||||
"title": title,
|
||||
"description": description,
|
||||
"canonical": canonical,
|
||||
"robots": "index,follow",
|
||||
"open_graph": og,
|
||||
"twitter": tw,
|
||||
"json_ld": json_ld,
|
||||
"hreflang": [],
|
||||
}
|
||||
|
||||
|
||||
class VendorType(DjangoObjectType):
|
||||
markup_percent = Float(description=_("markup percentage"))
|
||||
|
|
@ -234,6 +357,7 @@ class AddressType(DjangoObjectType):
|
|||
|
||||
class Meta:
|
||||
model = Address
|
||||
interfaces = (relay.Node,)
|
||||
fields = (
|
||||
"uuid",
|
||||
"street",
|
||||
|
|
@ -313,6 +437,7 @@ class OrderType(DjangoObjectType):
|
|||
is_whole_digital = Float(description=_("are all products in the order digital"))
|
||||
attributes = GenericScalar(description=_("attributes"))
|
||||
notifications = GenericScalar(description=_("notifications"))
|
||||
payments_transactions = Field(TransactionType, description=_("transactions for this order"))
|
||||
|
||||
class Meta:
|
||||
model = Order
|
||||
|
|
@ -329,21 +454,27 @@ class OrderType(DjangoObjectType):
|
|||
"total_quantity",
|
||||
"is_whole_digital",
|
||||
"human_readable_id",
|
||||
"payments_transactions",
|
||||
)
|
||||
description = _("orders")
|
||||
|
||||
def resolve_total_price(self, _info):
|
||||
def resolve_total_price(self: Order, _info):
|
||||
return self.total_price
|
||||
|
||||
def resolve_total_quantity(self, _info):
|
||||
def resolve_total_quantity(self: Order, _info):
|
||||
return self.total_quantity
|
||||
|
||||
def resolve_notifications(self, _info):
|
||||
def resolve_notifications(self: Order, _info):
|
||||
return camelize(self.notifications)
|
||||
|
||||
def resolve_attributes(self, _info):
|
||||
def resolve_attributes(self: Order, _info):
|
||||
return camelize(self.attributes)
|
||||
|
||||
def resolve_payments_transactions(self: Order, _info) -> QuerySet[Transaction] | None:
|
||||
if self.payments_transactions:
|
||||
return self.payments_transactions.all()
|
||||
return None
|
||||
|
||||
|
||||
class ProductImageType(DjangoObjectType):
|
||||
image = String(description=_("image url"))
|
||||
|
|
@ -368,6 +499,8 @@ class ProductType(DjangoObjectType):
|
|||
price = Float(description=_("price"))
|
||||
quantity = Float(description=_("quantity"))
|
||||
feedbacks_count = Int(description=_("number of feedbacks"))
|
||||
personal_orders_only = Boolean(description=_("only available for personal orders"))
|
||||
seo_meta = Field(SEOMetaType, description=_("SEO meta snapshot"))
|
||||
|
||||
class Meta:
|
||||
model = Product
|
||||
|
|
@ -381,13 +514,17 @@ class ProductType(DjangoObjectType):
|
|||
"slug",
|
||||
"description",
|
||||
"feedbacks",
|
||||
"feedbacks_count",
|
||||
"personal_orders_only",
|
||||
"quantity",
|
||||
"attribute_groups",
|
||||
"images",
|
||||
"price",
|
||||
)
|
||||
filter_fields = ["uuid", "name"]
|
||||
description = _("products")
|
||||
|
||||
def resolve_price(self, _info) -> float:
|
||||
def resolve_price(self: Product, _info) -> float:
|
||||
return self.price or 0.0
|
||||
|
||||
def resolve_feedbacks(self: Product, _info):
|
||||
|
|
@ -395,7 +532,7 @@ class ProductType(DjangoObjectType):
|
|||
return Feedback.objects.filter(order_product__product=self)
|
||||
return Feedback.objects.filter(order_product__product=self, is_active=True)
|
||||
|
||||
def resolve_feedbacks_count(self, _info) -> int:
|
||||
def resolve_feedbacks_count(self: Product, _info) -> int:
|
||||
return self.feedbacks_count or 0
|
||||
|
||||
def resolve_attribute_groups(self: Product, info):
|
||||
|
|
@ -403,9 +540,58 @@ class ProductType(DjangoObjectType):
|
|||
|
||||
return AttributeGroup.objects.filter(attributes__values__product=self).distinct()
|
||||
|
||||
def resolve_quantity(self, _info) -> int:
|
||||
def resolve_quantity(self: Product, _info) -> int:
|
||||
return self.quantity or 0
|
||||
|
||||
def resolve_personal_orders_only(self: Product, _info) -> bool:
|
||||
return False or self.personal_orders_only
|
||||
|
||||
def resolve_seo_meta(self: Product, info):
|
||||
lang = graphene_current_lang()
|
||||
base = f"https://{config.BASE_DOMAIN}"
|
||||
canonical = f"{base}/{lang}/product/{self.slug}"
|
||||
title = f"{self.name} | {config.PROJECT_NAME}"
|
||||
description = (self.description or "")[:180]
|
||||
|
||||
first_img = self.images.order_by("priority").first()
|
||||
og_image = graphene_abs(info.context, first_img.image.url) if first_img else ""
|
||||
|
||||
og = {
|
||||
"title": title,
|
||||
"description": description,
|
||||
"type": "product",
|
||||
"url": canonical,
|
||||
"image": og_image,
|
||||
}
|
||||
tw = {"card": "summary_large_image", "title": title, "description": description, "image": og_image}
|
||||
|
||||
crumbs = [("Home", f"{base}/")]
|
||||
if self.category:
|
||||
for c in self.category.get_ancestors(include_self=True):
|
||||
crumbs.append((c.name, f"{base}/{lang}/catalog/{c.slug}"))
|
||||
crumbs.append((self.name, canonical))
|
||||
|
||||
images = list(self.images.all()[:6])
|
||||
rating = {"value": self.rating, "count": self.feedbacks_count}
|
||||
|
||||
json_ld = [
|
||||
org_schema(),
|
||||
website_schema(),
|
||||
breadcrumb_schema(crumbs),
|
||||
product_schema(self, images, rating=rating),
|
||||
]
|
||||
|
||||
return {
|
||||
"title": title,
|
||||
"description": description,
|
||||
"canonical": canonical,
|
||||
"robots": "index,follow",
|
||||
"open_graph": og,
|
||||
"twitter": tw,
|
||||
"json_ld": json_ld,
|
||||
"hreflang": [],
|
||||
}
|
||||
|
||||
|
||||
class AttributeValueType(DjangoObjectType):
|
||||
value = String(description=_("attribute value"))
|
||||
|
|
@ -436,7 +622,7 @@ class PromoCodeType(DjangoObjectType):
|
|||
description = _("promocodes")
|
||||
|
||||
def resolve_discount(self: PromoCode, _info) -> float:
|
||||
return float(self.discount_percent) if self.discount_percent else float(self.discount_amount)
|
||||
return float(self.discount_percent) if self.discount_percent else float(self.discount_amount) # type: ignore [arg-type]
|
||||
|
||||
def resolve_discount_type(self: PromoCode, _info) -> str:
|
||||
return "percent" if self.discount_percent else "amount"
|
||||
|
|
@ -557,6 +743,6 @@ class SearchResultsType(ObjectType):
|
|||
posts = List(description=_("posts search results"), of_type=SearchPostsResultsType)
|
||||
|
||||
|
||||
class BulkActionOrderProductInput(InputObjectType):
|
||||
class BulkProductInput(InputObjectType):
|
||||
uuid = UUID(required=True)
|
||||
attributes = GenericScalar(required=False)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import logging
|
||||
|
||||
from django.core.cache import cache
|
||||
from django.utils import timezone
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from graphene import Field, List, ObjectType, Schema
|
||||
from graphene_django.filter import DjangoFilterConnectionField
|
||||
|
|
@ -14,12 +15,14 @@ from core.filters import (
|
|||
OrderFilter,
|
||||
ProductFilter,
|
||||
WishlistFilter,
|
||||
AddressFilter,
|
||||
)
|
||||
from core.graphene.mutations import (
|
||||
AddOrderProduct,
|
||||
AddWishlistProduct,
|
||||
AutocompleteAddress,
|
||||
BulkOrderAction,
|
||||
BulkWishlistAction,
|
||||
BuyOrder,
|
||||
BuyProduct,
|
||||
BuyWishlist,
|
||||
|
|
@ -29,6 +32,7 @@ from core.graphene.mutations import (
|
|||
CreateProduct,
|
||||
DeleteAddress,
|
||||
DeleteProduct,
|
||||
FeedbackProductAction,
|
||||
RemoveAllOrderProducts,
|
||||
RemoveAllWishlistProducts,
|
||||
RemoveOrderProduct,
|
||||
|
|
@ -56,6 +60,7 @@ from core.graphene.object_types import (
|
|||
StockType,
|
||||
VendorType,
|
||||
WishlistType,
|
||||
AddressType,
|
||||
)
|
||||
from core.models import (
|
||||
AttributeGroup,
|
||||
|
|
@ -73,6 +78,7 @@ from core.models import (
|
|||
Stock,
|
||||
Vendor,
|
||||
Wishlist,
|
||||
Address,
|
||||
)
|
||||
from core.utils import get_project_parameters
|
||||
from core.utils.languages import get_flag_by_language
|
||||
|
|
@ -95,7 +101,7 @@ from vibes_auth.graphene.mutations import (
|
|||
from vibes_auth.graphene.object_types import UserType
|
||||
from vibes_auth.models import User
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logger = logging.getLogger("django")
|
||||
|
||||
|
||||
class Query(ObjectType):
|
||||
|
|
@ -104,6 +110,7 @@ class Query(ObjectType):
|
|||
products = DjangoFilterConnectionField(ProductType, filterset_class=ProductFilter)
|
||||
orders = DjangoFilterConnectionField(OrderType, filterset_class=OrderFilter)
|
||||
users = DjangoFilterConnectionField(UserType, filterset_class=UserFilter)
|
||||
addresses = DjangoFilterConnectionField(AddressType, filterset_class=AddressFilter)
|
||||
attribute_groups = DjangoFilterConnectionField(AttributeGroupType)
|
||||
categories = DjangoFilterConnectionField(CategoryType, filterset_class=CategoryFilter)
|
||||
vendors = DjangoFilterConnectionField(VendorType)
|
||||
|
|
@ -145,7 +152,10 @@ class Query(ObjectType):
|
|||
Product.objects.all().select_related("brand", "category").prefetch_related("images", "stocks")
|
||||
if info.context.user.has_perm("core.view_product")
|
||||
else Product.objects.filter(
|
||||
is_active=True, brand__is_active=True, category__is_active=True, stocks__isnull=False
|
||||
is_active=True,
|
||||
brand__is_active=True,
|
||||
category__is_active=True,
|
||||
stocks__vendor__is_active=True,
|
||||
)
|
||||
.select_related("brand", "category")
|
||||
.prefetch_related("images", "stocks")
|
||||
|
|
@ -284,7 +294,12 @@ class Query(ObjectType):
|
|||
promocodes = PromoCode.objects
|
||||
if info.context.user.has_perm("core.view_promocode"):
|
||||
return promocodes.filter(user__uuid=kwargs.get("user_uuid")) or promocodes.all()
|
||||
return promocodes.filter(is_active=True, user=info.context.user)
|
||||
return promocodes.filter(
|
||||
is_active=True,
|
||||
user=info.context.user,
|
||||
used_on__isnull=True,
|
||||
start_time__lte=timezone.now(),
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def resolve_product_tags(_parent, info, **_kwargs):
|
||||
|
|
@ -298,6 +313,12 @@ class Query(ObjectType):
|
|||
return CategoryTag.objects.all()
|
||||
return CategoryTag.objects.filter(is_active=True)
|
||||
|
||||
@staticmethod
|
||||
def resolve_addresses(_parent, info, **_kwargs):
|
||||
if info.context.user.has_perm("core.view_address"):
|
||||
return Address.objects.all()
|
||||
return Address.objects.filter(is_active=True, user=info.context.user)
|
||||
|
||||
|
||||
class Mutation(ObjectType):
|
||||
search = Search.Field()
|
||||
|
|
@ -314,6 +335,8 @@ class Mutation(ObjectType):
|
|||
remove_order_products_of_a_kind = RemoveOrderProductsOfAKind.Field()
|
||||
buy_order = BuyOrder.Field()
|
||||
bulk_order_action = BulkOrderAction.Field()
|
||||
bulk_wishlist_action = BulkWishlistAction.Field()
|
||||
feedback_product_action = FeedbackProductAction.Field()
|
||||
deposit = Deposit.Field()
|
||||
obtain_jwt_token = ObtainJSONWebToken.Field()
|
||||
refresh_jwt_token = RefreshJSONWebToken.Field()
|
||||
|
|
|
|||
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
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
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue