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
|
*.cover
|
||||||
*.py,cover
|
*.py,cover
|
||||||
nosetests.xml
|
nosetests.xml
|
||||||
|
desktop.ini
|
||||||
|
|
||||||
# Cache directories
|
# Cache directories
|
||||||
__pycache__/
|
__pycache__/
|
||||||
|
|
@ -37,7 +38,6 @@ __pypackages__/
|
||||||
# Packaging and distribution
|
# Packaging and distribution
|
||||||
# ──────────────────────────────────────────────────────────────────────────
|
# ──────────────────────────────────────────────────────────────────────────
|
||||||
build/
|
build/
|
||||||
dist/
|
|
||||||
dist-ssr/
|
dist-ssr/
|
||||||
*.egg
|
*.egg
|
||||||
*.egg-info/
|
*.egg-info/
|
||||||
|
|
|
||||||
7
.gitignore
vendored
7
.gitignore
vendored
|
|
@ -64,8 +64,9 @@ htmlcov/
|
||||||
.pybuilder/
|
.pybuilder/
|
||||||
|
|
||||||
# Storefronts
|
# Storefronts
|
||||||
.astro/
|
|
||||||
.nuxt/
|
.nuxt/
|
||||||
|
.next/
|
||||||
|
next-env.d.ts
|
||||||
|
|
||||||
# Celery
|
# Celery
|
||||||
celerybeat-schedule
|
celerybeat-schedule
|
||||||
|
|
@ -141,6 +142,10 @@ cypress/screenshots/
|
||||||
|
|
||||||
# JetBrains
|
# JetBrains
|
||||||
.idea/
|
.idea/
|
||||||
|
!.idea/icon.svg
|
||||||
|
!.idea/externalDependencies.xml
|
||||||
|
!.idea/evibes.iml
|
||||||
|
!.idea/evibes.ico
|
||||||
|
|
||||||
# Microsoft
|
# Microsoft
|
||||||
*.suo
|
*.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
|
LICENSE @fureunoir contact@fureunoir.com
|
||||||
|
|
||||||
Dockerfile.app @fureunoir contact@fureunoir.com
|
Dockerfiles @@maintainer
|
||||||
Dockerfile.storefront @SaVBaD savbad@wiseless.xyz
|
|
||||||
docker-compose.yml @@maintainer
|
docker-compose.yml @@maintainer
|
||||||
.gitignore @@maintainer
|
.gitignore @@maintainer
|
||||||
.dockerignore @@maintainer
|
.dockerignore @@maintainer
|
||||||
|
|
@ -13,14 +12,6 @@ nginx @@maintainer
|
||||||
pyproject.toml @fureunoir contact@fureunoir.com
|
pyproject.toml @fureunoir contact@fureunoir.com
|
||||||
poetry.lock @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
|
*.py @fureunoir contact@fureunoir.com
|
||||||
*.bat @fureunoir contact@fureunoir.com
|
*.bat @fureunoir contact@fureunoir.com
|
||||||
*.sh @fureunoir contact@fureunoir.com
|
*.sh @fureunoir contact@fureunoir.com
|
||||||
|
|
@ -31,5 +22,13 @@ storefront/ @SaVBaD savbad@wiseless.xyz
|
||||||
*.mjs @SaVBaD savbad@wiseless.xyz
|
*.mjs @SaVBaD savbad@wiseless.xyz
|
||||||
*.cjs @SaVBaD savbad@wiseless.xyz
|
*.cjs @SaVBaD savbad@wiseless.xyz
|
||||||
*.vue @SaVBaD savbad@wiseless.xyz
|
*.vue @SaVBaD savbad@wiseless.xyz
|
||||||
*.astro @SaVBaD savbad@wiseless.xyz
|
|
||||||
*.scss @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 \
|
graphviz-dev \
|
||||||
libgts-dev \
|
libgts-dev \
|
||||||
libpq5 \
|
libpq5 \
|
||||||
|
chrony \
|
||||||
graphviz \
|
graphviz \
|
||||||
binutils \
|
binutils \
|
||||||
libproj-dev \
|
libproj-dev \
|
||||||
|
|
@ -46,4 +47,4 @@ RUN chmod +x /usr/local/bin/app-entrypoint.sh
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
ENTRYPOINT ["app-entrypoint.sh"]
|
ENTRYPOINT ["/usr/bin/bash", "app-entrypoint.sh"]
|
||||||
|
|
@ -26,6 +26,7 @@ RUN set -eux; \
|
||||||
graphviz-dev \
|
graphviz-dev \
|
||||||
libgts-dev \
|
libgts-dev \
|
||||||
libpq5 \
|
libpq5 \
|
||||||
|
chrony \
|
||||||
graphviz \
|
graphviz \
|
||||||
binutils \
|
binutils \
|
||||||
libproj-dev \
|
libproj-dev \
|
||||||
|
|
@ -46,4 +47,4 @@ RUN chmod +x /usr/local/bin/beat-entrypoint.sh
|
||||||
|
|
||||||
COPY . .
|
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 \
|
graphviz-dev \
|
||||||
libgts-dev \
|
libgts-dev \
|
||||||
libpq5 \
|
libpq5 \
|
||||||
|
chrony \
|
||||||
graphviz \
|
graphviz \
|
||||||
binutils \
|
binutils \
|
||||||
libproj-dev \
|
libproj-dev \
|
||||||
|
|
@ -46,4 +47,4 @@ RUN chmod +x /usr/local/bin/worker-entrypoint.sh
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
ENTRYPOINT ["worker-entrypoint.sh"]
|
ENTRYPOINT ["/usr/bin/bash", "worker-entrypoint.sh"]
|
||||||
|
|
@ -44,10 +44,11 @@ extension.
|
||||||
cd eVibes
|
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
|
```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.
|
3. Generate your .env file. Check and confirm the contents afterward.
|
||||||
|
|
|
||||||
|
|
@ -1,37 +1,40 @@
|
||||||
from django.contrib import admin
|
from django.contrib.admin import ModelAdmin, register
|
||||||
from django_summernote.admin import SummernoteModelAdmin
|
from django_summernote.admin import SummernoteModelAdminMixin
|
||||||
|
|
||||||
|
from core.admin import ActivationActionsMixin, FieldsetsMixin
|
||||||
|
|
||||||
from .models import Post, PostTag
|
from .models import Post, PostTag
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Post)
|
@register(Post)
|
||||||
class PostAdmin(SummernoteModelAdmin):
|
class PostAdmin(SummernoteModelAdminMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||||
list_display = ("title", "author", "slug", "created", "modified")
|
list_display = ("title", "author", "slug", "created", "modified")
|
||||||
list_filter = ("author", "tags", "created", "modified")
|
list_filter = ("author", "tags", "created", "modified")
|
||||||
search_fields = ("title", "content")
|
search_fields = ("title", "content", "slug")
|
||||||
filter_horizontal = ("tags",)
|
filter_horizontal = ("tags",)
|
||||||
date_hierarchy = "created"
|
date_hierarchy = "created"
|
||||||
autocomplete_fields = ("author", "tags")
|
autocomplete_fields = ("author", "tags")
|
||||||
summernote_fields = ("content",)
|
readonly_fields = (
|
||||||
|
"uuid",
|
||||||
fieldsets = (
|
"slug",
|
||||||
(
|
"modified",
|
||||||
None,
|
"created",
|
||||||
{
|
|
||||||
"fields": (
|
|
||||||
"author",
|
|
||||||
"title",
|
|
||||||
"content",
|
|
||||||
"file",
|
|
||||||
"tags",
|
|
||||||
)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
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")
|
list_display = ("tag_name", "name")
|
||||||
search_fields = ("tag_name", "name")
|
search_fields = ("tag_name", "name")
|
||||||
ordering = ("tag_name",)
|
ordering = ("tag_name",)
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||||
"Report-Msgid-Bugs-To: \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"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -17,55 +17,52 @@ msgstr ""
|
||||||
msgid "blog"
|
msgid "blog"
|
||||||
msgstr "المدونة"
|
msgstr "المدونة"
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "عنوان المنشور"
|
msgstr "عنوان المنشور"
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "العنوان"
|
msgstr "العنوان"
|
||||||
|
|
||||||
#: blog/models.py:64
|
#: blog/models.py:83
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "المنشور"
|
msgstr "المنشور"
|
||||||
|
|
||||||
#: blog/models.py:65
|
#: blog/models.py:84
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "المنشورات"
|
msgstr "المنشورات"
|
||||||
|
|
||||||
#: blog/models.py:69
|
#: blog/models.py:88
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "markdown files are not supported yet - use markdown content instead"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"ملفات تخفيض السعر غير مدعومة Yer - استخدم محتوى تخفيض السعر بدلاً من ذلك!"
|
"ملفات تخفيض السعر غير مدعومة Yer - استخدم محتوى تخفيض السعر بدلاً من ذلك!"
|
||||||
|
|
||||||
#: blog/models.py:71
|
#: blog/models.py:90
|
||||||
msgid ""
|
msgid ""
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||||
msgstr "يجب توفير ملف ترميز أو محتوى ترميز مخفض - متنافيان"
|
msgstr "يجب توفير ملف ترميز أو محتوى ترميز مخفض - متنافيان"
|
||||||
|
|
||||||
#: blog/models.py:82
|
#: blog/models.py:122
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "معرّف العلامة الداخلي لعلامة المنشور"
|
msgstr "معرّف العلامة الداخلي لعلامة المنشور"
|
||||||
|
|
||||||
#: blog/models.py:83
|
#: blog/models.py:123
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "اسم العلامة"
|
msgstr "اسم العلامة"
|
||||||
|
|
||||||
#: blog/models.py:87
|
#: blog/models.py:127
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "اسم سهل الاستخدام لعلامة المنشور"
|
msgstr "اسم سهل الاستخدام لعلامة المنشور"
|
||||||
|
|
||||||
#: blog/models.py:88
|
#: blog/models.py:128
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "اسم عرض العلامة"
|
msgstr "اسم عرض العلامة"
|
||||||
|
|
||||||
#: blog/models.py:96
|
#: blog/models.py:136
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "علامة المشاركة"
|
msgstr "علامة المشاركة"
|
||||||
|
|
||||||
#: blog/models.py:97
|
#: blog/models.py:137
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "علامات المشاركة"
|
msgstr "علامات المشاركة"
|
||||||
|
|
||||||
#~ msgid "eVibes Engine"
|
|
||||||
#~ msgstr "محرك eVibes"
|
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||||
"Report-Msgid-Bugs-To: \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"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -17,57 +17,54 @@ msgstr ""
|
||||||
msgid "blog"
|
msgid "blog"
|
||||||
msgstr "Blog"
|
msgstr "Blog"
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "Název příspěvku"
|
msgstr "Název příspěvku"
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Název"
|
msgstr "Název"
|
||||||
|
|
||||||
#: blog/models.py:64
|
#: blog/models.py:83
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "Příspěvek"
|
msgstr "Příspěvek"
|
||||||
|
|
||||||
#: blog/models.py:65
|
#: blog/models.py:84
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "Příspěvky"
|
msgstr "Příspěvky"
|
||||||
|
|
||||||
#: blog/models.py:69
|
#: blog/models.py:88
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "markdown files are not supported yet - use markdown content instead"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Soubory Markdown nejsou podporovány - místo toho použijte obsah Markdown!"
|
"Soubory Markdown nejsou podporovány - místo toho použijte obsah Markdown!"
|
||||||
|
|
||||||
#: blog/models.py:71
|
#: blog/models.py:90
|
||||||
msgid ""
|
msgid ""
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"musí být poskytnut soubor markdown nebo obsah markdown - vzájemně se "
|
"musí být poskytnut soubor markdown nebo obsah markdown - vzájemně se "
|
||||||
"vylučují."
|
"vylučují."
|
||||||
|
|
||||||
#: blog/models.py:82
|
#: blog/models.py:122
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "interní identifikátor tagu pro tag příspěvku"
|
msgstr "interní identifikátor tagu pro tag příspěvku"
|
||||||
|
|
||||||
#: blog/models.py:83
|
#: blog/models.py:123
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "Název štítku"
|
msgstr "Název štítku"
|
||||||
|
|
||||||
#: blog/models.py:87
|
#: blog/models.py:127
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "Uživatelsky přívětivý název pro značku příspěvku"
|
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"
|
msgid "tag display name"
|
||||||
msgstr "Zobrazení názvu štítku"
|
msgstr "Zobrazení názvu štítku"
|
||||||
|
|
||||||
#: blog/models.py:96
|
#: blog/models.py:136
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "Označení příspěvku"
|
msgstr "Označení příspěvku"
|
||||||
|
|
||||||
#: blog/models.py:97
|
#: blog/models.py:137
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "Štítky příspěvků"
|
msgstr "Štítky příspěvků"
|
||||||
|
|
||||||
#~ msgid "eVibes Engine"
|
|
||||||
#~ msgstr "Motor eVibes"
|
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||||
"Report-Msgid-Bugs-To: \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"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -17,55 +17,52 @@ msgstr ""
|
||||||
msgid "blog"
|
msgid "blog"
|
||||||
msgstr "Blog"
|
msgstr "Blog"
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "Indlæggets titel"
|
msgstr "Indlæggets titel"
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Titel"
|
msgstr "Titel"
|
||||||
|
|
||||||
#: blog/models.py:64
|
#: blog/models.py:83
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "Indlæg"
|
msgstr "Indlæg"
|
||||||
|
|
||||||
#: blog/models.py:65
|
#: blog/models.py:84
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "Indlæg"
|
msgstr "Indlæg"
|
||||||
|
|
||||||
#: blog/models.py:69
|
#: blog/models.py:88
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "markdown files are not supported yet - use markdown content instead"
|
||||||
msgstr "Markdown-filer understøttes ikke - brug markdown-indhold i stedet!"
|
msgstr "Markdown-filer understøttes ikke - brug markdown-indhold i stedet!"
|
||||||
|
|
||||||
#: blog/models.py:71
|
#: blog/models.py:90
|
||||||
msgid ""
|
msgid ""
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"en markdown-fil eller markdown-indhold skal leveres - gensidigt udelukkende"
|
"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"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "intern tag-identifikator for indlægs-tagget"
|
msgstr "intern tag-identifikator for indlægs-tagget"
|
||||||
|
|
||||||
#: blog/models.py:83
|
#: blog/models.py:123
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "Tag-navn"
|
msgstr "Tag-navn"
|
||||||
|
|
||||||
#: blog/models.py:87
|
#: blog/models.py:127
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "Brugervenligt navn til posttagget"
|
msgstr "Brugervenligt navn til posttagget"
|
||||||
|
|
||||||
#: blog/models.py:88
|
#: blog/models.py:128
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "Navn på tag-visning"
|
msgstr "Navn på tag-visning"
|
||||||
|
|
||||||
#: blog/models.py:96
|
#: blog/models.py:136
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "Tag til indlæg"
|
msgstr "Tag til indlæg"
|
||||||
|
|
||||||
#: blog/models.py:97
|
#: blog/models.py:137
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "Tags til indlæg"
|
msgstr "Tags til indlæg"
|
||||||
|
|
||||||
#~ msgid "eVibes Engine"
|
|
||||||
#~ msgstr "eVibes-motor"
|
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||||
"Report-Msgid-Bugs-To: \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"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -17,58 +17,55 @@ msgstr ""
|
||||||
msgid "blog"
|
msgid "blog"
|
||||||
msgstr "Blog"
|
msgstr "Blog"
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "Titel des Beitrags"
|
msgstr "Titel des Beitrags"
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Titel"
|
msgstr "Titel"
|
||||||
|
|
||||||
#: blog/models.py:64
|
#: blog/models.py:83
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "Beitrag"
|
msgstr "Beitrag"
|
||||||
|
|
||||||
#: blog/models.py:65
|
#: blog/models.py:84
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "Beiträge"
|
msgstr "Beiträge"
|
||||||
|
|
||||||
#: blog/models.py:69
|
#: blog/models.py:88
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "markdown files are not supported yet - use markdown content instead"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Markdown-Dateien werden nicht unterstützt - verwenden Sie stattdessen "
|
"Markdown-Dateien werden nicht unterstützt - verwenden Sie stattdessen "
|
||||||
"Markdown-Inhalte!"
|
"Markdown-Inhalte!"
|
||||||
|
|
||||||
#: blog/models.py:71
|
#: blog/models.py:90
|
||||||
msgid ""
|
msgid ""
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"eine Markdown-Datei oder ein Markdown-Inhalt muss bereitgestellt werden - "
|
"eine Markdown-Datei oder ein Markdown-Inhalt muss bereitgestellt werden - "
|
||||||
"beide schließen sich gegenseitig aus"
|
"beide schließen sich gegenseitig aus"
|
||||||
|
|
||||||
#: blog/models.py:82
|
#: blog/models.py:122
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "interner Tag-Bezeichner für den Post-Tag"
|
msgstr "interner Tag-Bezeichner für den Post-Tag"
|
||||||
|
|
||||||
#: blog/models.py:83
|
#: blog/models.py:123
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "Tag name"
|
msgstr "Tag name"
|
||||||
|
|
||||||
#: blog/models.py:87
|
#: blog/models.py:127
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "Benutzerfreundlicher Name für das Post-Tag"
|
msgstr "Benutzerfreundlicher Name für das Post-Tag"
|
||||||
|
|
||||||
#: blog/models.py:88
|
#: blog/models.py:128
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "Tag-Anzeigename"
|
msgstr "Tag-Anzeigename"
|
||||||
|
|
||||||
#: blog/models.py:96
|
#: blog/models.py:136
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "Tag eintragen"
|
msgstr "Tag eintragen"
|
||||||
|
|
||||||
#: blog/models.py:97
|
#: blog/models.py:137
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "Tags eintragen"
|
msgstr "Tags eintragen"
|
||||||
|
|
||||||
#~ msgid "eVibes Engine"
|
|
||||||
#~ msgstr "eVibes Motor"
|
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -2,12 +2,12 @@
|
||||||
# Copyright (C) 2025 EGOR <FUREUNOIR> GORBUNOV
|
# Copyright (C) 2025 EGOR <FUREUNOIR> GORBUNOV
|
||||||
# This file is distributed under the same license as the EVIBES package.
|
# This file is distributed under the same license as the EVIBES package.
|
||||||
# EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>, 2025.
|
# EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>, 2025.
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||||
"Report-Msgid-Bugs-To: \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"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -21,61 +21,52 @@ msgstr ""
|
||||||
msgid "blog"
|
msgid "blog"
|
||||||
msgstr "Blog"
|
msgstr "Blog"
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "Post's title"
|
msgstr "Post's title"
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Title"
|
msgstr "Title"
|
||||||
|
|
||||||
#: blog/models.py:64
|
#: blog/models.py:83
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "Post"
|
msgstr "Post"
|
||||||
|
|
||||||
#: blog/models.py:65
|
#: blog/models.py:84
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "Posts"
|
msgstr "Posts"
|
||||||
|
|
||||||
#: blog/models.py:69
|
#: blog/models.py:88
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "markdown files are not supported yet - use markdown content instead"
|
||||||
msgstr "Markdown files are not supported yer - use markdown content instead!"
|
msgstr "Markdown files are not supported yer - use markdown content instead!"
|
||||||
|
|
||||||
#: blog/models.py:71
|
#: blog/models.py:90
|
||||||
msgid ""
|
msgid ""
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
"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"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "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"
|
msgid "tag name"
|
||||||
msgstr "Tag name"
|
msgstr "Tag name"
|
||||||
|
|
||||||
#: blog/models.py:87
|
#: blog/models.py:127
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "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"
|
msgid "tag display name"
|
||||||
msgstr "Tag display name"
|
msgstr "Tag display name"
|
||||||
|
|
||||||
#: blog/models.py:96
|
#: blog/models.py:136
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "Post tag"
|
msgstr "Post tag"
|
||||||
|
|
||||||
#: blog/models.py:97
|
#: blog/models.py:137
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "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 ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||||
"Report-Msgid-Bugs-To: \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"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -17,55 +17,52 @@ msgstr ""
|
||||||
msgid "blog"
|
msgid "blog"
|
||||||
msgstr "Blog"
|
msgstr "Blog"
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "Post's title"
|
msgstr "Post's title"
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Title"
|
msgstr "Title"
|
||||||
|
|
||||||
#: blog/models.py:64
|
#: blog/models.py:83
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "Post"
|
msgstr "Post"
|
||||||
|
|
||||||
#: blog/models.py:65
|
#: blog/models.py:84
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "Posts"
|
msgstr "Posts"
|
||||||
|
|
||||||
#: blog/models.py:69
|
#: blog/models.py:88
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "markdown files are not supported yet - use markdown content instead"
|
||||||
msgstr "Markdown files are not supported yer - use markdown content instead!"
|
msgstr "Markdown files are not supported yer - use markdown content instead!"
|
||||||
|
|
||||||
#: blog/models.py:71
|
#: blog/models.py:90
|
||||||
msgid ""
|
msgid ""
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
"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"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "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"
|
msgid "tag name"
|
||||||
msgstr "Tag name"
|
msgstr "Tag name"
|
||||||
|
|
||||||
#: blog/models.py:87
|
#: blog/models.py:127
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "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"
|
msgid "tag display name"
|
||||||
msgstr "Tag display name"
|
msgstr "Tag display name"
|
||||||
|
|
||||||
#: blog/models.py:96
|
#: blog/models.py:136
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "Post tag"
|
msgstr "Post tag"
|
||||||
|
|
||||||
#: blog/models.py:97
|
#: blog/models.py:137
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "Post tags"
|
msgstr "Post tags"
|
||||||
|
|
||||||
#~ msgid "eVibes Engine"
|
|
||||||
#~ msgstr "eVibes Engine"
|
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||||
"Report-Msgid-Bugs-To: \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"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -17,57 +17,54 @@ msgstr ""
|
||||||
msgid "blog"
|
msgid "blog"
|
||||||
msgstr "Blog"
|
msgstr "Blog"
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "Título del mensaje"
|
msgstr "Título del mensaje"
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Título"
|
msgstr "Título"
|
||||||
|
|
||||||
#: blog/models.py:64
|
#: blog/models.py:83
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "Publicar en"
|
msgstr "Publicar en"
|
||||||
|
|
||||||
#: blog/models.py:65
|
#: blog/models.py:84
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "Puestos"
|
msgstr "Puestos"
|
||||||
|
|
||||||
#: blog/models.py:69
|
#: blog/models.py:88
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "markdown files are not supported yet - use markdown content instead"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"No se admiten archivos Markdown - ¡utiliza contenido Markdown en su lugar!"
|
"No se admiten archivos Markdown - ¡utiliza contenido Markdown en su lugar!"
|
||||||
|
|
||||||
#: blog/models.py:71
|
#: blog/models.py:90
|
||||||
msgid ""
|
msgid ""
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"se debe proporcionar un archivo markdown o contenido markdown - mutuamente "
|
"se debe proporcionar un archivo markdown o contenido markdown - mutuamente "
|
||||||
"excluyentes"
|
"excluyentes"
|
||||||
|
|
||||||
#: blog/models.py:82
|
#: blog/models.py:122
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "identificador interno de la etiqueta post"
|
msgstr "identificador interno de la etiqueta post"
|
||||||
|
|
||||||
#: blog/models.py:83
|
#: blog/models.py:123
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "Nombre de la etiqueta"
|
msgstr "Nombre de la etiqueta"
|
||||||
|
|
||||||
#: blog/models.py:87
|
#: blog/models.py:127
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "Nombre fácil de usar para la etiqueta de la entrada"
|
msgstr "Nombre fácil de usar para la etiqueta de la entrada"
|
||||||
|
|
||||||
#: blog/models.py:88
|
#: blog/models.py:128
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "Nombre de la etiqueta"
|
msgstr "Nombre de la etiqueta"
|
||||||
|
|
||||||
#: blog/models.py:96
|
#: blog/models.py:136
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "Etiqueta postal"
|
msgstr "Etiqueta postal"
|
||||||
|
|
||||||
#: blog/models.py:97
|
#: blog/models.py:137
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "Etiquetas"
|
msgstr "Etiquetas"
|
||||||
|
|
||||||
#~ msgid "eVibes Engine"
|
|
||||||
#~ msgstr "Motor eVibes"
|
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||||
"Report-Msgid-Bugs-To: \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"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -17,58 +17,55 @@ msgstr ""
|
||||||
msgid "blog"
|
msgid "blog"
|
||||||
msgstr "Blog"
|
msgstr "Blog"
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "Titre du message"
|
msgstr "Titre du message"
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Titre"
|
msgstr "Titre"
|
||||||
|
|
||||||
#: blog/models.py:64
|
#: blog/models.py:83
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "Poste"
|
msgstr "Poste"
|
||||||
|
|
||||||
#: blog/models.py:65
|
#: blog/models.py:84
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "Postes"
|
msgstr "Postes"
|
||||||
|
|
||||||
#: blog/models.py:69
|
#: blog/models.py:88
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "markdown files are not supported yet - use markdown content instead"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Les fichiers Markdown ne sont pas pris en charge - utilisez plutôt du "
|
"Les fichiers Markdown ne sont pas pris en charge - utilisez plutôt du "
|
||||||
"contenu Markdown !"
|
"contenu Markdown !"
|
||||||
|
|
||||||
#: blog/models.py:71
|
#: blog/models.py:90
|
||||||
msgid ""
|
msgid ""
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"un fichier markdown ou un contenu markdown doit être fourni - ils s'excluent "
|
"un fichier markdown ou un contenu markdown doit être fourni - ils s'excluent "
|
||||||
"mutuellement"
|
"mutuellement"
|
||||||
|
|
||||||
#: blog/models.py:82
|
#: blog/models.py:122
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "identifiant interne de la balise post"
|
msgstr "identifiant interne de la balise post"
|
||||||
|
|
||||||
#: blog/models.py:83
|
#: blog/models.py:123
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "Nom du jour"
|
msgstr "Nom du jour"
|
||||||
|
|
||||||
#: blog/models.py:87
|
#: blog/models.py:127
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "Nom convivial pour la balise post"
|
msgstr "Nom convivial pour la balise post"
|
||||||
|
|
||||||
#: blog/models.py:88
|
#: blog/models.py:128
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "Nom d'affichage de l'étiquette"
|
msgstr "Nom d'affichage de l'étiquette"
|
||||||
|
|
||||||
#: blog/models.py:96
|
#: blog/models.py:136
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "Tag de poste"
|
msgstr "Tag de poste"
|
||||||
|
|
||||||
#: blog/models.py:97
|
#: blog/models.py:137
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "Tags de la poste"
|
msgstr "Tags de la poste"
|
||||||
|
|
||||||
#~ msgid "eVibes Engine"
|
|
||||||
#~ msgstr "Moteur eVibes"
|
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -2,12 +2,12 @@
|
||||||
# Copyright (C) 2025 EGOR <FUREUNOIR> GORBUNOV
|
# Copyright (C) 2025 EGOR <FUREUNOIR> GORBUNOV
|
||||||
# This file is distributed under the same license as the EVIBES package.
|
# This file is distributed under the same license as the EVIBES package.
|
||||||
# EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>, 2025.
|
# EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>, 2025.
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||||
"Report-Msgid-Bugs-To: \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"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -20,51 +20,51 @@ msgstr ""
|
||||||
msgid "blog"
|
msgid "blog"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: blog/models.py:64
|
#: blog/models.py:83
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: blog/models.py:65
|
#: blog/models.py:84
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: blog/models.py:69
|
#: blog/models.py:88
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "markdown files are not supported yet - use markdown content instead"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: blog/models.py:71
|
#: blog/models.py:90
|
||||||
msgid ""
|
msgid ""
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: blog/models.py:82
|
#: blog/models.py:122
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: blog/models.py:83
|
#: blog/models.py:123
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: blog/models.py:87
|
#: blog/models.py:127
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: blog/models.py:88
|
#: blog/models.py:128
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: blog/models.py:96
|
#: blog/models.py:136
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: blog/models.py:97
|
#: blog/models.py:137
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||||
"Report-Msgid-Bugs-To: \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"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -17,56 +17,53 @@ msgstr ""
|
||||||
msgid "blog"
|
msgid "blog"
|
||||||
msgstr "Blog"
|
msgstr "Blog"
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "Titolo del post"
|
msgstr "Titolo del post"
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Titolo"
|
msgstr "Titolo"
|
||||||
|
|
||||||
#: blog/models.py:64
|
#: blog/models.py:83
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "Posta"
|
msgstr "Posta"
|
||||||
|
|
||||||
#: blog/models.py:65
|
#: blog/models.py:84
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "Messaggi"
|
msgstr "Messaggi"
|
||||||
|
|
||||||
#: blog/models.py:69
|
#: blog/models.py:88
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "markdown files are not supported yet - use markdown content instead"
|
||||||
msgstr "I file Markdown non sono supportati: usa invece i contenuti Markdown!"
|
msgstr "I file Markdown non sono supportati: usa invece i contenuti Markdown!"
|
||||||
|
|
||||||
#: blog/models.py:71
|
#: blog/models.py:90
|
||||||
msgid ""
|
msgid ""
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"deve essere fornito un file markdown o un contenuto markdown - si escludono "
|
"deve essere fornito un file markdown o un contenuto markdown - si escludono "
|
||||||
"a vicenda"
|
"a vicenda"
|
||||||
|
|
||||||
#: blog/models.py:82
|
#: blog/models.py:122
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "identificatore interno del tag post"
|
msgstr "identificatore interno del tag post"
|
||||||
|
|
||||||
#: blog/models.py:83
|
#: blog/models.py:123
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "Nome del tag"
|
msgstr "Nome del tag"
|
||||||
|
|
||||||
#: blog/models.py:87
|
#: blog/models.py:127
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "Nome intuitivo per il tag del post"
|
msgstr "Nome intuitivo per il tag del post"
|
||||||
|
|
||||||
#: blog/models.py:88
|
#: blog/models.py:128
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "Nome del tag"
|
msgstr "Nome del tag"
|
||||||
|
|
||||||
#: blog/models.py:96
|
#: blog/models.py:136
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "Post tag"
|
msgstr "Post tag"
|
||||||
|
|
||||||
#: blog/models.py:97
|
#: blog/models.py:137
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "Tag dei post"
|
msgstr "Tag dei post"
|
||||||
|
|
||||||
#~ msgid "eVibes Engine"
|
|
||||||
#~ msgstr "Motore eVibes"
|
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||||
"Report-Msgid-Bugs-To: \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"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -17,58 +17,55 @@ msgstr ""
|
||||||
msgid "blog"
|
msgid "blog"
|
||||||
msgstr "ブログ"
|
msgstr "ブログ"
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "投稿タイトル"
|
msgstr "投稿タイトル"
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "タイトル"
|
msgstr "タイトル"
|
||||||
|
|
||||||
#: blog/models.py:64
|
#: blog/models.py:83
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "ポスト"
|
msgstr "ポスト"
|
||||||
|
|
||||||
#: blog/models.py:65
|
#: blog/models.py:84
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "投稿"
|
msgstr "投稿"
|
||||||
|
|
||||||
#: blog/models.py:69
|
#: blog/models.py:88
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "markdown files are not supported yet - use markdown content instead"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"マークダウン・ファイルはサポートされていません - 代わりにマークダウン・コンテ"
|
"マークダウン・ファイルはサポートされていません - 代わりにマークダウン・コンテ"
|
||||||
"ンツを使用してください!"
|
"ンツを使用してください!"
|
||||||
|
|
||||||
#: blog/models.py:71
|
#: blog/models.py:90
|
||||||
msgid ""
|
msgid ""
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"マークダウン・ファイルまたはマークダウン・コンテンツを提供しなければならな"
|
"マークダウン・ファイルまたはマークダウン・コンテンツを提供しなければならな"
|
||||||
"い。"
|
"い。"
|
||||||
|
|
||||||
#: blog/models.py:82
|
#: blog/models.py:122
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "投稿タグの内部タグ識別子"
|
msgstr "投稿タグの内部タグ識別子"
|
||||||
|
|
||||||
#: blog/models.py:83
|
#: blog/models.py:123
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "タグ名"
|
msgstr "タグ名"
|
||||||
|
|
||||||
#: blog/models.py:87
|
#: blog/models.py:127
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "投稿タグのユーザーフレンドリーな名前"
|
msgstr "投稿タグのユーザーフレンドリーな名前"
|
||||||
|
|
||||||
#: blog/models.py:88
|
#: blog/models.py:128
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "タグ表示名"
|
msgstr "タグ表示名"
|
||||||
|
|
||||||
#: blog/models.py:96
|
#: blog/models.py:136
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "投稿タグ"
|
msgstr "投稿タグ"
|
||||||
|
|
||||||
#: blog/models.py:97
|
#: blog/models.py:137
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "投稿タグ"
|
msgstr "投稿タグ"
|
||||||
|
|
||||||
#~ msgid "eVibes Engine"
|
|
||||||
#~ msgstr "eVibesエンジン"
|
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -2,12 +2,12 @@
|
||||||
# Copyright (C) 2025 EGOR <FUREUNOIR> GORBUNOV
|
# Copyright (C) 2025 EGOR <FUREUNOIR> GORBUNOV
|
||||||
# This file is distributed under the same license as the EVIBES package.
|
# This file is distributed under the same license as the EVIBES package.
|
||||||
# EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>, 2025.
|
# EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>, 2025.
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||||
"Report-Msgid-Bugs-To: \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"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -20,51 +20,51 @@ msgstr ""
|
||||||
msgid "blog"
|
msgid "blog"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: blog/models.py:64
|
#: blog/models.py:83
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: blog/models.py:65
|
#: blog/models.py:84
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: blog/models.py:69
|
#: blog/models.py:88
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "markdown files are not supported yet - use markdown content instead"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: blog/models.py:71
|
#: blog/models.py:90
|
||||||
msgid ""
|
msgid ""
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: blog/models.py:82
|
#: blog/models.py:122
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: blog/models.py:83
|
#: blog/models.py:123
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: blog/models.py:87
|
#: blog/models.py:127
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: blog/models.py:88
|
#: blog/models.py:128
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: blog/models.py:96
|
#: blog/models.py:136
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: blog/models.py:97
|
#: blog/models.py:137
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||||
"Report-Msgid-Bugs-To: \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"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -17,58 +17,55 @@ msgstr ""
|
||||||
msgid "blog"
|
msgid "blog"
|
||||||
msgstr "Blog"
|
msgstr "Blog"
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "Titel van de post"
|
msgstr "Titel van de post"
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Titel"
|
msgstr "Titel"
|
||||||
|
|
||||||
#: blog/models.py:64
|
#: blog/models.py:83
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "Plaats"
|
msgstr "Plaats"
|
||||||
|
|
||||||
#: blog/models.py:65
|
#: blog/models.py:84
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "Berichten"
|
msgstr "Berichten"
|
||||||
|
|
||||||
#: blog/models.py:69
|
#: blog/models.py:88
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "markdown files are not supported yet - use markdown content instead"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Markdown-bestanden worden niet ondersteund - gebruik in plaats daarvan "
|
"Markdown-bestanden worden niet ondersteund - gebruik in plaats daarvan "
|
||||||
"markdown-inhoud!"
|
"markdown-inhoud!"
|
||||||
|
|
||||||
#: blog/models.py:71
|
#: blog/models.py:90
|
||||||
msgid ""
|
msgid ""
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"er moet een markdown-bestand of markdown-inhoud worden geleverd - wederzijds "
|
"er moet een markdown-bestand of markdown-inhoud worden geleverd - wederzijds "
|
||||||
"exclusief"
|
"exclusief"
|
||||||
|
|
||||||
#: blog/models.py:82
|
#: blog/models.py:122
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "interne tagidentifier voor de posttag"
|
msgstr "interne tagidentifier voor de posttag"
|
||||||
|
|
||||||
#: blog/models.py:83
|
#: blog/models.py:123
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "Tag naam"
|
msgstr "Tag naam"
|
||||||
|
|
||||||
#: blog/models.py:87
|
#: blog/models.py:127
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "Gebruiksvriendelijke naam voor de posttag"
|
msgstr "Gebruiksvriendelijke naam voor de posttag"
|
||||||
|
|
||||||
#: blog/models.py:88
|
#: blog/models.py:128
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "Tag weergavenaam"
|
msgstr "Tag weergavenaam"
|
||||||
|
|
||||||
#: blog/models.py:96
|
#: blog/models.py:136
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "Post tag"
|
msgstr "Post tag"
|
||||||
|
|
||||||
#: blog/models.py:97
|
#: blog/models.py:137
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "Post tags"
|
msgstr "Post tags"
|
||||||
|
|
||||||
#~ msgid "eVibes Engine"
|
|
||||||
#~ msgstr "eVibes motor"
|
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||||
"Report-Msgid-Bugs-To: \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"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -17,57 +17,54 @@ msgstr ""
|
||||||
msgid "blog"
|
msgid "blog"
|
||||||
msgstr "Blog"
|
msgstr "Blog"
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "Tytuł postu"
|
msgstr "Tytuł postu"
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Tytuł"
|
msgstr "Tytuł"
|
||||||
|
|
||||||
#: blog/models.py:64
|
#: blog/models.py:83
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "Post"
|
msgstr "Post"
|
||||||
|
|
||||||
#: blog/models.py:65
|
#: blog/models.py:84
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "Posty"
|
msgstr "Posty"
|
||||||
|
|
||||||
#: blog/models.py:69
|
#: blog/models.py:88
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "markdown files are not supported yet - use markdown content instead"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Pliki Markdown nie są obsługiwane - zamiast tego użyj zawartości Markdown!"
|
"Pliki Markdown nie są obsługiwane - zamiast tego użyj zawartości Markdown!"
|
||||||
|
|
||||||
#: blog/models.py:71
|
#: blog/models.py:90
|
||||||
msgid ""
|
msgid ""
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"należy dostarczyć plik markdown lub zawartość markdown - wzajemnie się "
|
"należy dostarczyć plik markdown lub zawartość markdown - wzajemnie się "
|
||||||
"wykluczające"
|
"wykluczające"
|
||||||
|
|
||||||
#: blog/models.py:82
|
#: blog/models.py:122
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "wewnętrzny identyfikator tagu posta"
|
msgstr "wewnętrzny identyfikator tagu posta"
|
||||||
|
|
||||||
#: blog/models.py:83
|
#: blog/models.py:123
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "Nazwa tagu"
|
msgstr "Nazwa tagu"
|
||||||
|
|
||||||
#: blog/models.py:87
|
#: blog/models.py:127
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "Przyjazna dla użytkownika nazwa tagu posta"
|
msgstr "Przyjazna dla użytkownika nazwa tagu posta"
|
||||||
|
|
||||||
#: blog/models.py:88
|
#: blog/models.py:128
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "Wyświetlana nazwa znacznika"
|
msgstr "Wyświetlana nazwa znacznika"
|
||||||
|
|
||||||
#: blog/models.py:96
|
#: blog/models.py:136
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "Tag posta"
|
msgstr "Tag posta"
|
||||||
|
|
||||||
#: blog/models.py:97
|
#: blog/models.py:137
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "Tagi postów"
|
msgstr "Tagi postów"
|
||||||
|
|
||||||
#~ msgid "eVibes Engine"
|
|
||||||
#~ msgstr "Silnik eVibes"
|
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||||
"Report-Msgid-Bugs-To: \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"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -17,56 +17,53 @@ msgstr ""
|
||||||
msgid "blog"
|
msgid "blog"
|
||||||
msgstr "Blog"
|
msgstr "Blog"
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "Título da postagem"
|
msgstr "Título da postagem"
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Título"
|
msgstr "Título"
|
||||||
|
|
||||||
#: blog/models.py:64
|
#: blog/models.py:83
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "Postar"
|
msgstr "Postar"
|
||||||
|
|
||||||
#: blog/models.py:65
|
#: blog/models.py:84
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "Publicações"
|
msgstr "Publicações"
|
||||||
|
|
||||||
#: blog/models.py:69
|
#: blog/models.py:88
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "markdown files are not supported yet - use markdown content instead"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Os arquivos markdown não são suportados - use conteúdo markdown em vez disso!"
|
"Os arquivos markdown não são suportados - use conteúdo markdown em vez disso!"
|
||||||
|
|
||||||
#: blog/models.py:71
|
#: blog/models.py:90
|
||||||
msgid ""
|
msgid ""
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"um arquivo ou conteúdo de markdown deve ser fornecido - mutuamente exclusivo"
|
"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"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "identificador de tag interno para a tag de postagem"
|
msgstr "identificador de tag interno para a tag de postagem"
|
||||||
|
|
||||||
#: blog/models.py:83
|
#: blog/models.py:123
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "Nome da etiqueta"
|
msgstr "Nome da etiqueta"
|
||||||
|
|
||||||
#: blog/models.py:87
|
#: blog/models.py:127
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "Nome de fácil utilização para a tag de postagem"
|
msgstr "Nome de fácil utilização para a tag de postagem"
|
||||||
|
|
||||||
#: blog/models.py:88
|
#: blog/models.py:128
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "Nome de exibição da tag"
|
msgstr "Nome de exibição da tag"
|
||||||
|
|
||||||
#: blog/models.py:96
|
#: blog/models.py:136
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "Etiqueta de postagem"
|
msgstr "Etiqueta de postagem"
|
||||||
|
|
||||||
#: blog/models.py:97
|
#: blog/models.py:137
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "Tags de postagem"
|
msgstr "Tags de postagem"
|
||||||
|
|
||||||
#~ msgid "eVibes Engine"
|
|
||||||
#~ msgstr "Motor eVibes"
|
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||||
"Report-Msgid-Bugs-To: \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"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -17,57 +17,54 @@ msgstr ""
|
||||||
msgid "blog"
|
msgid "blog"
|
||||||
msgstr "Blog"
|
msgstr "Blog"
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "Titlul postului"
|
msgstr "Titlul postului"
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Titlul"
|
msgstr "Titlul"
|
||||||
|
|
||||||
#: blog/models.py:64
|
#: blog/models.py:83
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "Post"
|
msgstr "Post"
|
||||||
|
|
||||||
#: blog/models.py:65
|
#: blog/models.py:84
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "Mesaje"
|
msgstr "Mesaje"
|
||||||
|
|
||||||
#: blog/models.py:69
|
#: blog/models.py:88
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "markdown files are not supported yet - use markdown content instead"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Fișierele Markdown nu sunt acceptate - utilizați în schimb conținut Markdown!"
|
"Fișierele Markdown nu sunt acceptate - utilizați în schimb conținut Markdown!"
|
||||||
|
|
||||||
#: blog/models.py:71
|
#: blog/models.py:90
|
||||||
msgid ""
|
msgid ""
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"trebuie furnizat un fișier markdown sau conținut markdown - se exclud "
|
"trebuie furnizat un fișier markdown sau conținut markdown - se exclud "
|
||||||
"reciproc"
|
"reciproc"
|
||||||
|
|
||||||
#: blog/models.py:82
|
#: blog/models.py:122
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "identificator intern de etichetă pentru eticheta postului"
|
msgstr "identificator intern de etichetă pentru eticheta postului"
|
||||||
|
|
||||||
#: blog/models.py:83
|
#: blog/models.py:123
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "Nume etichetă"
|
msgstr "Nume etichetă"
|
||||||
|
|
||||||
#: blog/models.py:87
|
#: blog/models.py:127
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "Nume ușor de utilizat pentru eticheta postului"
|
msgstr "Nume ușor de utilizat pentru eticheta postului"
|
||||||
|
|
||||||
#: blog/models.py:88
|
#: blog/models.py:128
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "Nume afișare etichetă"
|
msgstr "Nume afișare etichetă"
|
||||||
|
|
||||||
#: blog/models.py:96
|
#: blog/models.py:136
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "Etichetă post"
|
msgstr "Etichetă post"
|
||||||
|
|
||||||
#: blog/models.py:97
|
#: blog/models.py:137
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "Etichete poștale"
|
msgstr "Etichete poștale"
|
||||||
|
|
||||||
#~ msgid "eVibes Engine"
|
|
||||||
#~ msgstr "Motorul eVibes"
|
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||||
"Report-Msgid-Bugs-To: \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"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -17,58 +17,55 @@ msgstr ""
|
||||||
msgid "blog"
|
msgid "blog"
|
||||||
msgstr "Блог"
|
msgstr "Блог"
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "Заголовок сообщения"
|
msgstr "Заголовок сообщения"
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Название"
|
msgstr "Название"
|
||||||
|
|
||||||
#: blog/models.py:64
|
#: blog/models.py:83
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "Пост"
|
msgstr "Пост"
|
||||||
|
|
||||||
#: blog/models.py:65
|
#: blog/models.py:84
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "Посты"
|
msgstr "Посты"
|
||||||
|
|
||||||
#: blog/models.py:69
|
#: blog/models.py:88
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "markdown files are not supported yet - use markdown content instead"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Файлы в формате Markdown не поддерживаются - используйте вместо них "
|
"Файлы в формате Markdown не поддерживаются - используйте вместо них "
|
||||||
"содержимое в формате Markdown!"
|
"содержимое в формате Markdown!"
|
||||||
|
|
||||||
#: blog/models.py:71
|
#: blog/models.py:90
|
||||||
msgid ""
|
msgid ""
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"необходимо предоставить файл разметки или содержимое разметки - "
|
"необходимо предоставить файл разметки или содержимое разметки - "
|
||||||
"взаимоисключающие варианты"
|
"взаимоисключающие варианты"
|
||||||
|
|
||||||
#: blog/models.py:82
|
#: blog/models.py:122
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "внутренний идентификатор тега для тега post"
|
msgstr "внутренний идентификатор тега для тега post"
|
||||||
|
|
||||||
#: blog/models.py:83
|
#: blog/models.py:123
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "Название тега"
|
msgstr "Название тега"
|
||||||
|
|
||||||
#: blog/models.py:87
|
#: blog/models.py:127
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "Удобное для пользователя название тега поста"
|
msgstr "Удобное для пользователя название тега поста"
|
||||||
|
|
||||||
#: blog/models.py:88
|
#: blog/models.py:128
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "Отображаемое имя тега"
|
msgstr "Отображаемое имя тега"
|
||||||
|
|
||||||
#: blog/models.py:96
|
#: blog/models.py:136
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "Тэг поста"
|
msgstr "Тэг поста"
|
||||||
|
|
||||||
#: blog/models.py:97
|
#: blog/models.py:137
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "Тэги постов"
|
msgstr "Тэги постов"
|
||||||
|
|
||||||
#~ msgid "eVibes Engine"
|
|
||||||
#~ msgstr "Движок eVibes"
|
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -1,9 +1,9 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
"Project-Id-Version: EVIBES 2.9.2\n"
|
||||||
"Report-Msgid-Bugs-To: \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"
|
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
||||||
|
|
@ -17,54 +17,51 @@ msgstr ""
|
||||||
msgid "blog"
|
msgid "blog"
|
||||||
msgstr "博客"
|
msgstr "博客"
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "post title"
|
msgid "post title"
|
||||||
msgstr "帖子标题"
|
msgstr "帖子标题"
|
||||||
|
|
||||||
#: blog/models.py:17
|
#: blog/models.py:36
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "标题"
|
msgstr "标题"
|
||||||
|
|
||||||
#: blog/models.py:64
|
#: blog/models.py:83
|
||||||
msgid "post"
|
msgid "post"
|
||||||
msgstr "职位"
|
msgstr "职位"
|
||||||
|
|
||||||
#: blog/models.py:65
|
#: blog/models.py:84
|
||||||
msgid "posts"
|
msgid "posts"
|
||||||
msgstr "职位"
|
msgstr "职位"
|
||||||
|
|
||||||
#: blog/models.py:69
|
#: blog/models.py:88
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
msgid "markdown files are not supported yet - use markdown content instead"
|
||||||
msgstr "不支持 Markdown 文件,请使用 Markdown 内容!"
|
msgstr "不支持 Markdown 文件,请使用 Markdown 内容!"
|
||||||
|
|
||||||
#: blog/models.py:71
|
#: blog/models.py:90
|
||||||
msgid ""
|
msgid ""
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
"a markdown file or markdown content must be provided - mutually exclusive"
|
||||||
msgstr "必须提供标记符文件或标记符内容 - 相互排斥"
|
msgstr "必须提供标记符文件或标记符内容 - 相互排斥"
|
||||||
|
|
||||||
#: blog/models.py:82
|
#: blog/models.py:122
|
||||||
msgid "internal tag identifier for the post tag"
|
msgid "internal tag identifier for the post tag"
|
||||||
msgstr "职位标签的内部标签标识符"
|
msgstr "职位标签的内部标签标识符"
|
||||||
|
|
||||||
#: blog/models.py:83
|
#: blog/models.py:123
|
||||||
msgid "tag name"
|
msgid "tag name"
|
||||||
msgstr "标签名称"
|
msgstr "标签名称"
|
||||||
|
|
||||||
#: blog/models.py:87
|
#: blog/models.py:127
|
||||||
msgid "user-friendly name for the post tag"
|
msgid "user-friendly name for the post tag"
|
||||||
msgstr "方便用户使用的帖子标签名称"
|
msgstr "方便用户使用的帖子标签名称"
|
||||||
|
|
||||||
#: blog/models.py:88
|
#: blog/models.py:128
|
||||||
msgid "tag display name"
|
msgid "tag display name"
|
||||||
msgstr "标签显示名称"
|
msgstr "标签显示名称"
|
||||||
|
|
||||||
#: blog/models.py:96
|
#: blog/models.py:136
|
||||||
msgid "post tag"
|
msgid "post tag"
|
||||||
msgstr "职位标签"
|
msgstr "职位标签"
|
||||||
|
|
||||||
#: blog/models.py:97
|
#: blog/models.py:137
|
||||||
msgid "post tags"
|
msgid "post tags"
|
||||||
msgstr "帖子标签"
|
msgstr "帖子标签"
|
||||||
|
|
||||||
#~ msgid "eVibes Engine"
|
|
||||||
#~ msgstr "eVibes 引擎"
|
|
||||||
|
|
|
||||||
|
|
@ -18,56 +18,113 @@ class Migration(migrations.Migration):
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='PostTag',
|
name="PostTag",
|
||||||
fields=[
|
fields=[
|
||||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
|
(
|
||||||
help_text='unique id is used to surely identify any database object',
|
"uuid",
|
||||||
primary_key=True, serialize=False, verbose_name='unique id')),
|
models.UUIDField(
|
||||||
('is_active', models.BooleanField(default=True,
|
default=uuid.uuid4,
|
||||||
help_text="if set to false, this object can't be seen by users without needed permission",
|
editable=False,
|
||||||
verbose_name='is active')),
|
help_text="unique id is used to surely identify any database object",
|
||||||
('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True,
|
primary_key=True,
|
||||||
help_text='when the object first appeared on the database',
|
serialize=False,
|
||||||
verbose_name='created')),
|
verbose_name="unique id",
|
||||||
('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,
|
"is_active",
|
||||||
verbose_name='tag name')),
|
models.BooleanField(
|
||||||
('name', models.CharField(help_text='user-friendly name for the post tag', max_length=255, unique=True,
|
default=True,
|
||||||
verbose_name='tag display name')),
|
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",
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'post tag',
|
"verbose_name": "post tag",
|
||||||
'verbose_name_plural': 'post tags',
|
"verbose_name_plural": "post tags",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Post',
|
name="Post",
|
||||||
fields=[
|
fields=[
|
||||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
|
(
|
||||||
help_text='unique id is used to surely identify any database object',
|
"uuid",
|
||||||
primary_key=True, serialize=False, verbose_name='unique id')),
|
models.UUIDField(
|
||||||
('is_active', models.BooleanField(default=True,
|
default=uuid.uuid4,
|
||||||
help_text="if set to false, this object can't be seen by users without needed permission",
|
editable=False,
|
||||||
verbose_name='is active')),
|
help_text="unique id is used to surely identify any database object",
|
||||||
('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True,
|
primary_key=True,
|
||||||
help_text='when the object first appeared on the database',
|
serialize=False,
|
||||||
verbose_name='created')),
|
verbose_name="unique id",
|
||||||
('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True,
|
),
|
||||||
help_text='when the object was last modified',
|
),
|
||||||
verbose_name='modified')),
|
(
|
||||||
('title', models.CharField()),
|
"is_active",
|
||||||
('content', markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name='content')),
|
models.BooleanField(
|
||||||
('file', models.FileField(blank=True, null=True, upload_to='posts/')),
|
default=True,
|
||||||
('slug', models.SlugField(allow_unicode=True)),
|
help_text="if set to false, this object can't be seen by users without needed permission",
|
||||||
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='posts',
|
verbose_name="is active",
|
||||||
to=settings.AUTH_USER_MODEL)),
|
),
|
||||||
('tags', models.ManyToManyField(to='blog.posttag')),
|
),
|
||||||
|
(
|
||||||
|
"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={
|
options={
|
||||||
'verbose_name': 'post',
|
"verbose_name": "post",
|
||||||
'verbose_name_plural': 'posts',
|
"verbose_name_plural": "posts",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -5,20 +5,21 @@ from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('blog', '0001_initial'),
|
("blog", "0001_initial"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='post',
|
model_name="post",
|
||||||
name='slug',
|
name="slug",
|
||||||
field=django_extensions.db.fields.AutoSlugField(allow_unicode=True, blank=True, editable=False, populate_from='title', unique=True),
|
field=django_extensions.db.fields.AutoSlugField(
|
||||||
|
allow_unicode=True, blank=True, editable=False, populate_from="title", unique=True
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='post',
|
model_name="post",
|
||||||
name='title',
|
name="title",
|
||||||
field=models.CharField(help_text='post title', max_length=128, unique=True, verbose_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):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('blog', '0002_alter_post_slug_alter_post_title'),
|
("blog", "0002_alter_post_slug_alter_post_title"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='post',
|
model_name="post",
|
||||||
name='tags',
|
name="tags",
|
||||||
field=models.ManyToManyField(blank=True, related_name='posts', to='blog.posttag'),
|
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
|
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
|
is_publicly_visible = True
|
||||||
|
|
||||||
author: ForeignKey = ForeignKey(
|
author = ForeignKey(to="vibes_auth.User", on_delete=CASCADE, blank=False, null=False, related_name="posts")
|
||||||
to="vibes_auth.User", on_delete=CASCADE, blank=False, null=False, related_name="posts"
|
title = CharField(
|
||||||
)
|
|
||||||
title: CharField = CharField(
|
|
||||||
unique=True, max_length=128, blank=False, null=False, help_text=_("post title"), verbose_name=_("title")
|
unique=True, max_length=128, blank=False, null=False, help_text=_("post title"), verbose_name=_("title")
|
||||||
)
|
)
|
||||||
content: MarkdownField = MarkdownField(
|
content: MarkdownField = MarkdownField(
|
||||||
|
|
@ -53,9 +72,9 @@ class Post(NiceModel):
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
)
|
)
|
||||||
file: FileField = FileField(upload_to="posts/", blank=True, null=True)
|
file = FileField(upload_to="posts/", blank=True, null=True)
|
||||||
slug: AutoSlugField = AutoSlugField(populate_from="title", allow_unicode=True, unique=True, editable=False)
|
slug = AutoSlugField(populate_from="title", allow_unicode=True, unique=True, editable=False)
|
||||||
tags: ManyToManyField = ManyToManyField(to="blog.PostTag", blank=True, related_name="posts")
|
tags = ManyToManyField(to="blog.PostTag", blank=True, related_name="posts")
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.title} | {self.author.first_name} {self.author.last_name}"
|
return f"{self.title} | {self.author.first_name} {self.author.last_name}"
|
||||||
|
|
@ -73,16 +92,37 @@ class Post(NiceModel):
|
||||||
|
|
||||||
|
|
||||||
class PostTag(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,
|
blank=False,
|
||||||
null=False,
|
null=False,
|
||||||
max_length=255,
|
max_length=255,
|
||||||
help_text=_("internal tag identifier for the post tag"),
|
help_text=_("internal tag identifier for the post tag"),
|
||||||
verbose_name=_("tag name"),
|
verbose_name=_("tag name"),
|
||||||
)
|
)
|
||||||
name: CharField = CharField(
|
name = CharField(
|
||||||
max_length=255,
|
max_length=255,
|
||||||
help_text=_("user-friendly name for the post tag"),
|
help_text=_("user-friendly name for the post tag"),
|
||||||
verbose_name=_("tag display name"),
|
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
|
from blog.viewsets import PostViewSet
|
||||||
|
|
||||||
|
app_name = "blog"
|
||||||
|
|
||||||
payment_router = DefaultRouter()
|
payment_router = DefaultRouter()
|
||||||
payment_router.register(prefix=r"posts", viewset=PostViewSet, basename="posts")
|
payment_router.register(prefix=r"posts", viewset=PostViewSet, basename="posts")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger("django")
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,22 @@ from core.permissions import EvibesPermission
|
||||||
|
|
||||||
|
|
||||||
class PostViewSet(ReadOnlyModelViewSet):
|
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
|
serializer_class = PostSerializer
|
||||||
permission_classes = (EvibesPermission,)
|
permission_classes = (EvibesPermission,)
|
||||||
queryset = Post.objects.filter(is_active=True)
|
queryset = Post.objects.filter(is_active=True)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import uuid
|
import uuid
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
from django.db.models import BooleanField, Model, UUIDField
|
from django.db.models import BooleanField, Model, UUIDField
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
@ -7,32 +6,24 @@ from django_extensions.db.fields import CreationDateTimeField, ModificationDateT
|
||||||
|
|
||||||
|
|
||||||
class NiceModel(Model):
|
class NiceModel(Model):
|
||||||
id = None
|
id: None = None
|
||||||
uuid: uuid = UUIDField( # type: ignore
|
uuid = UUIDField(
|
||||||
verbose_name=_("unique id"),
|
verbose_name=_("unique id"),
|
||||||
help_text=_("unique id is used to surely identify any database object"),
|
help_text=_("unique id is used to surely identify any database object"),
|
||||||
primary_key=True,
|
primary_key=True,
|
||||||
default=uuid.uuid4,
|
default=uuid.uuid4,
|
||||||
editable=False,
|
editable=False,
|
||||||
)
|
)
|
||||||
is_active: bool = BooleanField( # type: ignore
|
is_active = BooleanField(
|
||||||
default=True,
|
default=True,
|
||||||
verbose_name=_("is active"),
|
verbose_name=_("is active"),
|
||||||
help_text=_(
|
help_text=_("if set to false, this object can't be seen by users without needed permission"),
|
||||||
"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")
|
|
||||||
)
|
)
|
||||||
|
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):
|
def save(self, **kwargs):
|
||||||
self.update_modified = kwargs.pop(
|
self.update_modified = kwargs.pop("update_modified", getattr(self, "update_modified", True))
|
||||||
"update_modified", getattr(self, "update_modified", True)
|
|
||||||
)
|
|
||||||
super().save(**kwargs)
|
super().save(**kwargs)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
||||||
243
core/admin.py
243
core/admin.py
|
|
@ -1,21 +1,20 @@
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
|
from typing import ClassVar, Type
|
||||||
|
|
||||||
from constance.admin import Config
|
from constance.admin import Config
|
||||||
from constance.admin import ConstanceAdmin as BaseConstanceAdmin
|
from constance.admin import ConstanceAdmin as BaseConstanceAdmin
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.contrib import admin
|
from django.contrib.admin import ModelAdmin, TabularInline, action, register, site
|
||||||
from django.contrib.admin import ModelAdmin, TabularInline
|
|
||||||
from django.contrib.gis.admin import GISModelAdmin
|
from django.contrib.gis.admin import GISModelAdmin
|
||||||
|
from django.contrib.messages import constants as messages
|
||||||
from django.db.models import Model
|
from django.db.models import Model
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from modeltranslation.translator import NotRegistered, translator
|
from modeltranslation.translator import NotRegistered, translator
|
||||||
from modeltranslation.utils import get_translation_fields
|
from modeltranslation.utils import get_translation_fields
|
||||||
from mptt.admin import DraggableMPTTAdmin
|
from mptt.admin import DraggableMPTTAdmin
|
||||||
|
|
||||||
from evibes.settings import CONSTANCE_CONFIG
|
from core.forms import OrderForm, OrderProductForm, VendorForm
|
||||||
|
from core.models import (
|
||||||
from .forms import OrderForm, OrderProductForm, VendorForm
|
|
||||||
from .models import (
|
|
||||||
Address,
|
Address,
|
||||||
Attribute,
|
Attribute,
|
||||||
AttributeGroup,
|
AttributeGroup,
|
||||||
|
|
@ -35,14 +34,21 @@ from .models import (
|
||||||
Vendor,
|
Vendor,
|
||||||
Wishlist,
|
Wishlist,
|
||||||
)
|
)
|
||||||
|
from evibes.settings import CONSTANCE_CONFIG
|
||||||
|
|
||||||
|
|
||||||
class FieldsetsMixin:
|
class FieldsetsMixin:
|
||||||
general_fields: list = []
|
general_fields: list = []
|
||||||
relation_fields: list = []
|
relation_fields: list = []
|
||||||
model: Model
|
model: ClassVar[Type[Model]]
|
||||||
|
|
||||||
def get_fieldsets(self, request, obj=None):
|
def get_fieldsets(self, request, obj=None):
|
||||||
|
if request:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if obj:
|
||||||
|
pass
|
||||||
|
|
||||||
fieldsets = []
|
fieldsets = []
|
||||||
|
|
||||||
def add_translations_fieldset(fss):
|
def add_translations_fieldset(fss):
|
||||||
|
|
@ -52,9 +58,7 @@ class FieldsetsMixin:
|
||||||
for orig in transoptions.local_fields:
|
for orig in transoptions.local_fields:
|
||||||
translation_fields += get_translation_fields(orig)
|
translation_fields += get_translation_fields(orig)
|
||||||
if translation_fields:
|
if translation_fields:
|
||||||
fss = list(fss) + [
|
fss = list(fss) + [(_("translations"), {"fields": translation_fields})]
|
||||||
(_("translations"), {"fields": translation_fields})
|
|
||||||
]
|
|
||||||
return fss
|
return fss
|
||||||
|
|
||||||
if self.general_fields:
|
if self.general_fields:
|
||||||
|
|
@ -79,34 +83,37 @@ class FieldsetsMixin:
|
||||||
return fieldsets
|
return fieldsets
|
||||||
|
|
||||||
|
|
||||||
class BasicModelAdmin(ModelAdmin):
|
# noinspection PyUnresolvedReferences
|
||||||
@admin.action(description=str(_("activate selected %(verbose_name_plural)s")))
|
class ActivationActionsMixin:
|
||||||
def activate_selected(self, request, queryset) -> str:
|
actions_on_top = True
|
||||||
if request:
|
actions_on_bottom = True
|
||||||
pass
|
actions = [
|
||||||
queryset.update(is_active=True)
|
"delete_selected",
|
||||||
return str(_("%(verbose_name_plural)s activated successfully!"))
|
"activate_selected",
|
||||||
|
"deactivate_selected",
|
||||||
|
]
|
||||||
|
|
||||||
@admin.action(description=str(_("deactivate selected %(verbose_name_plural)s")))
|
@action(description=_("activate selected %(verbose_name_plural)s").lower(), permissions=["change"])
|
||||||
def deactivate_selected(self, request, queryset) -> str:
|
def activate_selected(self, request, queryset):
|
||||||
if request:
|
try:
|
||||||
pass
|
queryset.update(is_active=True)
|
||||||
queryset.update(is_active=False)
|
self.message_user(
|
||||||
return str(_("%(verbose_name_plural)s deactivated successfully."))
|
request=request, message=_("selected items have been activated.").lower(), level=messages.SUCCESS
|
||||||
|
)
|
||||||
|
|
||||||
def get_actions(self, request):
|
except Exception as e:
|
||||||
actions = super().get_actions(request)
|
self.message_user(request=request, message=str(e), level=messages.ERROR)
|
||||||
actions["activate_selected"] = (
|
|
||||||
self.activate_selected,
|
@action(description=_("deactivate selected %(verbose_name_plural)s").lower(), permissions=["change"])
|
||||||
"activate_selected",
|
def deactivate_selected(self, request, queryset):
|
||||||
str(_("activate selected %(verbose_name_plural)s")),
|
try:
|
||||||
)
|
queryset.update(is_active=False)
|
||||||
actions["deactivate_selected"] = (
|
self.message_user(
|
||||||
self.deactivate_selected,
|
request=request, message=_("selected items have been deactivated.").lower(), level=messages.SUCCESS
|
||||||
"deactivate_selected",
|
)
|
||||||
str(_("deactivate selected %(verbose_name_plural)s")),
|
|
||||||
)
|
except Exception as e:
|
||||||
return actions
|
self.message_user(request=request, message=str(e), level=messages.ERROR)
|
||||||
|
|
||||||
|
|
||||||
class AttributeValueInline(TabularInline):
|
class AttributeValueInline(TabularInline):
|
||||||
|
|
@ -148,12 +155,7 @@ class OrderProductInline(TabularInline):
|
||||||
icon = "fa-solid fa-boxes-packing"
|
icon = "fa-solid fa-boxes-packing"
|
||||||
|
|
||||||
def get_queryset(self, request):
|
def get_queryset(self, request):
|
||||||
return (
|
return super().get_queryset(request).select_related("product").only("product__name")
|
||||||
super()
|
|
||||||
.get_queryset(request)
|
|
||||||
.select_related("product")
|
|
||||||
.only("product__name")
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class CategoryChildrenInline(TabularInline):
|
class CategoryChildrenInline(TabularInline):
|
||||||
|
|
@ -167,9 +169,10 @@ class CategoryChildrenInline(TabularInline):
|
||||||
icon = "fa-solid fa-leaf"
|
icon = "fa-solid fa-leaf"
|
||||||
|
|
||||||
|
|
||||||
@admin.register(AttributeGroup)
|
@register(AttributeGroup)
|
||||||
class AttributeGroupAdmin(FieldsetsMixin, BasicModelAdmin):
|
class AttributeGroupAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||||
model = AttributeGroup # type: ignore
|
# noinspection PyClassVar
|
||||||
|
model = AttributeGroup # type: ignore [misc]
|
||||||
list_display = ("name", "modified")
|
list_display = ("name", "modified")
|
||||||
search_fields = ("uuid", "name")
|
search_fields = ("uuid", "name")
|
||||||
readonly_fields = ("uuid", "modified", "created")
|
readonly_fields = ("uuid", "modified", "created")
|
||||||
|
|
@ -178,9 +181,10 @@ class AttributeGroupAdmin(FieldsetsMixin, BasicModelAdmin):
|
||||||
relation_fields = []
|
relation_fields = []
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Attribute)
|
@register(Attribute)
|
||||||
class AttributeAdmin(FieldsetsMixin, BasicModelAdmin):
|
class AttributeAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||||
model = Attribute # type: ignore
|
# noinspection PyClassVar
|
||||||
|
model = Attribute # type: ignore [misc]
|
||||||
list_display = ("name", "group", "value_type", "modified")
|
list_display = ("name", "group", "value_type", "modified")
|
||||||
list_filter = ("value_type", "group", "is_active")
|
list_filter = ("value_type", "group", "is_active")
|
||||||
search_fields = ("uuid", "name", "group__name")
|
search_fields = ("uuid", "name", "group__name")
|
||||||
|
|
@ -191,9 +195,10 @@ class AttributeAdmin(FieldsetsMixin, BasicModelAdmin):
|
||||||
relation_fields = ["group", "categories"]
|
relation_fields = ["group", "categories"]
|
||||||
|
|
||||||
|
|
||||||
@admin.register(AttributeValue)
|
@register(AttributeValue)
|
||||||
class AttributeValueAdmin(FieldsetsMixin, BasicModelAdmin):
|
class AttributeValueAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||||
model = AttributeValue # type: ignore
|
# noinspection PyClassVar
|
||||||
|
model = AttributeValue # type: ignore [misc]
|
||||||
list_display = ("attribute", "value", "modified")
|
list_display = ("attribute", "value", "modified")
|
||||||
list_filter = ("attribute__group", "is_active")
|
list_filter = ("attribute__group", "is_active")
|
||||||
search_fields = ("uuid", "value", "attribute__name")
|
search_fields = ("uuid", "value", "attribute__name")
|
||||||
|
|
@ -204,35 +209,39 @@ class AttributeValueAdmin(FieldsetsMixin, BasicModelAdmin):
|
||||||
relation_fields = ["attribute", "product"]
|
relation_fields = ["attribute", "product"]
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Category)
|
@register(Category)
|
||||||
class CategoryAdmin(FieldsetsMixin, DraggableMPTTAdmin, BasicModelAdmin):
|
class CategoryAdmin(FieldsetsMixin, ActivationActionsMixin, DraggableMPTTAdmin):
|
||||||
model = Category # type: ignore
|
# noinspection PyClassVar
|
||||||
|
model = Category
|
||||||
list_display = ("indented_title", "parent", "is_active", "modified")
|
list_display = ("indented_title", "parent", "is_active", "modified")
|
||||||
|
# noinspection PyUnresolvedReferences
|
||||||
list_filter = ("is_active", "level", "created", "modified")
|
list_filter = ("is_active", "level", "created", "modified")
|
||||||
search_fields = ("uuid", "name")
|
search_fields = ("uuid", "name")
|
||||||
inlines = [CategoryChildrenInline]
|
inlines = [CategoryChildrenInline]
|
||||||
autocomplete_fields = ["parent", "tags"]
|
autocomplete_fields = ["parent", "tags"]
|
||||||
readonly_fields = ("slug", "uuid", "modified", "created")
|
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"]
|
relation_fields = ["parent", "tags"]
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Brand)
|
@register(Brand)
|
||||||
class BrandAdmin(FieldsetsMixin, BasicModelAdmin):
|
class BrandAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||||
model = Brand # type: ignore
|
# noinspection PyClassVar
|
||||||
|
model = Brand # type: ignore [misc]
|
||||||
list_display = ("name",)
|
list_display = ("name",)
|
||||||
list_filter = ("categories", "is_active")
|
list_filter = ("categories", "is_active")
|
||||||
search_fields = ("uuid", "name", "categories__name")
|
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"]
|
relation_fields = ["small_logo", "big_logo", "categories"]
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Product)
|
@register(Product)
|
||||||
class ProductAdmin(FieldsetsMixin, BasicModelAdmin):
|
class ProductAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||||
model = Product # type: ignore
|
# noinspection PyClassVar
|
||||||
|
model = Product # type: ignore [misc]
|
||||||
list_display = (
|
list_display = (
|
||||||
"name",
|
"name",
|
||||||
"partnumber",
|
"partnumber",
|
||||||
|
|
@ -246,8 +255,8 @@ class ProductAdmin(FieldsetsMixin, BasicModelAdmin):
|
||||||
list_filter = (
|
list_filter = (
|
||||||
"is_active",
|
"is_active",
|
||||||
"is_digital",
|
"is_digital",
|
||||||
("tags", admin.RelatedOnlyFieldListFilter),
|
"stocks__vendor",
|
||||||
("stocks__vendor", admin.RelatedOnlyFieldListFilter),
|
"tags__name",
|
||||||
"created",
|
"created",
|
||||||
"modified",
|
"modified",
|
||||||
)
|
)
|
||||||
|
|
@ -255,7 +264,9 @@ class ProductAdmin(FieldsetsMixin, BasicModelAdmin):
|
||||||
"name",
|
"name",
|
||||||
"partnumber",
|
"partnumber",
|
||||||
"brand__name",
|
"brand__name",
|
||||||
|
"brand__slug",
|
||||||
"category__name",
|
"category__name",
|
||||||
|
"category__slug",
|
||||||
"uuid",
|
"uuid",
|
||||||
"slug",
|
"slug",
|
||||||
)
|
)
|
||||||
|
|
@ -263,13 +274,14 @@ class ProductAdmin(FieldsetsMixin, BasicModelAdmin):
|
||||||
autocomplete_fields = ("category", "brand", "tags")
|
autocomplete_fields = ("category", "brand", "tags")
|
||||||
inlines = [AttributeValueInline, ProductImageInline, StockInline]
|
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"]
|
relation_fields = ["category", "brand", "tags"]
|
||||||
|
|
||||||
|
|
||||||
@admin.register(ProductTag)
|
@register(ProductTag)
|
||||||
class ProductTagAdmin(FieldsetsMixin, BasicModelAdmin):
|
class ProductTagAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||||
model = ProductTag # type: ignore
|
# noinspection PyClassVar
|
||||||
|
model = ProductTag # type: ignore [misc]
|
||||||
list_display = ("tag_name",)
|
list_display = ("tag_name",)
|
||||||
search_fields = ("tag_name",)
|
search_fields = ("tag_name",)
|
||||||
readonly_fields = ("uuid", "modified", "created")
|
readonly_fields = ("uuid", "modified", "created")
|
||||||
|
|
@ -278,9 +290,10 @@ class ProductTagAdmin(FieldsetsMixin, BasicModelAdmin):
|
||||||
relation_fields = []
|
relation_fields = []
|
||||||
|
|
||||||
|
|
||||||
@admin.register(CategoryTag)
|
@register(CategoryTag)
|
||||||
class CategoryTagAdmin(FieldsetsMixin, BasicModelAdmin):
|
class CategoryTagAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||||
model = CategoryTag # type: ignore
|
# noinspection PyClassVar
|
||||||
|
model = CategoryTag # type: ignore [misc]
|
||||||
list_display = ("tag_name",)
|
list_display = ("tag_name",)
|
||||||
search_fields = ("tag_name",)
|
search_fields = ("tag_name",)
|
||||||
readonly_fields = ("uuid", "modified", "created")
|
readonly_fields = ("uuid", "modified", "created")
|
||||||
|
|
@ -289,22 +302,24 @@ class CategoryTagAdmin(FieldsetsMixin, BasicModelAdmin):
|
||||||
relation_fields = []
|
relation_fields = []
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Vendor)
|
@register(Vendor)
|
||||||
class VendorAdmin(FieldsetsMixin, BasicModelAdmin):
|
class VendorAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||||
model = Vendor # type: ignore
|
# noinspection PyClassVar
|
||||||
|
model = Vendor # type: ignore [misc]
|
||||||
list_display = ("name", "markup_percent", "modified")
|
list_display = ("name", "markup_percent", "modified")
|
||||||
list_filter = ("markup_percent", "is_active")
|
list_filter = ("markup_percent", "is_active")
|
||||||
search_fields = ("name",)
|
search_fields = ("name",)
|
||||||
readonly_fields = ("uuid", "modified", "created")
|
readonly_fields = ("uuid", "modified", "created")
|
||||||
form = VendorForm
|
form = VendorForm
|
||||||
|
|
||||||
general_fields = ["is_active", "name", "markup_percent", "authentication"]
|
general_fields = ["is_active", "name", "markup_percent", "authentication", "b2b_auth_token"]
|
||||||
relation_fields = []
|
relation_fields = ["users"]
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Feedback)
|
@register(Feedback)
|
||||||
class FeedbackAdmin(FieldsetsMixin, BasicModelAdmin):
|
class FeedbackAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||||
model = Feedback # type: ignore
|
# noinspection PyClassVar
|
||||||
|
model = Feedback # type: ignore [misc]
|
||||||
list_display = ("order_product", "rating", "comment", "modified")
|
list_display = ("order_product", "rating", "comment", "modified")
|
||||||
list_filter = ("rating", "is_active")
|
list_filter = ("rating", "is_active")
|
||||||
search_fields = ("order_product__product__name", "comment")
|
search_fields = ("order_product__product__name", "comment")
|
||||||
|
|
@ -314,9 +329,10 @@ class FeedbackAdmin(FieldsetsMixin, BasicModelAdmin):
|
||||||
relation_fields = ["order_product"]
|
relation_fields = ["order_product"]
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Order)
|
@register(Order)
|
||||||
class OrderAdmin(FieldsetsMixin, BasicModelAdmin):
|
class OrderAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||||
model = Order # type: ignore
|
# noinspection PyClassVar
|
||||||
|
model = Order # type: ignore [misc]
|
||||||
list_display = (
|
list_display = (
|
||||||
"human_readable_id",
|
"human_readable_id",
|
||||||
"user",
|
"user",
|
||||||
|
|
@ -338,13 +354,14 @@ class OrderAdmin(FieldsetsMixin, BasicModelAdmin):
|
||||||
inlines = [OrderProductInline]
|
inlines = [OrderProductInline]
|
||||||
form = OrderForm
|
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"]
|
relation_fields = ["promo_code", "billing_address", "shipping_address"]
|
||||||
|
|
||||||
|
|
||||||
@admin.register(OrderProduct)
|
@register(OrderProduct)
|
||||||
class OrderProductAdmin(FieldsetsMixin, BasicModelAdmin):
|
class OrderProductAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||||
model = OrderProduct # type: ignore
|
# noinspection PyClassVar
|
||||||
|
model = OrderProduct # type: ignore [misc]
|
||||||
list_display = ("order", "product", "quantity", "buy_price", "status", "modified")
|
list_display = ("order", "product", "quantity", "buy_price", "status", "modified")
|
||||||
list_filter = ("status",)
|
list_filter = ("status",)
|
||||||
search_fields = ("order__user__email", "product__name")
|
search_fields = ("order__user__email", "product__name")
|
||||||
|
|
@ -355,9 +372,10 @@ class OrderProductAdmin(FieldsetsMixin, BasicModelAdmin):
|
||||||
relation_fields = ["order", "product"]
|
relation_fields = ["order", "product"]
|
||||||
|
|
||||||
|
|
||||||
@admin.register(PromoCode)
|
@register(PromoCode)
|
||||||
class PromoCodeAdmin(FieldsetsMixin, BasicModelAdmin):
|
class PromoCodeAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||||
model = PromoCode # type: ignore
|
# noinspection PyClassVar
|
||||||
|
model = PromoCode # type: ignore [misc]
|
||||||
list_display = (
|
list_display = (
|
||||||
"code",
|
"code",
|
||||||
"discount_percent",
|
"discount_percent",
|
||||||
|
|
@ -383,9 +401,10 @@ class PromoCodeAdmin(FieldsetsMixin, BasicModelAdmin):
|
||||||
relation_fields = ["user"]
|
relation_fields = ["user"]
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Promotion)
|
@register(Promotion)
|
||||||
class PromotionAdmin(FieldsetsMixin, BasicModelAdmin):
|
class PromotionAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||||
model = Promotion # type: ignore
|
# noinspection PyClassVar
|
||||||
|
model = Promotion # type: ignore [misc]
|
||||||
list_display = ("name", "discount_percent", "modified")
|
list_display = ("name", "discount_percent", "modified")
|
||||||
search_fields = ("name",)
|
search_fields = ("name",)
|
||||||
readonly_fields = ("uuid", "modified", "created")
|
readonly_fields = ("uuid", "modified", "created")
|
||||||
|
|
@ -395,9 +414,10 @@ class PromotionAdmin(FieldsetsMixin, BasicModelAdmin):
|
||||||
relation_fields = ["products"]
|
relation_fields = ["products"]
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Stock)
|
@register(Stock)
|
||||||
class StockAdmin(FieldsetsMixin, BasicModelAdmin):
|
class StockAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||||
model = Stock # type: ignore
|
# noinspection PyClassVar
|
||||||
|
model = Stock # type: ignore [misc]
|
||||||
list_display = ("product", "vendor", "sku", "quantity", "price", "modified")
|
list_display = ("product", "vendor", "sku", "quantity", "price", "modified")
|
||||||
list_filter = ("vendor", "quantity")
|
list_filter = ("vendor", "quantity")
|
||||||
search_fields = ("product__name", "vendor__name", "sku")
|
search_fields = ("product__name", "vendor__name", "sku")
|
||||||
|
|
@ -415,9 +435,10 @@ class StockAdmin(FieldsetsMixin, BasicModelAdmin):
|
||||||
relation_fields = ["product", "vendor"]
|
relation_fields = ["product", "vendor"]
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Wishlist)
|
@register(Wishlist)
|
||||||
class WishlistAdmin(FieldsetsMixin, BasicModelAdmin):
|
class WishlistAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||||
model = Wishlist # type: ignore
|
# noinspection PyClassVar
|
||||||
|
model = Wishlist # type: ignore [misc]
|
||||||
list_display = ("user", "modified")
|
list_display = ("user", "modified")
|
||||||
search_fields = ("user__email",)
|
search_fields = ("user__email",)
|
||||||
readonly_fields = ("uuid", "modified", "created")
|
readonly_fields = ("uuid", "modified", "created")
|
||||||
|
|
@ -426,9 +447,10 @@ class WishlistAdmin(FieldsetsMixin, BasicModelAdmin):
|
||||||
relation_fields = ["products"]
|
relation_fields = ["products"]
|
||||||
|
|
||||||
|
|
||||||
@admin.register(ProductImage)
|
@register(ProductImage)
|
||||||
class ProductImageAdmin(FieldsetsMixin, BasicModelAdmin):
|
class ProductImageAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
|
||||||
model = ProductImage # type: ignore
|
# noinspection PyClassVar
|
||||||
|
model = ProductImage # type: ignore [misc]
|
||||||
list_display = ("alt", "product", "priority", "modified")
|
list_display = ("alt", "product", "priority", "modified")
|
||||||
list_filter = ("priority",)
|
list_filter = ("priority",)
|
||||||
search_fields = ("alt", "product__name")
|
search_fields = ("alt", "product__name")
|
||||||
|
|
@ -439,9 +461,10 @@ class ProductImageAdmin(FieldsetsMixin, BasicModelAdmin):
|
||||||
relation_fields = ["product"]
|
relation_fields = ["product"]
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Address)
|
@register(Address)
|
||||||
class AddressAdmin(FieldsetsMixin, GISModelAdmin):
|
class AddressAdmin(FieldsetsMixin, GISModelAdmin):
|
||||||
model = Address # type: ignore
|
# noinspection PyClassVar
|
||||||
|
model = Address # type: ignore [misc]
|
||||||
list_display = ("street", "city", "region", "country", "user")
|
list_display = ("street", "city", "region", "country", "user")
|
||||||
list_filter = ("country", "region")
|
list_filter = ("country", "region")
|
||||||
search_fields = ("street", "city", "postal_code", "user__email")
|
search_fields = ("street", "city", "postal_code", "user__email")
|
||||||
|
|
@ -501,8 +524,10 @@ class ConstanceConfig:
|
||||||
_meta = Meta()
|
_meta = Meta()
|
||||||
|
|
||||||
|
|
||||||
admin.site.unregister([Config]) # type: ignore
|
# noinspection PyTypeChecker
|
||||||
admin.site.register([ConstanceConfig], BaseConstanceAdmin) # type: ignore
|
site.unregister([Config])
|
||||||
admin.site.site_title = CONSTANCE_CONFIG["PROJECT_NAME"][0] # type: ignore
|
# noinspection PyTypeChecker
|
||||||
admin.site.site_header = "eVibes"
|
site.register([ConstanceConfig], BaseConstanceAdmin) # type: ignore [list-item]
|
||||||
admin.site.index_title = CONSTANCE_CONFIG["PROJECT_NAME"][0] # type: ignore
|
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,
|
WishlistViewSet,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
app_name = "core"
|
||||||
|
|
||||||
core_router = DefaultRouter()
|
core_router = DefaultRouter()
|
||||||
core_router.register(r"products", ProductViewSet, basename="products")
|
core_router.register(r"products", ProductViewSet, basename="products")
|
||||||
core_router.register(r"orders", OrderViewSet, basename="orders")
|
core_router.register(r"orders", OrderViewSet, basename="orders")
|
||||||
|
|
@ -55,10 +57,26 @@ sitemaps = {
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("core/", include(core_router.urls)),
|
path("core/", include(core_router.urls)),
|
||||||
path(
|
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("download/<str:order_product_uuid>/", download_digital_asset_view, name="download_digital_asset"),
|
||||||
path("search/", GlobalSearchView.as_view(), name="global_search"),
|
path("search/", GlobalSearchView.as_view(), name="global_search"),
|
||||||
path("app/cache/", CacheOperatorView.as_view(), name="cache_operator"),
|
path("app/cache/", CacheOperatorView.as_view(), name="cache_operator"),
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ from core.views import (
|
||||||
GlobalSearchView,
|
GlobalSearchView,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
app_name = "core"
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("search/", GlobalSearchView.as_view(), name="global_search"),
|
path("search/", GlobalSearchView.as_view(), name="global_search"),
|
||||||
path("orders/buy_as_business/", BuyAsBusinessView.as_view(), name="request_cursed_url"),
|
path("orders/buy_as_business/", BuyAsBusinessView.as_view(), name="request_cursed_url"),
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ from core.serializers import (
|
||||||
WishlistDetailSerializer,
|
WishlistDetailSerializer,
|
||||||
WishlistSimpleSerializer,
|
WishlistSimpleSerializer,
|
||||||
)
|
)
|
||||||
|
from core.serializers.seo import SeoSnapshotSerializer
|
||||||
from core.serializers.utility import AddressCreateSerializer, AddressSuggestionSerializer, DoFeedbackSerializer
|
from core.serializers.utility import AddressCreateSerializer, AddressSuggestionSerializer, DoFeedbackSerializer
|
||||||
from payments.serializers import TransactionProcessSerializer
|
from payments.serializers import TransactionProcessSerializer
|
||||||
|
|
||||||
|
|
@ -122,28 +123,50 @@ ATTRIBUTE_VALUE_SCHEMA = {
|
||||||
CATEGORY_SCHEMA = {
|
CATEGORY_SCHEMA = {
|
||||||
"list": extend_schema(
|
"list": extend_schema(
|
||||||
summary=_("list all categories (simple view)"),
|
summary=_("list all categories (simple view)"),
|
||||||
|
description=_("list all categories (simple view)"),
|
||||||
responses={status.HTTP_200_OK: CategorySimpleSerializer(many=True), **BASE_ERRORS},
|
responses={status.HTTP_200_OK: CategorySimpleSerializer(many=True), **BASE_ERRORS},
|
||||||
),
|
),
|
||||||
"retrieve": extend_schema(
|
"retrieve": extend_schema(
|
||||||
summary=_("retrieve a single category (detailed view)"),
|
summary=_("retrieve a single category (detailed view)"),
|
||||||
|
description=_("retrieve a single category (detailed view)"),
|
||||||
responses={status.HTTP_200_OK: CategoryDetailSerializer(), **BASE_ERRORS},
|
responses={status.HTTP_200_OK: CategoryDetailSerializer(), **BASE_ERRORS},
|
||||||
),
|
),
|
||||||
"create": extend_schema(
|
"create": extend_schema(
|
||||||
summary=_("create a category"),
|
summary=_("create a category"),
|
||||||
|
description=_("create a category"),
|
||||||
responses={status.HTTP_201_CREATED: CategoryDetailSerializer(), **BASE_ERRORS},
|
responses={status.HTTP_201_CREATED: CategoryDetailSerializer(), **BASE_ERRORS},
|
||||||
),
|
),
|
||||||
"destroy": extend_schema(
|
"destroy": extend_schema(
|
||||||
summary=_("delete a category"),
|
summary=_("delete a category"),
|
||||||
|
description=_("delete a category"),
|
||||||
responses={status.HTTP_204_NO_CONTENT: {}, **BASE_ERRORS},
|
responses={status.HTTP_204_NO_CONTENT: {}, **BASE_ERRORS},
|
||||||
),
|
),
|
||||||
"update": extend_schema(
|
"update": extend_schema(
|
||||||
summary=_("rewrite an existing category saving non-editables"),
|
summary=_("rewrite an existing category saving non-editables"),
|
||||||
|
description=_("rewrite an existing category saving non-editables"),
|
||||||
responses={status.HTTP_200_OK: CategoryDetailSerializer(), **BASE_ERRORS},
|
responses={status.HTTP_200_OK: CategoryDetailSerializer(), **BASE_ERRORS},
|
||||||
),
|
),
|
||||||
"partial_update": extend_schema(
|
"partial_update": extend_schema(
|
||||||
summary=_("rewrite some fields of an existing category saving non-editables"),
|
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},
|
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 = {
|
ORDER_SCHEMA = {
|
||||||
|
|
@ -347,6 +370,7 @@ ATTRIBUTES_DESC = _(
|
||||||
PRODUCT_SCHEMA = {
|
PRODUCT_SCHEMA = {
|
||||||
"list": extend_schema(
|
"list": extend_schema(
|
||||||
summary=_("list all products (simple view)"),
|
summary=_("list all products (simple view)"),
|
||||||
|
description=_("list all products (simple view)"),
|
||||||
parameters=[
|
parameters=[
|
||||||
OpenApiParameter(
|
OpenApiParameter(
|
||||||
name="uuid",
|
name="uuid",
|
||||||
|
|
@ -439,6 +463,7 @@ PRODUCT_SCHEMA = {
|
||||||
),
|
),
|
||||||
"retrieve": extend_schema(
|
"retrieve": extend_schema(
|
||||||
summary=_("retrieve a single product (detailed view)"),
|
summary=_("retrieve a single product (detailed view)"),
|
||||||
|
description=_("retrieve a single product (detailed view)"),
|
||||||
parameters=[
|
parameters=[
|
||||||
OpenApiParameter(
|
OpenApiParameter(
|
||||||
name="lookup_value",
|
name="lookup_value",
|
||||||
|
|
@ -454,6 +479,7 @@ PRODUCT_SCHEMA = {
|
||||||
),
|
),
|
||||||
"create": extend_schema(
|
"create": extend_schema(
|
||||||
summary=_("create a product"),
|
summary=_("create a product"),
|
||||||
|
description=_("create a product"),
|
||||||
responses={
|
responses={
|
||||||
status.HTTP_201_CREATED: ProductDetailSerializer(),
|
status.HTTP_201_CREATED: ProductDetailSerializer(),
|
||||||
**BASE_ERRORS,
|
**BASE_ERRORS,
|
||||||
|
|
@ -461,6 +487,7 @@ PRODUCT_SCHEMA = {
|
||||||
),
|
),
|
||||||
"update": extend_schema(
|
"update": extend_schema(
|
||||||
summary=_("rewrite an existing product, preserving non-editable fields"),
|
summary=_("rewrite an existing product, preserving non-editable fields"),
|
||||||
|
description=_("rewrite an existing product, preserving non-editable fields"),
|
||||||
parameters=[
|
parameters=[
|
||||||
OpenApiParameter(
|
OpenApiParameter(
|
||||||
name="lookup",
|
name="lookup",
|
||||||
|
|
@ -476,6 +503,7 @@ PRODUCT_SCHEMA = {
|
||||||
),
|
),
|
||||||
"partial_update": extend_schema(
|
"partial_update": extend_schema(
|
||||||
summary=_("update some fields of an existing product, preserving non-editable fields"),
|
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=[
|
parameters=[
|
||||||
OpenApiParameter(
|
OpenApiParameter(
|
||||||
name="lookup",
|
name="lookup",
|
||||||
|
|
@ -491,6 +519,7 @@ PRODUCT_SCHEMA = {
|
||||||
),
|
),
|
||||||
"destroy": extend_schema(
|
"destroy": extend_schema(
|
||||||
summary=_("delete a product"),
|
summary=_("delete a product"),
|
||||||
|
description=_("delete a product"),
|
||||||
parameters=[
|
parameters=[
|
||||||
OpenApiParameter(
|
OpenApiParameter(
|
||||||
name="lookup",
|
name="lookup",
|
||||||
|
|
@ -506,6 +535,7 @@ PRODUCT_SCHEMA = {
|
||||||
),
|
),
|
||||||
"feedbacks": extend_schema(
|
"feedbacks": extend_schema(
|
||||||
summary=_("lists all permitted feedbacks for a product"),
|
summary=_("lists all permitted feedbacks for a product"),
|
||||||
|
description=_("lists all permitted feedbacks for a product"),
|
||||||
parameters=[
|
parameters=[
|
||||||
OpenApiParameter(
|
OpenApiParameter(
|
||||||
name="lookup",
|
name="lookup",
|
||||||
|
|
@ -519,6 +549,22 @@ PRODUCT_SCHEMA = {
|
||||||
**BASE_ERRORS,
|
**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 = {
|
ADDRESS_SCHEMA = {
|
||||||
|
|
|
||||||
|
|
@ -15,19 +15,15 @@ SMART_FIELDS = [
|
||||||
"name^6",
|
"name^6",
|
||||||
"name.ngram^5",
|
"name.ngram^5",
|
||||||
"name.phonetic",
|
"name.phonetic",
|
||||||
|
|
||||||
"title^4",
|
"title^4",
|
||||||
"title.ngram^3",
|
"title.ngram^3",
|
||||||
"title.phonetic",
|
"title.phonetic",
|
||||||
|
|
||||||
"description^2",
|
"description^2",
|
||||||
"description.ngram",
|
"description.ngram",
|
||||||
"description.phonetic",
|
"description.phonetic",
|
||||||
|
|
||||||
"brand__name^3",
|
"brand__name^3",
|
||||||
"brand__name.ngram",
|
"brand__name.ngram",
|
||||||
"brand__name.auto",
|
"brand__name.auto",
|
||||||
|
|
||||||
"category__name^2",
|
"category__name^2",
|
||||||
"category__name.ngram",
|
"category__name.ngram",
|
||||||
"category__name.auto",
|
"category__name.auto",
|
||||||
|
|
@ -71,7 +67,6 @@ functions = [
|
||||||
"missing": 0,
|
"missing": 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
# category-level boost when searching for categories
|
# category-level boost when searching for categories
|
||||||
{
|
{
|
||||||
"filter": Q("term", **{"_index": "categories"}),
|
"filter": Q("term", **{"_index": "categories"}),
|
||||||
|
|
@ -82,7 +77,6 @@ functions = [
|
||||||
"missing": 0,
|
"missing": 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
# brand-level boost when searching for brands
|
# brand-level boost when searching for brands
|
||||||
{
|
{
|
||||||
"filter": Q("term", **{"_index": "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)
|
results[idx].append(hit_result)
|
||||||
|
|
||||||
return results
|
return results
|
||||||
except NotFoundError:
|
except NotFoundError as nfe:
|
||||||
raise Http404
|
raise Http404 from nfe
|
||||||
|
|
||||||
|
|
||||||
LANGUAGE_ANALYZER_MAP = {
|
LANGUAGE_ANALYZER_MAP = {
|
||||||
|
|
|
||||||
|
|
@ -12,13 +12,9 @@ class _BaseDoc(ActiveOnlyMixin, Document):
|
||||||
analyzer="standard",
|
analyzer="standard",
|
||||||
fields={
|
fields={
|
||||||
"raw": fields.KeywordField(ignore_above=256),
|
"raw": fields.KeywordField(ignore_above=256),
|
||||||
"ngram": fields.TextField(
|
"ngram": fields.TextField(analyzer="name_ngram", search_analyzer="query_lc"),
|
||||||
analyzer="name_ngram", search_analyzer="query_lc"
|
|
||||||
),
|
|
||||||
"phonetic": fields.TextField(analyzer="name_phonetic"),
|
"phonetic": fields.TextField(analyzer="name_phonetic"),
|
||||||
"auto": fields.TextField(
|
"auto": fields.TextField(analyzer="autocomplete", search_analyzer="autocomplete_search"),
|
||||||
analyzer="autocomplete", search_analyzer="autocomplete_search"
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
description = fields.TextField(
|
description = fields.TextField(
|
||||||
|
|
@ -26,13 +22,9 @@ class _BaseDoc(ActiveOnlyMixin, Document):
|
||||||
analyzer="standard",
|
analyzer="standard",
|
||||||
fields={
|
fields={
|
||||||
"raw": fields.KeywordField(ignore_above=256),
|
"raw": fields.KeywordField(ignore_above=256),
|
||||||
"ngram": fields.TextField(
|
"ngram": fields.TextField(analyzer="name_ngram", search_analyzer="query_lc"),
|
||||||
analyzer="name_ngram", search_analyzer="query_lc"
|
|
||||||
),
|
|
||||||
"phonetic": fields.TextField(analyzer="name_phonetic"),
|
"phonetic": fields.TextField(analyzer="name_phonetic"),
|
||||||
"auto": fields.TextField(
|
"auto": fields.TextField(analyzer="autocomplete", search_analyzer="autocomplete_search"),
|
||||||
analyzer="autocomplete", search_analyzer="autocomplete_search"
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
slug = fields.KeywordField(attr="slug", index=False)
|
slug = fields.KeywordField(attr="slug", index=False)
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ from django_filters import (
|
||||||
from core.elasticsearch import process_query
|
from core.elasticsearch import process_query
|
||||||
from core.models import Address, Brand, Category, Feedback, Order, Product, Wishlist
|
from core.models import Address, Brand, Category, Feedback, Order, Product, Wishlist
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger("django")
|
||||||
|
|
||||||
|
|
||||||
class CaseInsensitiveListFilter(BaseInFilter, CharFilter):
|
class CaseInsensitiveListFilter(BaseInFilter, CharFilter):
|
||||||
|
|
@ -363,6 +363,7 @@ class CategoryFilter(FilterSet):
|
||||||
|
|
||||||
order_by = OrderingFilter(
|
order_by = OrderingFilter(
|
||||||
fields=(
|
fields=(
|
||||||
|
("priority", "priority"),
|
||||||
("uuid", "uuid"),
|
("uuid", "uuid"),
|
||||||
("name", "name"),
|
("name", "name"),
|
||||||
("?", "random"),
|
("?", "random"),
|
||||||
|
|
@ -430,6 +431,7 @@ class BrandFilter(FilterSet):
|
||||||
|
|
||||||
order_by = OrderingFilter(
|
order_by = OrderingFilter(
|
||||||
fields=(
|
fields=(
|
||||||
|
("priority", "priority"),
|
||||||
("uuid", "uuid"),
|
("uuid", "uuid"),
|
||||||
("name", "name"),
|
("name", "name"),
|
||||||
("?", "random"),
|
("?", "random"),
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
from graphene import Mutation
|
from graphene import Mutation
|
||||||
|
|
||||||
|
|
||||||
class BaseMutation(Mutation):
|
class BaseMutation(Mutation): # type: ignore [misc]
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs) -> None:
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mutate(**kwargs):
|
def mutate(**kwargs) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
|
||||||
|
|
@ -13,13 +13,14 @@ from core.elasticsearch import process_query
|
||||||
from core.graphene import BaseMutation
|
from core.graphene import BaseMutation
|
||||||
from core.graphene.object_types import (
|
from core.graphene.object_types import (
|
||||||
AddressType,
|
AddressType,
|
||||||
BulkActionOrderProductInput,
|
BulkProductInput,
|
||||||
OrderType,
|
OrderType,
|
||||||
ProductType,
|
ProductType,
|
||||||
SearchResultsType,
|
SearchResultsType,
|
||||||
WishlistType,
|
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 import format_attributes, is_url_safe
|
||||||
from core.utils.caching import web_cache
|
from core.utils.caching import web_cache
|
||||||
from core.utils.emailing import contact_us_email
|
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 core.utils.nominatim import fetch_address_suggestions
|
||||||
from payments.graphene.object_types import TransactionType
|
from payments.graphene.object_types import TransactionType
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger("django")
|
||||||
|
|
||||||
|
|
||||||
class CacheOperator(BaseMutation):
|
class CacheOperator(BaseMutation):
|
||||||
|
|
@ -96,8 +97,8 @@ class AddOrderProduct(BaseMutation):
|
||||||
order = order.add_product(product_uuid=product_uuid, attributes=format_attributes(attributes))
|
order = order.add_product(product_uuid=product_uuid, attributes=format_attributes(attributes))
|
||||||
|
|
||||||
return AddOrderProduct(order=order)
|
return AddOrderProduct(order=order)
|
||||||
except Order.DoesNotExist:
|
except Order.DoesNotExist as dne:
|
||||||
raise Http404(_(f"order {order_uuid} not found"))
|
raise Http404(_(f"order {order_uuid} not found")) from dne
|
||||||
|
|
||||||
|
|
||||||
class RemoveOrderProduct(BaseMutation):
|
class RemoveOrderProduct(BaseMutation):
|
||||||
|
|
@ -122,8 +123,8 @@ class RemoveOrderProduct(BaseMutation):
|
||||||
order = order.remove_product(product_uuid=product_uuid, attributes=format_attributes(attributes))
|
order = order.remove_product(product_uuid=product_uuid, attributes=format_attributes(attributes))
|
||||||
|
|
||||||
return AddOrderProduct(order=order)
|
return AddOrderProduct(order=order)
|
||||||
except Order.DoesNotExist:
|
except Order.DoesNotExist as dne:
|
||||||
raise Http404(_(f"order {order_uuid} not found"))
|
raise Http404(_(f"order {order_uuid} not found")) from dne
|
||||||
|
|
||||||
|
|
||||||
class RemoveAllOrderProducts(BaseMutation):
|
class RemoveAllOrderProducts(BaseMutation):
|
||||||
|
|
@ -174,13 +175,14 @@ class BuyOrder(BaseMutation):
|
||||||
description = _("buy an order")
|
description = _("buy an order")
|
||||||
|
|
||||||
class Arguments:
|
class Arguments:
|
||||||
order_uuid = UUID(required=False)
|
order_uuid = String(required=False)
|
||||||
order_hr_id = String(required=False)
|
order_hr_id = String(required=False)
|
||||||
force_balance = Boolean(required=False)
|
force_balance = Boolean(required=False)
|
||||||
force_payment = Boolean(required=False)
|
force_payment = Boolean(required=False)
|
||||||
promocode_uuid = UUID(required=False)
|
promocode_uuid = String(required=False)
|
||||||
shipping_address = UUID(required=False)
|
shipping_address = String(required=False)
|
||||||
billing_address = UUID(required=False)
|
billing_address = String(required=False)
|
||||||
|
chosen_products = List(BulkProductInput, required=False)
|
||||||
|
|
||||||
order = Field(OrderType, required=False)
|
order = Field(OrderType, required=False)
|
||||||
transaction = Field(TransactionType, required=False)
|
transaction = Field(TransactionType, required=False)
|
||||||
|
|
@ -196,6 +198,7 @@ class BuyOrder(BaseMutation):
|
||||||
promocode_uuid=None,
|
promocode_uuid=None,
|
||||||
shipping_address=None,
|
shipping_address=None,
|
||||||
billing_address=None,
|
billing_address=None,
|
||||||
|
chosen_products=None,
|
||||||
):
|
):
|
||||||
if not any([order_uuid, order_hr_id]) or all([order_uuid, order_hr_id]):
|
if not any([order_uuid, order_hr_id]) or all([order_uuid, order_hr_id]):
|
||||||
raise BadRequest(_("please provide either order_uuid or order_hr_id - mutually exclusive"))
|
raise BadRequest(_("please provide either order_uuid or order_hr_id - mutually exclusive"))
|
||||||
|
|
@ -214,6 +217,7 @@ class BuyOrder(BaseMutation):
|
||||||
promocode_uuid=promocode_uuid,
|
promocode_uuid=promocode_uuid,
|
||||||
shipping_address=shipping_address,
|
shipping_address=shipping_address,
|
||||||
billing_address=billing_address,
|
billing_address=billing_address,
|
||||||
|
chosen_products=chosen_products,
|
||||||
)
|
)
|
||||||
|
|
||||||
match str(type(instance)):
|
match str(type(instance)):
|
||||||
|
|
@ -224,8 +228,8 @@ class BuyOrder(BaseMutation):
|
||||||
case _:
|
case _:
|
||||||
raise TypeError(_(f"wrong type came from order.buy() method: {type(instance)!s}"))
|
raise TypeError(_(f"wrong type came from order.buy() method: {type(instance)!s}"))
|
||||||
|
|
||||||
except Order.DoesNotExist:
|
except Order.DoesNotExist as dne:
|
||||||
raise Http404(_(f"order {order_uuid} not found"))
|
raise Http404(_(f"order {order_uuid} not found")) from dne
|
||||||
|
|
||||||
|
|
||||||
class BulkOrderAction(BaseMutation):
|
class BulkOrderAction(BaseMutation):
|
||||||
|
|
@ -236,7 +240,7 @@ class BulkOrderAction(BaseMutation):
|
||||||
order_uuid = UUID(required=False)
|
order_uuid = UUID(required=False)
|
||||||
order_hr_id = String(required=False)
|
order_hr_id = String(required=False)
|
||||||
action = String(required=True, description=_("remove/add"))
|
action = String(required=True, description=_("remove/add"))
|
||||||
products = List(BulkActionOrderProductInput, required=True)
|
products = List(BulkProductInput, required=True)
|
||||||
|
|
||||||
order = Field(OrderType, required=False)
|
order = Field(OrderType, required=False)
|
||||||
|
|
||||||
|
|
@ -271,8 +275,48 @@ class BulkOrderAction(BaseMutation):
|
||||||
|
|
||||||
return BulkOrderAction(order=order)
|
return BulkOrderAction(order=order)
|
||||||
|
|
||||||
except Order.DoesNotExist:
|
except Order.DoesNotExist as dne:
|
||||||
raise Http404(_(f"order {order_uuid} not found"))
|
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):
|
class BuyUnregisteredOrder(BaseMutation):
|
||||||
|
|
@ -344,8 +388,8 @@ class AddWishlistProduct(BaseMutation):
|
||||||
|
|
||||||
return AddWishlistProduct(wishlist=wishlist)
|
return AddWishlistProduct(wishlist=wishlist)
|
||||||
|
|
||||||
except Wishlist.DoesNotExist:
|
except Wishlist.DoesNotExist as dne:
|
||||||
raise Http404(_(f"wishlist {wishlist_uuid} not found"))
|
raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
|
||||||
|
|
||||||
|
|
||||||
class RemoveWishlistProduct(BaseMutation):
|
class RemoveWishlistProduct(BaseMutation):
|
||||||
|
|
@ -371,8 +415,8 @@ class RemoveWishlistProduct(BaseMutation):
|
||||||
|
|
||||||
return RemoveWishlistProduct(wishlist=wishlist)
|
return RemoveWishlistProduct(wishlist=wishlist)
|
||||||
|
|
||||||
except Wishlist.DoesNotExist:
|
except Wishlist.DoesNotExist as dne:
|
||||||
raise Http404(_(f"wishlist {wishlist_uuid} not found"))
|
raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
|
||||||
|
|
||||||
|
|
||||||
class RemoveAllWishlistProducts(BaseMutation):
|
class RemoveAllWishlistProducts(BaseMutation):
|
||||||
|
|
@ -398,8 +442,8 @@ class RemoveAllWishlistProducts(BaseMutation):
|
||||||
|
|
||||||
return RemoveAllWishlistProducts(wishlist=wishlist)
|
return RemoveAllWishlistProducts(wishlist=wishlist)
|
||||||
|
|
||||||
except Wishlist.DoesNotExist:
|
except Wishlist.DoesNotExist as dne:
|
||||||
raise Http404(_(f"wishlist {wishlist_uuid} not found"))
|
raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
|
||||||
|
|
||||||
|
|
||||||
class BuyWishlist(BaseMutation):
|
class BuyWishlist(BaseMutation):
|
||||||
|
|
@ -441,8 +485,8 @@ class BuyWishlist(BaseMutation):
|
||||||
case _:
|
case _:
|
||||||
raise TypeError(_(f"wrong type came from order.buy() method: {type(instance)!s}"))
|
raise TypeError(_(f"wrong type came from order.buy() method: {type(instance)!s}"))
|
||||||
|
|
||||||
except Wishlist.DoesNotExist:
|
except Wishlist.DoesNotExist as dne:
|
||||||
raise Http404(_(f"wishlist {wishlist_uuid} not found"))
|
raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
|
||||||
|
|
||||||
|
|
||||||
class BuyProduct(BaseMutation):
|
class BuyProduct(BaseMutation):
|
||||||
|
|
@ -483,6 +527,37 @@ class BuyProduct(BaseMutation):
|
||||||
raise TypeError(_(f"wrong type came from order.buy() method: {type(instance)!s}"))
|
raise TypeError(_(f"wrong type came from order.buy() method: {type(instance)!s}"))
|
||||||
|
|
||||||
|
|
||||||
|
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 CreateProduct(BaseMutation):
|
||||||
class Arguments:
|
class Arguments:
|
||||||
name = String(required=True)
|
name = String(required=True)
|
||||||
|
|
@ -575,9 +650,9 @@ class DeleteAddress(BaseMutation):
|
||||||
|
|
||||||
raise PermissionDenied(permission_denied_message)
|
raise PermissionDenied(permission_denied_message)
|
||||||
|
|
||||||
except Address.DoesNotExist:
|
except Address.DoesNotExist as dne:
|
||||||
name = "Address"
|
name = "Address"
|
||||||
raise Http404(_(f"{name} does not exist: {uuid}"))
|
raise Http404(_(f"{name} does not exist: {uuid}")) from dne
|
||||||
|
|
||||||
|
|
||||||
class AutocompleteAddress(BaseMutation):
|
class AutocompleteAddress(BaseMutation):
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from constance import config
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.db.models import Max, Min
|
from django.db.models import Max, Min, QuerySet
|
||||||
from django.db.models.functions import Length
|
from django.db.models.functions import Length
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from graphene import (
|
from graphene import (
|
||||||
|
|
@ -13,6 +16,7 @@ from graphene import (
|
||||||
ObjectType,
|
ObjectType,
|
||||||
String,
|
String,
|
||||||
relay,
|
relay,
|
||||||
|
Boolean,
|
||||||
)
|
)
|
||||||
from graphene.types.generic import GenericScalar
|
from graphene.types.generic import GenericScalar
|
||||||
from graphene_django import DjangoObjectType
|
from graphene_django import DjangoObjectType
|
||||||
|
|
@ -40,8 +44,31 @@ from core.models import (
|
||||||
Vendor,
|
Vendor,
|
||||||
Wishlist,
|
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):
|
class AttributeType(DjangoObjectType):
|
||||||
|
|
@ -87,6 +114,7 @@ class AttributeGroupType(DjangoObjectType):
|
||||||
|
|
||||||
class BrandType(DjangoObjectType):
|
class BrandType(DjangoObjectType):
|
||||||
categories = List(lambda: CategoryType, description=_("categories"))
|
categories = List(lambda: CategoryType, description=_("categories"))
|
||||||
|
seo_meta = Field(SEOMetaType, description=_("SEO meta snapshot"))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Brand
|
model = Brand
|
||||||
|
|
@ -106,6 +134,48 @@ class BrandType(DjangoObjectType):
|
||||||
def resolve_small_logo(self: Brand, info):
|
def resolve_small_logo(self: Brand, info):
|
||||||
return info.context.build_absolute_uri(self.small_logo.url) if self.small_logo else ""
|
return info.context.build_absolute_uri(self.small_logo.url) if self.small_logo else ""
|
||||||
|
|
||||||
|
def resolve_seo_meta(self: Brand, info):
|
||||||
|
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):
|
class FilterableAttributeType(ObjectType):
|
||||||
attribute_name = String(required=True)
|
attribute_name = String(required=True)
|
||||||
|
|
@ -134,6 +204,7 @@ class CategoryType(DjangoObjectType):
|
||||||
)
|
)
|
||||||
tags = DjangoFilterConnectionField(lambda: CategoryTagType, description=_("tags for this category"))
|
tags = DjangoFilterConnectionField(lambda: CategoryTagType, description=_("tags for this category"))
|
||||||
products = DjangoFilterConnectionField(lambda: ProductType, description=_("products in this category"))
|
products = DjangoFilterConnectionField(lambda: ProductType, description=_("products in this category"))
|
||||||
|
seo_meta = Field(SEOMetaType, description=_("SEO meta snapshot"))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Category
|
model = Category
|
||||||
|
|
@ -216,6 +287,58 @@ class CategoryType(DjangoObjectType):
|
||||||
"max_price": min_max_prices["max_price"],
|
"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):
|
class VendorType(DjangoObjectType):
|
||||||
markup_percent = Float(description=_("markup percentage"))
|
markup_percent = Float(description=_("markup percentage"))
|
||||||
|
|
@ -234,6 +357,7 @@ class AddressType(DjangoObjectType):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Address
|
model = Address
|
||||||
|
interfaces = (relay.Node,)
|
||||||
fields = (
|
fields = (
|
||||||
"uuid",
|
"uuid",
|
||||||
"street",
|
"street",
|
||||||
|
|
@ -313,6 +437,7 @@ class OrderType(DjangoObjectType):
|
||||||
is_whole_digital = Float(description=_("are all products in the order digital"))
|
is_whole_digital = Float(description=_("are all products in the order digital"))
|
||||||
attributes = GenericScalar(description=_("attributes"))
|
attributes = GenericScalar(description=_("attributes"))
|
||||||
notifications = GenericScalar(description=_("notifications"))
|
notifications = GenericScalar(description=_("notifications"))
|
||||||
|
payments_transactions = Field(TransactionType, description=_("transactions for this order"))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Order
|
model = Order
|
||||||
|
|
@ -329,21 +454,27 @@ class OrderType(DjangoObjectType):
|
||||||
"total_quantity",
|
"total_quantity",
|
||||||
"is_whole_digital",
|
"is_whole_digital",
|
||||||
"human_readable_id",
|
"human_readable_id",
|
||||||
|
"payments_transactions",
|
||||||
)
|
)
|
||||||
description = _("orders")
|
description = _("orders")
|
||||||
|
|
||||||
def resolve_total_price(self, _info):
|
def resolve_total_price(self: Order, _info):
|
||||||
return self.total_price
|
return self.total_price
|
||||||
|
|
||||||
def resolve_total_quantity(self, _info):
|
def resolve_total_quantity(self: Order, _info):
|
||||||
return self.total_quantity
|
return self.total_quantity
|
||||||
|
|
||||||
def resolve_notifications(self, _info):
|
def resolve_notifications(self: Order, _info):
|
||||||
return camelize(self.notifications)
|
return camelize(self.notifications)
|
||||||
|
|
||||||
def resolve_attributes(self, _info):
|
def resolve_attributes(self: Order, _info):
|
||||||
return camelize(self.attributes)
|
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):
|
class ProductImageType(DjangoObjectType):
|
||||||
image = String(description=_("image url"))
|
image = String(description=_("image url"))
|
||||||
|
|
@ -368,6 +499,8 @@ class ProductType(DjangoObjectType):
|
||||||
price = Float(description=_("price"))
|
price = Float(description=_("price"))
|
||||||
quantity = Float(description=_("quantity"))
|
quantity = Float(description=_("quantity"))
|
||||||
feedbacks_count = Int(description=_("number of feedbacks"))
|
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:
|
class Meta:
|
||||||
model = Product
|
model = Product
|
||||||
|
|
@ -381,13 +514,17 @@ class ProductType(DjangoObjectType):
|
||||||
"slug",
|
"slug",
|
||||||
"description",
|
"description",
|
||||||
"feedbacks",
|
"feedbacks",
|
||||||
|
"feedbacks_count",
|
||||||
|
"personal_orders_only",
|
||||||
|
"quantity",
|
||||||
|
"attribute_groups",
|
||||||
"images",
|
"images",
|
||||||
"price",
|
"price",
|
||||||
)
|
)
|
||||||
filter_fields = ["uuid", "name"]
|
filter_fields = ["uuid", "name"]
|
||||||
description = _("products")
|
description = _("products")
|
||||||
|
|
||||||
def resolve_price(self, _info) -> float:
|
def resolve_price(self: Product, _info) -> float:
|
||||||
return self.price or 0.0
|
return self.price or 0.0
|
||||||
|
|
||||||
def resolve_feedbacks(self: Product, _info):
|
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)
|
||||||
return Feedback.objects.filter(order_product__product=self, is_active=True)
|
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
|
return self.feedbacks_count or 0
|
||||||
|
|
||||||
def resolve_attribute_groups(self: Product, info):
|
def resolve_attribute_groups(self: Product, info):
|
||||||
|
|
@ -403,9 +540,58 @@ class ProductType(DjangoObjectType):
|
||||||
|
|
||||||
return AttributeGroup.objects.filter(attributes__values__product=self).distinct()
|
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
|
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):
|
class AttributeValueType(DjangoObjectType):
|
||||||
value = String(description=_("attribute value"))
|
value = String(description=_("attribute value"))
|
||||||
|
|
@ -436,7 +622,7 @@ class PromoCodeType(DjangoObjectType):
|
||||||
description = _("promocodes")
|
description = _("promocodes")
|
||||||
|
|
||||||
def resolve_discount(self: PromoCode, _info) -> float:
|
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:
|
def resolve_discount_type(self: PromoCode, _info) -> str:
|
||||||
return "percent" if self.discount_percent else "amount"
|
return "percent" if self.discount_percent else "amount"
|
||||||
|
|
@ -557,6 +743,6 @@ class SearchResultsType(ObjectType):
|
||||||
posts = List(description=_("posts search results"), of_type=SearchPostsResultsType)
|
posts = List(description=_("posts search results"), of_type=SearchPostsResultsType)
|
||||||
|
|
||||||
|
|
||||||
class BulkActionOrderProductInput(InputObjectType):
|
class BulkProductInput(InputObjectType):
|
||||||
uuid = UUID(required=True)
|
uuid = UUID(required=True)
|
||||||
attributes = GenericScalar(required=False)
|
attributes = GenericScalar(required=False)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
|
from django.utils import timezone
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
from graphene import Field, List, ObjectType, Schema
|
from graphene import Field, List, ObjectType, Schema
|
||||||
from graphene_django.filter import DjangoFilterConnectionField
|
from graphene_django.filter import DjangoFilterConnectionField
|
||||||
|
|
@ -14,12 +15,14 @@ from core.filters import (
|
||||||
OrderFilter,
|
OrderFilter,
|
||||||
ProductFilter,
|
ProductFilter,
|
||||||
WishlistFilter,
|
WishlistFilter,
|
||||||
|
AddressFilter,
|
||||||
)
|
)
|
||||||
from core.graphene.mutations import (
|
from core.graphene.mutations import (
|
||||||
AddOrderProduct,
|
AddOrderProduct,
|
||||||
AddWishlistProduct,
|
AddWishlistProduct,
|
||||||
AutocompleteAddress,
|
AutocompleteAddress,
|
||||||
BulkOrderAction,
|
BulkOrderAction,
|
||||||
|
BulkWishlistAction,
|
||||||
BuyOrder,
|
BuyOrder,
|
||||||
BuyProduct,
|
BuyProduct,
|
||||||
BuyWishlist,
|
BuyWishlist,
|
||||||
|
|
@ -29,6 +32,7 @@ from core.graphene.mutations import (
|
||||||
CreateProduct,
|
CreateProduct,
|
||||||
DeleteAddress,
|
DeleteAddress,
|
||||||
DeleteProduct,
|
DeleteProduct,
|
||||||
|
FeedbackProductAction,
|
||||||
RemoveAllOrderProducts,
|
RemoveAllOrderProducts,
|
||||||
RemoveAllWishlistProducts,
|
RemoveAllWishlistProducts,
|
||||||
RemoveOrderProduct,
|
RemoveOrderProduct,
|
||||||
|
|
@ -56,6 +60,7 @@ from core.graphene.object_types import (
|
||||||
StockType,
|
StockType,
|
||||||
VendorType,
|
VendorType,
|
||||||
WishlistType,
|
WishlistType,
|
||||||
|
AddressType,
|
||||||
)
|
)
|
||||||
from core.models import (
|
from core.models import (
|
||||||
AttributeGroup,
|
AttributeGroup,
|
||||||
|
|
@ -73,6 +78,7 @@ from core.models import (
|
||||||
Stock,
|
Stock,
|
||||||
Vendor,
|
Vendor,
|
||||||
Wishlist,
|
Wishlist,
|
||||||
|
Address,
|
||||||
)
|
)
|
||||||
from core.utils import get_project_parameters
|
from core.utils import get_project_parameters
|
||||||
from core.utils.languages import get_flag_by_language
|
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.graphene.object_types import UserType
|
||||||
from vibes_auth.models import User
|
from vibes_auth.models import User
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger("django")
|
||||||
|
|
||||||
|
|
||||||
class Query(ObjectType):
|
class Query(ObjectType):
|
||||||
|
|
@ -104,6 +110,7 @@ class Query(ObjectType):
|
||||||
products = DjangoFilterConnectionField(ProductType, filterset_class=ProductFilter)
|
products = DjangoFilterConnectionField(ProductType, filterset_class=ProductFilter)
|
||||||
orders = DjangoFilterConnectionField(OrderType, filterset_class=OrderFilter)
|
orders = DjangoFilterConnectionField(OrderType, filterset_class=OrderFilter)
|
||||||
users = DjangoFilterConnectionField(UserType, filterset_class=UserFilter)
|
users = DjangoFilterConnectionField(UserType, filterset_class=UserFilter)
|
||||||
|
addresses = DjangoFilterConnectionField(AddressType, filterset_class=AddressFilter)
|
||||||
attribute_groups = DjangoFilterConnectionField(AttributeGroupType)
|
attribute_groups = DjangoFilterConnectionField(AttributeGroupType)
|
||||||
categories = DjangoFilterConnectionField(CategoryType, filterset_class=CategoryFilter)
|
categories = DjangoFilterConnectionField(CategoryType, filterset_class=CategoryFilter)
|
||||||
vendors = DjangoFilterConnectionField(VendorType)
|
vendors = DjangoFilterConnectionField(VendorType)
|
||||||
|
|
@ -145,7 +152,10 @@ class Query(ObjectType):
|
||||||
Product.objects.all().select_related("brand", "category").prefetch_related("images", "stocks")
|
Product.objects.all().select_related("brand", "category").prefetch_related("images", "stocks")
|
||||||
if info.context.user.has_perm("core.view_product")
|
if info.context.user.has_perm("core.view_product")
|
||||||
else Product.objects.filter(
|
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")
|
.select_related("brand", "category")
|
||||||
.prefetch_related("images", "stocks")
|
.prefetch_related("images", "stocks")
|
||||||
|
|
@ -284,7 +294,12 @@ class Query(ObjectType):
|
||||||
promocodes = PromoCode.objects
|
promocodes = PromoCode.objects
|
||||||
if info.context.user.has_perm("core.view_promocode"):
|
if info.context.user.has_perm("core.view_promocode"):
|
||||||
return promocodes.filter(user__uuid=kwargs.get("user_uuid")) or promocodes.all()
|
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
|
@staticmethod
|
||||||
def resolve_product_tags(_parent, info, **_kwargs):
|
def resolve_product_tags(_parent, info, **_kwargs):
|
||||||
|
|
@ -298,6 +313,12 @@ class Query(ObjectType):
|
||||||
return CategoryTag.objects.all()
|
return CategoryTag.objects.all()
|
||||||
return CategoryTag.objects.filter(is_active=True)
|
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):
|
class Mutation(ObjectType):
|
||||||
search = Search.Field()
|
search = Search.Field()
|
||||||
|
|
@ -314,6 +335,8 @@ class Mutation(ObjectType):
|
||||||
remove_order_products_of_a_kind = RemoveOrderProductsOfAKind.Field()
|
remove_order_products_of_a_kind = RemoveOrderProductsOfAKind.Field()
|
||||||
buy_order = BuyOrder.Field()
|
buy_order = BuyOrder.Field()
|
||||||
bulk_order_action = BulkOrderAction.Field()
|
bulk_order_action = BulkOrderAction.Field()
|
||||||
|
bulk_wishlist_action = BulkWishlistAction.Field()
|
||||||
|
feedback_product_action = FeedbackProductAction.Field()
|
||||||
deposit = Deposit.Field()
|
deposit = Deposit.Field()
|
||||||
obtain_jwt_token = ObtainJSONWebToken.Field()
|
obtain_jwt_token = ObtainJSONWebToken.Field()
|
||||||
refresh_jwt_token = RefreshJSONWebToken.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