Merge branch 'main' into storefront-next
This commit is contained in:
commit
0b829d3b5f
876 changed files with 160393 additions and 73108 deletions
|
|
@ -26,6 +26,7 @@ cython_debug/
|
||||||
|
|
||||||
# Python environments
|
# Python environments
|
||||||
.Python
|
.Python
|
||||||
|
.python-version
|
||||||
env/
|
env/
|
||||||
env.bak/
|
env.bak/
|
||||||
venv/
|
venv/
|
||||||
|
|
@ -38,7 +39,6 @@ __pypackages__/
|
||||||
# Packaging and distribution
|
# Packaging and distribution
|
||||||
# ──────────────────────────────────────────────────────────────────────────
|
# ──────────────────────────────────────────────────────────────────────────
|
||||||
build/
|
build/
|
||||||
dist/
|
|
||||||
dist-ssr/
|
dist-ssr/
|
||||||
*.egg
|
*.egg
|
||||||
*.egg-info/
|
*.egg-info/
|
||||||
|
|
@ -69,14 +69,13 @@ pip-delete-this-directory.txt
|
||||||
# ──────────────────────────────────────────────────────────────────────────
|
# ──────────────────────────────────────────────────────────────────────────
|
||||||
storefront/Dockerfile
|
storefront/Dockerfile
|
||||||
docker-compose.yml
|
docker-compose.yml
|
||||||
db_backups/
|
backups/
|
||||||
services_data/
|
|
||||||
static/
|
static/
|
||||||
media/
|
media/
|
||||||
!core/static
|
!engine/core/static
|
||||||
!blog/static
|
!engine/blog/static
|
||||||
!vibes_auth/static
|
!engine/vibes_auth/static
|
||||||
!payments/static
|
!engine/payments/static
|
||||||
|
|
||||||
# Environment file
|
# Environment file
|
||||||
.env
|
.env
|
||||||
|
|
|
||||||
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
*.sh text eol=lf
|
||||||
28
.gitignore
vendored
28
.gitignore
vendored
|
|
@ -27,6 +27,7 @@ venv.bak/
|
||||||
ENV/
|
ENV/
|
||||||
.venv/
|
.venv/
|
||||||
__pypackages__/
|
__pypackages__/
|
||||||
|
.python-version
|
||||||
|
|
||||||
# Local Django settings and database
|
# Local Django settings and database
|
||||||
local_settings.py
|
local_settings.py
|
||||||
|
|
@ -35,7 +36,7 @@ db.sqlite3-journal
|
||||||
|
|
||||||
# Django backups and metadata
|
# Django backups and metadata
|
||||||
instance/
|
instance/
|
||||||
db_backups/
|
backups/
|
||||||
|
|
||||||
# ──────────────────────────────────────────────────────────────────────────
|
# ──────────────────────────────────────────────────────────────────────────
|
||||||
# Logs and reports
|
# Logs and reports
|
||||||
|
|
@ -50,6 +51,7 @@ coverage.*
|
||||||
*.cover
|
*.cover
|
||||||
*.py,cover
|
*.py,cover
|
||||||
nosetests.xml
|
nosetests.xml
|
||||||
|
tmp
|
||||||
|
|
||||||
# Coverage / test reports
|
# Coverage / test reports
|
||||||
htmlcov/
|
htmlcov/
|
||||||
|
|
@ -90,6 +92,7 @@ share/python-wheels/
|
||||||
pip-log.txt
|
pip-log.txt
|
||||||
pip-delete-this-directory.txt
|
pip-delete-this-directory.txt
|
||||||
desktop.ini
|
desktop.ini
|
||||||
|
*.iml
|
||||||
|
|
||||||
# Node build artifacts
|
# Node build artifacts
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
|
|
@ -106,22 +109,14 @@ static/
|
||||||
media/
|
media/
|
||||||
|
|
||||||
# Allow checked-in static from apps
|
# Allow checked-in static from apps
|
||||||
!core/static/
|
!engine/core/static/
|
||||||
!payments/static/
|
!engine/payments/static/
|
||||||
!vibes_auth/static/
|
!engine/vibes_auth/static/
|
||||||
!blog/static/
|
!engine/blog/static/
|
||||||
|
|
||||||
# Webassets
|
# Webassets
|
||||||
.webassets-cache/
|
.webassets-cache/
|
||||||
|
|
||||||
# ──────────────────────────────────────────────────────────────────────────
|
|
||||||
# Docker & service data
|
|
||||||
# ──────────────────────────────────────────────────────────────────────────
|
|
||||||
# Local volume mounts
|
|
||||||
services_data/
|
|
||||||
services_data/postgres/
|
|
||||||
services_data/redis/
|
|
||||||
|
|
||||||
# ──────────────────────────────────────────────────────────────────────────
|
# ──────────────────────────────────────────────────────────────────────────
|
||||||
# Node dependencies
|
# Node dependencies
|
||||||
# ──────────────────────────────────────────────────────────────────────────
|
# ──────────────────────────────────────────────────────────────────────────
|
||||||
|
|
@ -145,6 +140,7 @@ cypress/screenshots/
|
||||||
!.idea/icon.svg
|
!.idea/icon.svg
|
||||||
!.idea/externalDependencies.xml
|
!.idea/externalDependencies.xml
|
||||||
!.idea/evibes.iml
|
!.idea/evibes.iml
|
||||||
|
!.idea/evibes.ico
|
||||||
|
|
||||||
# Microsoft
|
# Microsoft
|
||||||
*.suo
|
*.suo
|
||||||
|
|
@ -168,4 +164,8 @@ cypress/screenshots/
|
||||||
.env
|
.env
|
||||||
|
|
||||||
# Development stuff
|
# Development stuff
|
||||||
test.ipynb
|
test.ipynb
|
||||||
|
|
||||||
|
# Production stuff
|
||||||
|
.initialized
|
||||||
|
queries
|
||||||
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
|
|
@ -1,14 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module version="4">
|
|
||||||
<component name="PyDocumentationSettings">
|
|
||||||
<option name="format" value="GOOGLE" />
|
|
||||||
<option name="myDocStringFormat" value="Google" />
|
|
||||||
</component>
|
|
||||||
<component name="TemplatesService">
|
|
||||||
<option name="TEMPLATE_FOLDERS">
|
|
||||||
<list>
|
|
||||||
<option value="$MODULE_DIR$/blog/templates" />
|
|
||||||
</list>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
</module>
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
<?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>
|
|
||||||
|
|
@ -10,7 +10,7 @@ docker-compose.yml @@maintainer
|
||||||
.dockerignore @@maintainer
|
.dockerignore @@maintainer
|
||||||
nginx @@maintainer
|
nginx @@maintainer
|
||||||
pyproject.toml @fureunoir contact@fureunoir.com
|
pyproject.toml @fureunoir contact@fureunoir.com
|
||||||
poetry.lock @fureunoir contact@fureunoir.com
|
uv.lock @fureunoir contact@fureunoir.com
|
||||||
|
|
||||||
*.py @fureunoir contact@fureunoir.com
|
*.py @fureunoir contact@fureunoir.com
|
||||||
*.bat @fureunoir contact@fureunoir.com
|
*.bat @fureunoir contact@fureunoir.com
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# syntax=docker/dockerfile:1
|
# syntax=docker/dockerfile:1
|
||||||
FROM python:3.12-bookworm
|
FROM python:3.12-slim-bookworm
|
||||||
LABEL authors="fureunoir"
|
LABEL authors="fureunoir"
|
||||||
|
|
||||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||||
|
|
@ -13,7 +13,7 @@ WORKDIR /app
|
||||||
RUN set -eux; \
|
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; \
|
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 update; \
|
||||||
apt-get install -y --no-install-recommends wget gnupg; \
|
apt-get install -y --no-install-recommends wget gnupg curl; \
|
||||||
wget -qO - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -; \
|
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" \
|
echo "deb http://apt.postgresql.org/pub/repos/apt bookworm-pgdg main" \
|
||||||
> /etc/apt/sources.list.d/pgdg.list; \
|
> /etc/apt/sources.list.d/pgdg.list; \
|
||||||
|
|
@ -26,24 +26,32 @@ RUN set -eux; \
|
||||||
graphviz-dev \
|
graphviz-dev \
|
||||||
libgts-dev \
|
libgts-dev \
|
||||||
libpq5 \
|
libpq5 \
|
||||||
|
chrony \
|
||||||
graphviz \
|
graphviz \
|
||||||
binutils \
|
binutils \
|
||||||
libproj-dev \
|
libproj-dev \
|
||||||
postgresql-client-17 \
|
postgresql-client-17 \
|
||||||
gdal-bin; \
|
gdal-bin; \
|
||||||
rm -rf /var/lib/apt/lists/*; \
|
rm -rf /var/lib/apt/lists/*; \
|
||||||
pip install --upgrade pip; \
|
pip install --upgrade pip
|
||||||
curl -sSL https://install.python-poetry.org | python3
|
|
||||||
|
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||||
|
ENV PATH="/root/.local/bin:/root/.cargo/bin:$PATH"
|
||||||
|
|
||||||
|
RUN uv venv /opt/evibes-python
|
||||||
|
ENV VIRTUAL_ENV=/opt/evibes-python
|
||||||
|
ENV UV_PROJECT_ENVIRONMENT=/opt/evibes-python
|
||||||
|
ENV PATH="/opt/evibes-python/bin:/root/.local/bin:/root/.cargo/bin:$PATH"
|
||||||
|
|
||||||
COPY pyproject.toml pyproject.toml
|
COPY pyproject.toml pyproject.toml
|
||||||
COPY poetry.lock poetry.lock
|
COPY uv.lock uv.lock
|
||||||
|
|
||||||
RUN poetry config virtualenvs.create false
|
RUN set -eux; \
|
||||||
RUN poetry install --extras="graph worker openai testing" --no-interaction --no-ansi
|
uv sync --extra graph --extra worker --extra openai --locked
|
||||||
|
|
||||||
COPY ./scripts/Docker/app-entrypoint.sh /usr/local/bin/app-entrypoint.sh
|
COPY ./scripts/Docker/app-entrypoint.sh /usr/local/bin/app-entrypoint.sh
|
||||||
RUN chmod +x /usr/local/bin/app-entrypoint.sh
|
RUN chmod +x /usr/local/bin/app-entrypoint.sh
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
ENTRYPOINT ["app-entrypoint.sh"]
|
ENTRYPOINT ["/usr/bin/bash", "app-entrypoint.sh"]
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# syntax=docker/dockerfile:1
|
# syntax=docker/dockerfile:1
|
||||||
FROM python:3.12-bookworm
|
FROM python:3.12-slim-bookworm
|
||||||
LABEL authors="fureunoir"
|
LABEL authors="fureunoir"
|
||||||
|
|
||||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||||
|
|
@ -13,7 +13,7 @@ WORKDIR /app
|
||||||
RUN set -eux; \
|
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; \
|
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 update; \
|
||||||
apt-get install -y --no-install-recommends wget gnupg; \
|
apt-get install -y --no-install-recommends wget gnupg curl; \
|
||||||
wget -qO - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -; \
|
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" \
|
echo "deb http://apt.postgresql.org/pub/repos/apt bookworm-pgdg main" \
|
||||||
> /etc/apt/sources.list.d/pgdg.list; \
|
> /etc/apt/sources.list.d/pgdg.list; \
|
||||||
|
|
@ -26,24 +26,32 @@ RUN set -eux; \
|
||||||
graphviz-dev \
|
graphviz-dev \
|
||||||
libgts-dev \
|
libgts-dev \
|
||||||
libpq5 \
|
libpq5 \
|
||||||
|
chrony \
|
||||||
graphviz \
|
graphviz \
|
||||||
binutils \
|
binutils \
|
||||||
libproj-dev \
|
libproj-dev \
|
||||||
postgresql-client-17 \
|
postgresql-client-17 \
|
||||||
gdal-bin; \
|
gdal-bin; \
|
||||||
rm -rf /var/lib/apt/lists/*; \
|
rm -rf /var/lib/apt/lists/*; \
|
||||||
pip install --upgrade pip; \
|
pip install --upgrade pip
|
||||||
curl -sSL https://install.python-poetry.org | python3
|
|
||||||
|
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||||
|
ENV PATH="/root/.local/bin:/root/.cargo/bin:$PATH"
|
||||||
|
ENV UV_PROJECT_ENVIRONMENT=/opt/evibes-python
|
||||||
|
ENV PATH="/opt/evibes-python/bin:/root/.local/bin:/root/.cargo/bin:$PATH"
|
||||||
|
|
||||||
|
RUN uv venv /opt/evibes-python
|
||||||
|
ENV VIRTUAL_ENV=/opt/evibes-python
|
||||||
|
|
||||||
COPY pyproject.toml pyproject.toml
|
COPY pyproject.toml pyproject.toml
|
||||||
COPY poetry.lock poetry.lock
|
COPY uv.lock uv.lock
|
||||||
|
|
||||||
RUN poetry config virtualenvs.create false
|
RUN set -eux; \
|
||||||
RUN poetry install --extras="worker openai" --no-interaction --no-ansi
|
uv sync --extra worker --extra openai --locked
|
||||||
|
|
||||||
COPY ./scripts/Docker/beat-entrypoint.sh /usr/local/bin/beat-entrypoint.sh
|
COPY ./scripts/Docker/beat-entrypoint.sh /usr/local/bin/beat-entrypoint.sh
|
||||||
RUN chmod +x /usr/local/bin/beat-entrypoint.sh
|
RUN chmod +x /usr/local/bin/beat-entrypoint.sh
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
ENTRYPOINT ["beat-entrypoint.sh"]
|
ENTRYPOINT ["/usr/bin/bash", "beat-entrypoint.sh"]
|
||||||
57
Dockerfiles/stock_updater.Dockerfile
Normal file
57
Dockerfiles/stock_updater.Dockerfile
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
FROM python:3.12-slim-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 curl; \
|
||||||
|
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
|
||||||
|
|
||||||
|
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||||
|
ENV PATH="/root/.local/bin:/root/.cargo/bin:$PATH"
|
||||||
|
ENV UV_PROJECT_ENVIRONMENT=/opt/evibes-python
|
||||||
|
ENV PATH="/opt/evibes-python/bin:/root/.local/bin:/root/.cargo/bin:$PATH"
|
||||||
|
|
||||||
|
RUN uv venv /opt/evibes-python
|
||||||
|
ENV VIRTUAL_ENV=/opt/evibes-python
|
||||||
|
|
||||||
|
COPY pyproject.toml pyproject.toml
|
||||||
|
COPY uv.lock uv.lock
|
||||||
|
|
||||||
|
RUN set -eux; \
|
||||||
|
uv sync --extra worker --extra openai --locked
|
||||||
|
|
||||||
|
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"]
|
||||||
38
Dockerfiles/supervisor.Dockerfile
Normal file
38
Dockerfiles/supervisor.Dockerfile
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
FROM node:22-bookworm-slim AS build
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
ARG EVIBES_BASE_DOMAIN
|
||||||
|
ARG EVIBES_PROJECT_NAME
|
||||||
|
ENV EVIBES_BASE_DOMAIN=$EVIBES_BASE_DOMAIN
|
||||||
|
ENV EVIBES_PROJECT_NAME=$EVIBES_PROJECT_NAME
|
||||||
|
|
||||||
|
COPY ./supervisor/package.json ./supervisor/package-lock.json ./
|
||||||
|
RUN npm ci --include=optional
|
||||||
|
|
||||||
|
COPY ./supervisor ./
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
FROM node:22-bookworm-slim AS runtime
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
ENV HOST=0.0.0.0
|
||||||
|
ENV PORT=7777
|
||||||
|
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get install -y --no-install-recommends curl \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
RUN addgroup --system --gid 1001 nodeapp \
|
||||||
|
&& adduser --system --uid 1001 --ingroup nodeapp --home /home/nodeapp nodeapp
|
||||||
|
USER nodeapp
|
||||||
|
|
||||||
|
COPY --from=build /app/.output/ ./
|
||||||
|
|
||||||
|
RUN install -d -m 0755 -o nodeapp -g nodeapp /home/nodeapp \
|
||||||
|
&& printf '#!/bin/sh\nif [ \"$DEBUG\" = \"1\" ]; then export NODE_ENV=development; else export NODE_ENV=production; fi\nexec node /app/server/index.mjs\n' > /home/nodeapp/start.sh \
|
||||||
|
&& chown nodeapp:nodeapp /home/nodeapp/start.sh \
|
||||||
|
&& chmod +x /home/nodeapp/start.sh
|
||||||
|
|
||||||
|
USER nodeapp
|
||||||
|
CMD ["sh", "/home/nodeapp/start.sh"]
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# syntax=docker/dockerfile:1
|
# syntax=docker/dockerfile:1
|
||||||
FROM python:3.12-bookworm
|
FROM python:3.12-slim-bookworm
|
||||||
LABEL authors="fureunoir"
|
LABEL authors="fureunoir"
|
||||||
|
|
||||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||||
|
|
@ -13,7 +13,7 @@ WORKDIR /app
|
||||||
RUN set -eux; \
|
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; \
|
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 update; \
|
||||||
apt-get install -y --no-install-recommends wget gnupg; \
|
apt-get install -y --no-install-recommends wget gnupg curl; \
|
||||||
wget -qO - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -; \
|
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" \
|
echo "deb http://apt.postgresql.org/pub/repos/apt bookworm-pgdg main" \
|
||||||
> /etc/apt/sources.list.d/pgdg.list; \
|
> /etc/apt/sources.list.d/pgdg.list; \
|
||||||
|
|
@ -26,24 +26,32 @@ RUN set -eux; \
|
||||||
graphviz-dev \
|
graphviz-dev \
|
||||||
libgts-dev \
|
libgts-dev \
|
||||||
libpq5 \
|
libpq5 \
|
||||||
|
chrony \
|
||||||
graphviz \
|
graphviz \
|
||||||
binutils \
|
binutils \
|
||||||
libproj-dev \
|
libproj-dev \
|
||||||
postgresql-client-17 \
|
postgresql-client-17 \
|
||||||
gdal-bin; \
|
gdal-bin; \
|
||||||
rm -rf /var/lib/apt/lists/*; \
|
rm -rf /var/lib/apt/lists/*; \
|
||||||
pip install --upgrade pip; \
|
pip install --upgrade pip
|
||||||
curl -sSL https://install.python-poetry.org | python3
|
|
||||||
|
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||||
|
ENV PATH="/root/.local/bin:/root/.cargo/bin:$PATH"
|
||||||
|
|
||||||
|
RUN uv venv /opt/evibes-python
|
||||||
|
ENV VIRTUAL_ENV=/opt/evibes-python
|
||||||
|
ENV UV_PROJECT_ENVIRONMENT=/opt/evibes-python
|
||||||
|
ENV PATH="/opt/evibes-python/bin:/root/.local/bin:/root/.cargo/bin:$PATH"
|
||||||
|
|
||||||
COPY pyproject.toml pyproject.toml
|
COPY pyproject.toml pyproject.toml
|
||||||
COPY poetry.lock poetry.lock
|
COPY uv.lock uv.lock
|
||||||
|
|
||||||
RUN poetry config virtualenvs.create false
|
RUN set -eux; \
|
||||||
RUN poetry install --extras="worker openai" --no-interaction --no-ansi
|
uv sync --extra worker --extra openai --locked
|
||||||
|
|
||||||
COPY ./scripts/Docker/worker-entrypoint.sh /usr/local/bin/worker-entrypoint.sh
|
COPY ./scripts/Docker/worker-entrypoint.sh /usr/local/bin/worker-entrypoint.sh
|
||||||
RUN chmod +x /usr/local/bin/worker-entrypoint.sh
|
RUN chmod +x /usr/local/bin/worker-entrypoint.sh
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
ENTRYPOINT ["worker-entrypoint.sh"]
|
ENTRYPOINT ["/usr/bin/bash", "worker-entrypoint.sh"]
|
||||||
196
README.md
196
README.md
|
|
@ -1,154 +1,132 @@
|
||||||
# eVibes
|
# eVibes
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
eVibes is an eCommerce backend service built with Django. It’s designed for flexibility, making it ideal for various use
|
eVibes — a lightweight, production-ready e‑commerce backend. Storefront, product catalog, cart, and orders work out of the box. Minimal complexity, maximum flexibility — install, adjust to your needs, and start selling.
|
||||||
cases and learning Django skills. The project is straightforward to customize, allowing for straightforward editing and
|
|
||||||
extension.
|
- Public issues: https://plane.wiseless.xyz/spaces/issues/dd33cb0ab9b04ef08a10f7eefae6d90c/?board=kanban
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
|
|
||||||
- [Features](#features)
|
- Features
|
||||||
- [Getting Started](#getting-started)
|
- Quick Start
|
||||||
- [Prerequisites](#prerequisites)
|
- Prerequisites
|
||||||
- [Installation](#installation)
|
- Installation
|
||||||
- [Configuration](#configuration)
|
- Configuration
|
||||||
- [Dockerfile](#Dockerfile)
|
- Dockerfile
|
||||||
- [nginx](#nginx)
|
- nginx
|
||||||
- [.env](#env)
|
- .env
|
||||||
- [Usage](#usage)
|
- Usage
|
||||||
- [Contact](#contact)
|
- Contributing
|
||||||
|
- Contact
|
||||||
|
- License
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- **Modular Architecture**: Extend and customize the backend to fit your needs.
|
- Modular backend, easy to extend and customize
|
||||||
- **Dockerized Deployment**: Quick setup and deployment using Docker and Docker Compose.
|
- Dockerized deployment with Docker Compose
|
||||||
- **Asynchronous Task Processing**: Integrated Celery workers and beat scheduler for background tasks.
|
- Celery workers and beat for background tasks
|
||||||
- **GraphQL and REST APIs**: Supports both GraphQL and RESTful API endpoints.
|
- REST and GraphQL APIs
|
||||||
- **Internationalization**: Multilingual support using modeltranslate.
|
- Internationalization with modeltranslation
|
||||||
- **Advanced Caching**: Utilizes Redis for caching and task queuing.
|
- Redis-based caching and queues
|
||||||
- **Security**: Implements JWT authentication and rate limiting.
|
- JWT auth and rate limiting
|
||||||
|
|
||||||
## Getting Started
|
## Quick Start
|
||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
- Docker and Docker Compose are installed on your machine.
|
- Docker and Docker Compose
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
|
|
||||||
1. Clone the repository:
|
1. Clone the repository
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://gitlab.com/wiseless.xyz/eVibes.git
|
git clone https://gitlab.com/wiseless.xyz/eVibes.git
|
||||||
cd eVibes
|
cd eVibes
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Choose the storefront. By default, `main` branch has no storefront included.
|
2. Choose a storefront (optional). The `main` branch ships without a storefront. If you want one, pick a branch:
|
||||||
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-<options: nuxt, next, sk, qwik >
|
git checkout storefront-<nuxt|next|sk|qwik>
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Generate your .env file. Check and confirm the contents afterward.
|
3. Generate your .env file and review its values
|
||||||
|
- Windows
|
||||||
|
```powershell
|
||||||
|
scripts\Windows\generate-environment-file.ps1
|
||||||
|
```
|
||||||
|
- Unix
|
||||||
|
```bash
|
||||||
|
scripts/Unix/generate-environment-file.sh
|
||||||
|
```
|
||||||
|
|
||||||
- Windows
|
4. Install dependencies
|
||||||
```powershell
|
- Windows
|
||||||
scripts\Windows\generate-environment-file.ps1
|
```powershell
|
||||||
```
|
scripts\Windows\install.ps1
|
||||||
- Unix
|
```
|
||||||
```bash
|
- Unix
|
||||||
scripts/Unix/generate-environment-file.sh
|
```bash
|
||||||
```
|
scripts/Unix/install.sh
|
||||||
|
```
|
||||||
|
|
||||||
4. Install all the dependencies.
|
5. Run the stack
|
||||||
|
- Windows
|
||||||
|
```powershell
|
||||||
|
scripts\Windows\run.ps1
|
||||||
|
```
|
||||||
|
- Unix
|
||||||
|
```bash
|
||||||
|
scripts/Unix/run.sh
|
||||||
|
```
|
||||||
|
|
||||||
- Windows
|
6. Production checklist
|
||||||
```powershell
|
- Include `nginx.conf` into your Nginx setup
|
||||||
scripts\Windows\install.ps1
|
- Issue TLS certs with Certbot (https://certbot.eff.org/)
|
||||||
```
|
|
||||||
- Unix
|
|
||||||
```bash
|
|
||||||
scripts/Unix/install.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
5. Spin it up.
|
|
||||||
|
|
||||||
- Windows
|
|
||||||
```powershell
|
|
||||||
scripts\Windows\run.ps1
|
|
||||||
```
|
|
||||||
- Unix
|
|
||||||
```bash
|
|
||||||
scripts/Unix/run.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
6. Bring to production.
|
|
||||||
|
|
||||||
Include `nginx` file to your nginx configuration, you really want to install and
|
|
||||||
run [Certbot](https://certbot.eff.org/) afterward!
|
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
### Dockerfile
|
### Dockerfile
|
||||||
|
If you rely on locale mirrors, adjust Debian sources before running installation scripts:
|
||||||
Remember to change the
|
```
|
||||||
`RUN sed -i 's|https://deb.debian.org/debian|https://ftp.<locale>.debian.org/debian|g' /etc/apt/sources.list.d/debian.sources`
|
RUN sed -i 's|https://deb.debian.org/debian|https://ftp.<locale>.debian.org/debian|g' /etc/apt/sources.list.d/debian.sources
|
||||||
before running installment scripts
|
```
|
||||||
|
|
||||||
### nginx
|
### nginx
|
||||||
|
- Comment out SSL-related lines
|
||||||
Please comment-out SSL-related lines, then apply necessary configurations, run `certbot --cert-only --nginx`,
|
- Apply your domain-specific settings
|
||||||
decomment previously commented lines and enjoy eVibes over HTTPS!
|
- Run `certbot --cert-only --nginx`
|
||||||
|
- Uncomment SSL lines and reload Nginx
|
||||||
|
|
||||||
### .env
|
### .env
|
||||||
|
After generation, review and update secrets and credentials (API keys, DB password, Redis password, etc.).
|
||||||
After .env file generation, you may want to edit some of its values, such as macroservices` API keys, database password,
|
|
||||||
redis password, etc.
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
- Add the necessary subdomains to DNS-settings of your domain, those are:
|
- DNS records you’ll typically want:
|
||||||
|
1. @.your-domain.com
|
||||||
|
2. www.your-domain.com
|
||||||
|
3. api.your-domain.com
|
||||||
|
4. prometheus.your-domain.com
|
||||||
|
|
||||||
1. @.your-domain.com
|
- Once running, access:
|
||||||
2. www.your-domain.com
|
- API root / Admin redirect: http://api.localhost:8000/
|
||||||
3. api.your-domain.com
|
- REST docs: http://api.localhost:8000/docs/swagger or http://api.localhost:8000/docs/redoc
|
||||||
4. b2b.your-domain.com
|
- GraphQL: http://api.localhost:8000/graphql/
|
||||||
5. prometheus.your-domain.com
|
|
||||||
|
|
||||||
- Add these lines to your hosts-file to use django-hosts functionality on localhost(*DEVELOPMENT ONLY*):
|
## Contributing
|
||||||
|
|
||||||
```hosts
|
- Track and report issues here: https://plane.wiseless.xyz/spaces/issues/dd33cb0ab9b04ef08a10f7eefae6d90c/?board=list
|
||||||
127.0.0.1 api.localhost
|
- Pull requests are welcome. Please keep changes minimal and focused.
|
||||||
127.0.0.1 b2b.localhost
|
|
||||||
```
|
|
||||||
|
|
||||||
Once the services are up and running, you can access the application at
|
|
||||||
`http://api.your-domain.com`(http://api.localhost:8000).
|
|
||||||
|
|
||||||
- **Django Admin**: `http://api.your-domain.com/` (will redirect to admin)
|
|
||||||
- **API Docs**:
|
|
||||||
- REST API: `http://api.localhost:8000/docs/swagger` or `http://api.localhost:8000/docs/redoc`
|
|
||||||
- GraphQL API: `http://api.localhost:8000/graphql/`
|
|
||||||
|
|
||||||
## Uninstall eVibes
|
|
||||||
|
|
||||||
You are not planning to do that, aren't you?
|
|
||||||
|
|
||||||
- Windows
|
|
||||||
```powershell
|
|
||||||
scripts\Windows\uninstall.ps1
|
|
||||||
```
|
|
||||||
- Unix
|
|
||||||
```bash
|
|
||||||
scripts/Unix/uninstall.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
## Contact
|
## Contact
|
||||||
|
|
||||||
- **Author**: Egor "fureunoir" Gorbunov
|
- Author: Egor "fureunoir" Gorbunov
|
||||||
- Email: contact@fureunoir.com
|
- Email: contact@fureunoir.com
|
||||||
- Telegram: [@fureunoir](https://t.me/fureunoir)
|
- Telegram: https://t.me/fureunoir
|
||||||
|
|
||||||

|
## License
|
||||||
|
|
||||||
|
This project is licensed under the terms of the LICENSE file included in this repository.
|
||||||
|
|
||||||
|

|
||||||
Binary file not shown.
|
|
@ -1,71 +0,0 @@
|
||||||
#
|
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
|
||||||
"Report-Msgid-Bugs-To: \n"
|
|
||||||
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
|
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language: ar-ar\n"
|
|
||||||
"MIME-Version: 1.0\n"
|
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
|
||||||
|
|
||||||
#: blog/apps.py:8
|
|
||||||
msgid "blog"
|
|
||||||
msgstr "المدونة"
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "post title"
|
|
||||||
msgstr "عنوان المنشور"
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "title"
|
|
||||||
msgstr "العنوان"
|
|
||||||
|
|
||||||
#: blog/models.py:64
|
|
||||||
msgid "post"
|
|
||||||
msgstr "المنشور"
|
|
||||||
|
|
||||||
#: blog/models.py:65
|
|
||||||
msgid "posts"
|
|
||||||
msgstr "المنشورات"
|
|
||||||
|
|
||||||
#: blog/models.py:69
|
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
|
||||||
msgstr ""
|
|
||||||
"ملفات تخفيض السعر غير مدعومة Yer - استخدم محتوى تخفيض السعر بدلاً من ذلك!"
|
|
||||||
|
|
||||||
#: blog/models.py:71
|
|
||||||
msgid ""
|
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr "يجب توفير ملف ترميز أو محتوى ترميز مخفض - متنافيان"
|
|
||||||
|
|
||||||
#: blog/models.py:82
|
|
||||||
msgid "internal tag identifier for the post tag"
|
|
||||||
msgstr "معرّف العلامة الداخلي لعلامة المنشور"
|
|
||||||
|
|
||||||
#: blog/models.py:83
|
|
||||||
msgid "tag name"
|
|
||||||
msgstr "اسم العلامة"
|
|
||||||
|
|
||||||
#: blog/models.py:87
|
|
||||||
msgid "user-friendly name for the post tag"
|
|
||||||
msgstr "اسم سهل الاستخدام لعلامة المنشور"
|
|
||||||
|
|
||||||
#: blog/models.py:88
|
|
||||||
msgid "tag display name"
|
|
||||||
msgstr "اسم عرض العلامة"
|
|
||||||
|
|
||||||
#: blog/models.py:96
|
|
||||||
msgid "post tag"
|
|
||||||
msgstr "علامة المشاركة"
|
|
||||||
|
|
||||||
#: blog/models.py:97
|
|
||||||
msgid "post tags"
|
|
||||||
msgstr "علامات المشاركة"
|
|
||||||
|
|
||||||
#~ msgid "eVibes Engine"
|
|
||||||
#~ msgstr "محرك eVibes"
|
|
||||||
Binary file not shown.
|
|
@ -1,73 +0,0 @@
|
||||||
#
|
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
|
||||||
"Report-Msgid-Bugs-To: \n"
|
|
||||||
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
|
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language: cs-cz\n"
|
|
||||||
"MIME-Version: 1.0\n"
|
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
|
||||||
|
|
||||||
#: blog/apps.py:8
|
|
||||||
msgid "blog"
|
|
||||||
msgstr "Blog"
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "post title"
|
|
||||||
msgstr "Název příspěvku"
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "title"
|
|
||||||
msgstr "Název"
|
|
||||||
|
|
||||||
#: blog/models.py:64
|
|
||||||
msgid "post"
|
|
||||||
msgstr "Příspěvek"
|
|
||||||
|
|
||||||
#: blog/models.py:65
|
|
||||||
msgid "posts"
|
|
||||||
msgstr "Příspěvky"
|
|
||||||
|
|
||||||
#: blog/models.py:69
|
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
|
||||||
msgstr ""
|
|
||||||
"Soubory Markdown nejsou podporovány - místo toho použijte obsah Markdown!"
|
|
||||||
|
|
||||||
#: blog/models.py:71
|
|
||||||
msgid ""
|
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
|
||||||
"musí být poskytnut soubor markdown nebo obsah markdown - vzájemně se "
|
|
||||||
"vylučují."
|
|
||||||
|
|
||||||
#: blog/models.py:82
|
|
||||||
msgid "internal tag identifier for the post tag"
|
|
||||||
msgstr "interní identifikátor tagu pro tag příspěvku"
|
|
||||||
|
|
||||||
#: blog/models.py:83
|
|
||||||
msgid "tag name"
|
|
||||||
msgstr "Název štítku"
|
|
||||||
|
|
||||||
#: blog/models.py:87
|
|
||||||
msgid "user-friendly name for the post tag"
|
|
||||||
msgstr "Uživatelsky přívětivý název pro značku příspěvku"
|
|
||||||
|
|
||||||
#: blog/models.py:88
|
|
||||||
msgid "tag display name"
|
|
||||||
msgstr "Zobrazení názvu štítku"
|
|
||||||
|
|
||||||
#: blog/models.py:96
|
|
||||||
msgid "post tag"
|
|
||||||
msgstr "Označení příspěvku"
|
|
||||||
|
|
||||||
#: blog/models.py:97
|
|
||||||
msgid "post tags"
|
|
||||||
msgstr "Štítky příspěvků"
|
|
||||||
|
|
||||||
#~ msgid "eVibes Engine"
|
|
||||||
#~ msgstr "Motor eVibes"
|
|
||||||
Binary file not shown.
|
|
@ -1,71 +0,0 @@
|
||||||
#
|
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
|
||||||
"Report-Msgid-Bugs-To: \n"
|
|
||||||
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
|
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language: da-dk\n"
|
|
||||||
"MIME-Version: 1.0\n"
|
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
|
||||||
|
|
||||||
#: blog/apps.py:8
|
|
||||||
msgid "blog"
|
|
||||||
msgstr "Blog"
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "post title"
|
|
||||||
msgstr "Indlæggets titel"
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "title"
|
|
||||||
msgstr "Titel"
|
|
||||||
|
|
||||||
#: blog/models.py:64
|
|
||||||
msgid "post"
|
|
||||||
msgstr "Indlæg"
|
|
||||||
|
|
||||||
#: blog/models.py:65
|
|
||||||
msgid "posts"
|
|
||||||
msgstr "Indlæg"
|
|
||||||
|
|
||||||
#: blog/models.py:69
|
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
|
||||||
msgstr "Markdown-filer understøttes ikke - brug markdown-indhold i stedet!"
|
|
||||||
|
|
||||||
#: blog/models.py:71
|
|
||||||
msgid ""
|
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
|
||||||
"en markdown-fil eller markdown-indhold skal leveres - gensidigt udelukkende"
|
|
||||||
|
|
||||||
#: blog/models.py:82
|
|
||||||
msgid "internal tag identifier for the post tag"
|
|
||||||
msgstr "intern tag-identifikator for indlægs-tagget"
|
|
||||||
|
|
||||||
#: blog/models.py:83
|
|
||||||
msgid "tag name"
|
|
||||||
msgstr "Tag-navn"
|
|
||||||
|
|
||||||
#: blog/models.py:87
|
|
||||||
msgid "user-friendly name for the post tag"
|
|
||||||
msgstr "Brugervenligt navn til posttagget"
|
|
||||||
|
|
||||||
#: blog/models.py:88
|
|
||||||
msgid "tag display name"
|
|
||||||
msgstr "Navn på tag-visning"
|
|
||||||
|
|
||||||
#: blog/models.py:96
|
|
||||||
msgid "post tag"
|
|
||||||
msgstr "Tag til indlæg"
|
|
||||||
|
|
||||||
#: blog/models.py:97
|
|
||||||
msgid "post tags"
|
|
||||||
msgstr "Tags til indlæg"
|
|
||||||
|
|
||||||
#~ msgid "eVibes Engine"
|
|
||||||
#~ msgstr "eVibes-motor"
|
|
||||||
Binary file not shown.
|
|
@ -1,74 +0,0 @@
|
||||||
#
|
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
|
||||||
"Report-Msgid-Bugs-To: \n"
|
|
||||||
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
|
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language: de-de\n"
|
|
||||||
"MIME-Version: 1.0\n"
|
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
|
||||||
|
|
||||||
#: blog/apps.py:8
|
|
||||||
msgid "blog"
|
|
||||||
msgstr "Blog"
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "post title"
|
|
||||||
msgstr "Titel des Beitrags"
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "title"
|
|
||||||
msgstr "Titel"
|
|
||||||
|
|
||||||
#: blog/models.py:64
|
|
||||||
msgid "post"
|
|
||||||
msgstr "Beitrag"
|
|
||||||
|
|
||||||
#: blog/models.py:65
|
|
||||||
msgid "posts"
|
|
||||||
msgstr "Beiträge"
|
|
||||||
|
|
||||||
#: blog/models.py:69
|
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
|
||||||
msgstr ""
|
|
||||||
"Markdown-Dateien werden nicht unterstützt - verwenden Sie stattdessen "
|
|
||||||
"Markdown-Inhalte!"
|
|
||||||
|
|
||||||
#: blog/models.py:71
|
|
||||||
msgid ""
|
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
|
||||||
"eine Markdown-Datei oder ein Markdown-Inhalt muss bereitgestellt werden - "
|
|
||||||
"beide schließen sich gegenseitig aus"
|
|
||||||
|
|
||||||
#: blog/models.py:82
|
|
||||||
msgid "internal tag identifier for the post tag"
|
|
||||||
msgstr "interner Tag-Bezeichner für den Post-Tag"
|
|
||||||
|
|
||||||
#: blog/models.py:83
|
|
||||||
msgid "tag name"
|
|
||||||
msgstr "Tag name"
|
|
||||||
|
|
||||||
#: blog/models.py:87
|
|
||||||
msgid "user-friendly name for the post tag"
|
|
||||||
msgstr "Benutzerfreundlicher Name für das Post-Tag"
|
|
||||||
|
|
||||||
#: blog/models.py:88
|
|
||||||
msgid "tag display name"
|
|
||||||
msgstr "Tag-Anzeigename"
|
|
||||||
|
|
||||||
#: blog/models.py:96
|
|
||||||
msgid "post tag"
|
|
||||||
msgstr "Tag eintragen"
|
|
||||||
|
|
||||||
#: blog/models.py:97
|
|
||||||
msgid "post tags"
|
|
||||||
msgstr "Tags eintragen"
|
|
||||||
|
|
||||||
#~ msgid "eVibes Engine"
|
|
||||||
#~ msgstr "eVibes Motor"
|
|
||||||
Binary file not shown.
|
|
@ -1,81 +0,0 @@
|
||||||
# EVIBES GETTEXT TRANSLATIONS
|
|
||||||
# Copyright (C) 2025 EGOR <FUREUNOIR> GORBUNOV
|
|
||||||
# This file is distributed under the same license as the EVIBES package.
|
|
||||||
# EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>, 2025.
|
|
||||||
#
|
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
|
||||||
"Report-Msgid-Bugs-To: \n"
|
|
||||||
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
|
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language: \n"
|
|
||||||
"MIME-Version: 1.0\n"
|
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
|
||||||
|
|
||||||
#: blog/apps.py:8
|
|
||||||
msgid "blog"
|
|
||||||
msgstr "Blog"
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "post title"
|
|
||||||
msgstr "Post's title"
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "title"
|
|
||||||
msgstr "Title"
|
|
||||||
|
|
||||||
#: blog/models.py:64
|
|
||||||
msgid "post"
|
|
||||||
msgstr "Post"
|
|
||||||
|
|
||||||
#: blog/models.py:65
|
|
||||||
msgid "posts"
|
|
||||||
msgstr "Posts"
|
|
||||||
|
|
||||||
#: blog/models.py:69
|
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
|
||||||
msgstr "Markdown files are not supported yer - use markdown content instead!"
|
|
||||||
|
|
||||||
#: blog/models.py:71
|
|
||||||
msgid ""
|
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
|
|
||||||
#: blog/models.py:82
|
|
||||||
msgid "internal tag identifier for the post tag"
|
|
||||||
msgstr "internal tag identifier for the post tag"
|
|
||||||
|
|
||||||
#: blog/models.py:83
|
|
||||||
msgid "tag name"
|
|
||||||
msgstr "Tag name"
|
|
||||||
|
|
||||||
#: blog/models.py:87
|
|
||||||
msgid "user-friendly name for the post tag"
|
|
||||||
msgstr "User-friendly name for the post tag"
|
|
||||||
|
|
||||||
#: blog/models.py:88
|
|
||||||
msgid "tag display name"
|
|
||||||
msgstr "Tag display name"
|
|
||||||
|
|
||||||
#: blog/models.py:96
|
|
||||||
msgid "post tag"
|
|
||||||
msgstr "Post tag"
|
|
||||||
|
|
||||||
#: blog/models.py:97
|
|
||||||
msgid "post tags"
|
|
||||||
msgstr "Post tags"
|
|
||||||
|
|
||||||
#~ msgid "eVibes Engine"
|
|
||||||
#~ msgstr "eVibes Engine"
|
|
||||||
|
|
||||||
#~ msgid "(no content yet)"
|
|
||||||
#~ msgstr "(no content yet)"
|
|
||||||
|
|
||||||
#~ msgid "rendered HTML"
|
|
||||||
#~ msgstr "Rendered HTML"
|
|
||||||
Binary file not shown.
|
|
@ -1,71 +0,0 @@
|
||||||
#
|
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
|
||||||
"Report-Msgid-Bugs-To: \n"
|
|
||||||
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
|
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language: en-us\n"
|
|
||||||
"MIME-Version: 1.0\n"
|
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
|
||||||
|
|
||||||
#: blog/apps.py:8
|
|
||||||
msgid "blog"
|
|
||||||
msgstr "Blog"
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "post title"
|
|
||||||
msgstr "Post's title"
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "title"
|
|
||||||
msgstr "Title"
|
|
||||||
|
|
||||||
#: blog/models.py:64
|
|
||||||
msgid "post"
|
|
||||||
msgstr "Post"
|
|
||||||
|
|
||||||
#: blog/models.py:65
|
|
||||||
msgid "posts"
|
|
||||||
msgstr "Posts"
|
|
||||||
|
|
||||||
#: blog/models.py:69
|
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
|
||||||
msgstr "Markdown files are not supported yer - use markdown content instead!"
|
|
||||||
|
|
||||||
#: blog/models.py:71
|
|
||||||
msgid ""
|
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
|
|
||||||
#: blog/models.py:82
|
|
||||||
msgid "internal tag identifier for the post tag"
|
|
||||||
msgstr "internal tag identifier for the post tag"
|
|
||||||
|
|
||||||
#: blog/models.py:83
|
|
||||||
msgid "tag name"
|
|
||||||
msgstr "Tag name"
|
|
||||||
|
|
||||||
#: blog/models.py:87
|
|
||||||
msgid "user-friendly name for the post tag"
|
|
||||||
msgstr "User-friendly name for the post tag"
|
|
||||||
|
|
||||||
#: blog/models.py:88
|
|
||||||
msgid "tag display name"
|
|
||||||
msgstr "Tag display name"
|
|
||||||
|
|
||||||
#: blog/models.py:96
|
|
||||||
msgid "post tag"
|
|
||||||
msgstr "Post tag"
|
|
||||||
|
|
||||||
#: blog/models.py:97
|
|
||||||
msgid "post tags"
|
|
||||||
msgstr "Post tags"
|
|
||||||
|
|
||||||
#~ msgid "eVibes Engine"
|
|
||||||
#~ msgstr "eVibes Engine"
|
|
||||||
Binary file not shown.
|
|
@ -1,73 +0,0 @@
|
||||||
#
|
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
|
||||||
"Report-Msgid-Bugs-To: \n"
|
|
||||||
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
|
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language: es-es\n"
|
|
||||||
"MIME-Version: 1.0\n"
|
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
|
||||||
|
|
||||||
#: blog/apps.py:8
|
|
||||||
msgid "blog"
|
|
||||||
msgstr "Blog"
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "post title"
|
|
||||||
msgstr "Título del mensaje"
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "title"
|
|
||||||
msgstr "Título"
|
|
||||||
|
|
||||||
#: blog/models.py:64
|
|
||||||
msgid "post"
|
|
||||||
msgstr "Publicar en"
|
|
||||||
|
|
||||||
#: blog/models.py:65
|
|
||||||
msgid "posts"
|
|
||||||
msgstr "Puestos"
|
|
||||||
|
|
||||||
#: blog/models.py:69
|
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
|
||||||
msgstr ""
|
|
||||||
"No se admiten archivos Markdown - ¡utiliza contenido Markdown en su lugar!"
|
|
||||||
|
|
||||||
#: blog/models.py:71
|
|
||||||
msgid ""
|
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
|
||||||
"se debe proporcionar un archivo markdown o contenido markdown - mutuamente "
|
|
||||||
"excluyentes"
|
|
||||||
|
|
||||||
#: blog/models.py:82
|
|
||||||
msgid "internal tag identifier for the post tag"
|
|
||||||
msgstr "identificador interno de la etiqueta post"
|
|
||||||
|
|
||||||
#: blog/models.py:83
|
|
||||||
msgid "tag name"
|
|
||||||
msgstr "Nombre de la etiqueta"
|
|
||||||
|
|
||||||
#: blog/models.py:87
|
|
||||||
msgid "user-friendly name for the post tag"
|
|
||||||
msgstr "Nombre fácil de usar para la etiqueta de la entrada"
|
|
||||||
|
|
||||||
#: blog/models.py:88
|
|
||||||
msgid "tag display name"
|
|
||||||
msgstr "Nombre de la etiqueta"
|
|
||||||
|
|
||||||
#: blog/models.py:96
|
|
||||||
msgid "post tag"
|
|
||||||
msgstr "Etiqueta postal"
|
|
||||||
|
|
||||||
#: blog/models.py:97
|
|
||||||
msgid "post tags"
|
|
||||||
msgstr "Etiquetas"
|
|
||||||
|
|
||||||
#~ msgid "eVibes Engine"
|
|
||||||
#~ msgstr "Motor eVibes"
|
|
||||||
Binary file not shown.
|
|
@ -1,74 +0,0 @@
|
||||||
#
|
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
|
||||||
"Report-Msgid-Bugs-To: \n"
|
|
||||||
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
|
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language: fr-fr\n"
|
|
||||||
"MIME-Version: 1.0\n"
|
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
|
||||||
|
|
||||||
#: blog/apps.py:8
|
|
||||||
msgid "blog"
|
|
||||||
msgstr "Blog"
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "post title"
|
|
||||||
msgstr "Titre du message"
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "title"
|
|
||||||
msgstr "Titre"
|
|
||||||
|
|
||||||
#: blog/models.py:64
|
|
||||||
msgid "post"
|
|
||||||
msgstr "Poste"
|
|
||||||
|
|
||||||
#: blog/models.py:65
|
|
||||||
msgid "posts"
|
|
||||||
msgstr "Postes"
|
|
||||||
|
|
||||||
#: blog/models.py:69
|
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
|
||||||
msgstr ""
|
|
||||||
"Les fichiers Markdown ne sont pas pris en charge - utilisez plutôt du "
|
|
||||||
"contenu Markdown !"
|
|
||||||
|
|
||||||
#: blog/models.py:71
|
|
||||||
msgid ""
|
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
|
||||||
"un fichier markdown ou un contenu markdown doit être fourni - ils s'excluent "
|
|
||||||
"mutuellement"
|
|
||||||
|
|
||||||
#: blog/models.py:82
|
|
||||||
msgid "internal tag identifier for the post tag"
|
|
||||||
msgstr "identifiant interne de la balise post"
|
|
||||||
|
|
||||||
#: blog/models.py:83
|
|
||||||
msgid "tag name"
|
|
||||||
msgstr "Nom du jour"
|
|
||||||
|
|
||||||
#: blog/models.py:87
|
|
||||||
msgid "user-friendly name for the post tag"
|
|
||||||
msgstr "Nom convivial pour la balise post"
|
|
||||||
|
|
||||||
#: blog/models.py:88
|
|
||||||
msgid "tag display name"
|
|
||||||
msgstr "Nom d'affichage de l'étiquette"
|
|
||||||
|
|
||||||
#: blog/models.py:96
|
|
||||||
msgid "post tag"
|
|
||||||
msgstr "Tag de poste"
|
|
||||||
|
|
||||||
#: blog/models.py:97
|
|
||||||
msgid "post tags"
|
|
||||||
msgstr "Tags de la poste"
|
|
||||||
|
|
||||||
#~ msgid "eVibes Engine"
|
|
||||||
#~ msgstr "Moteur eVibes"
|
|
||||||
|
|
@ -1,70 +0,0 @@
|
||||||
# EVIBES GETTEXT TRANSLATIONS
|
|
||||||
# Copyright (C) 2025 EGOR <FUREUNOIR> GORBUNOV
|
|
||||||
# This file is distributed under the same license as the EVIBES package.
|
|
||||||
# EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>, 2025.
|
|
||||||
#
|
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
|
||||||
"Report-Msgid-Bugs-To: \n"
|
|
||||||
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
|
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language: \n"
|
|
||||||
"MIME-Version: 1.0\n"
|
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
|
||||||
|
|
||||||
#: blog/apps.py:8
|
|
||||||
msgid "blog"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "post title"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "title"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: blog/models.py:64
|
|
||||||
msgid "post"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: blog/models.py:65
|
|
||||||
msgid "posts"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: blog/models.py:69
|
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: blog/models.py:71
|
|
||||||
msgid ""
|
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: blog/models.py:82
|
|
||||||
msgid "internal tag identifier for the post tag"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: blog/models.py:83
|
|
||||||
msgid "tag name"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: blog/models.py:87
|
|
||||||
msgid "user-friendly name for the post tag"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: blog/models.py:88
|
|
||||||
msgid "tag display name"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: blog/models.py:96
|
|
||||||
msgid "post tag"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: blog/models.py:97
|
|
||||||
msgid "post tags"
|
|
||||||
msgstr ""
|
|
||||||
Binary file not shown.
|
|
@ -1,72 +0,0 @@
|
||||||
#
|
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
|
||||||
"Report-Msgid-Bugs-To: \n"
|
|
||||||
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
|
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language: it-it\n"
|
|
||||||
"MIME-Version: 1.0\n"
|
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
|
||||||
|
|
||||||
#: blog/apps.py:8
|
|
||||||
msgid "blog"
|
|
||||||
msgstr "Blog"
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "post title"
|
|
||||||
msgstr "Titolo del post"
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "title"
|
|
||||||
msgstr "Titolo"
|
|
||||||
|
|
||||||
#: blog/models.py:64
|
|
||||||
msgid "post"
|
|
||||||
msgstr "Posta"
|
|
||||||
|
|
||||||
#: blog/models.py:65
|
|
||||||
msgid "posts"
|
|
||||||
msgstr "Messaggi"
|
|
||||||
|
|
||||||
#: blog/models.py:69
|
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
|
||||||
msgstr "I file Markdown non sono supportati: usa invece i contenuti Markdown!"
|
|
||||||
|
|
||||||
#: blog/models.py:71
|
|
||||||
msgid ""
|
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
|
||||||
"deve essere fornito un file markdown o un contenuto markdown - si escludono "
|
|
||||||
"a vicenda"
|
|
||||||
|
|
||||||
#: blog/models.py:82
|
|
||||||
msgid "internal tag identifier for the post tag"
|
|
||||||
msgstr "identificatore interno del tag post"
|
|
||||||
|
|
||||||
#: blog/models.py:83
|
|
||||||
msgid "tag name"
|
|
||||||
msgstr "Nome del tag"
|
|
||||||
|
|
||||||
#: blog/models.py:87
|
|
||||||
msgid "user-friendly name for the post tag"
|
|
||||||
msgstr "Nome intuitivo per il tag del post"
|
|
||||||
|
|
||||||
#: blog/models.py:88
|
|
||||||
msgid "tag display name"
|
|
||||||
msgstr "Nome del tag"
|
|
||||||
|
|
||||||
#: blog/models.py:96
|
|
||||||
msgid "post tag"
|
|
||||||
msgstr "Post tag"
|
|
||||||
|
|
||||||
#: blog/models.py:97
|
|
||||||
msgid "post tags"
|
|
||||||
msgstr "Tag dei post"
|
|
||||||
|
|
||||||
#~ msgid "eVibes Engine"
|
|
||||||
#~ msgstr "Motore eVibes"
|
|
||||||
Binary file not shown.
|
|
@ -1,74 +0,0 @@
|
||||||
#
|
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
|
||||||
"Report-Msgid-Bugs-To: \n"
|
|
||||||
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
|
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language: ja-jp\n"
|
|
||||||
"MIME-Version: 1.0\n"
|
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
|
||||||
|
|
||||||
#: blog/apps.py:8
|
|
||||||
msgid "blog"
|
|
||||||
msgstr "ブログ"
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "post title"
|
|
||||||
msgstr "投稿タイトル"
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "title"
|
|
||||||
msgstr "タイトル"
|
|
||||||
|
|
||||||
#: blog/models.py:64
|
|
||||||
msgid "post"
|
|
||||||
msgstr "ポスト"
|
|
||||||
|
|
||||||
#: blog/models.py:65
|
|
||||||
msgid "posts"
|
|
||||||
msgstr "投稿"
|
|
||||||
|
|
||||||
#: blog/models.py:69
|
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
|
||||||
msgstr ""
|
|
||||||
"マークダウン・ファイルはサポートされていません - 代わりにマークダウン・コンテ"
|
|
||||||
"ンツを使用してください!"
|
|
||||||
|
|
||||||
#: blog/models.py:71
|
|
||||||
msgid ""
|
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
|
||||||
"マークダウン・ファイルまたはマークダウン・コンテンツを提供しなければならな"
|
|
||||||
"い。"
|
|
||||||
|
|
||||||
#: blog/models.py:82
|
|
||||||
msgid "internal tag identifier for the post tag"
|
|
||||||
msgstr "投稿タグの内部タグ識別子"
|
|
||||||
|
|
||||||
#: blog/models.py:83
|
|
||||||
msgid "tag name"
|
|
||||||
msgstr "タグ名"
|
|
||||||
|
|
||||||
#: blog/models.py:87
|
|
||||||
msgid "user-friendly name for the post tag"
|
|
||||||
msgstr "投稿タグのユーザーフレンドリーな名前"
|
|
||||||
|
|
||||||
#: blog/models.py:88
|
|
||||||
msgid "tag display name"
|
|
||||||
msgstr "タグ表示名"
|
|
||||||
|
|
||||||
#: blog/models.py:96
|
|
||||||
msgid "post tag"
|
|
||||||
msgstr "投稿タグ"
|
|
||||||
|
|
||||||
#: blog/models.py:97
|
|
||||||
msgid "post tags"
|
|
||||||
msgstr "投稿タグ"
|
|
||||||
|
|
||||||
#~ msgid "eVibes Engine"
|
|
||||||
#~ msgstr "eVibesエンジン"
|
|
||||||
|
|
@ -1,70 +0,0 @@
|
||||||
# EVIBES GETTEXT TRANSLATIONS
|
|
||||||
# Copyright (C) 2025 EGOR <FUREUNOIR> GORBUNOV
|
|
||||||
# This file is distributed under the same license as the EVIBES package.
|
|
||||||
# EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>, 2025.
|
|
||||||
#
|
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
|
||||||
"Report-Msgid-Bugs-To: \n"
|
|
||||||
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
|
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language: \n"
|
|
||||||
"MIME-Version: 1.0\n"
|
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
|
||||||
|
|
||||||
#: blog/apps.py:8
|
|
||||||
msgid "blog"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "post title"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "title"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: blog/models.py:64
|
|
||||||
msgid "post"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: blog/models.py:65
|
|
||||||
msgid "posts"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: blog/models.py:69
|
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: blog/models.py:71
|
|
||||||
msgid ""
|
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: blog/models.py:82
|
|
||||||
msgid "internal tag identifier for the post tag"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: blog/models.py:83
|
|
||||||
msgid "tag name"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: blog/models.py:87
|
|
||||||
msgid "user-friendly name for the post tag"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: blog/models.py:88
|
|
||||||
msgid "tag display name"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: blog/models.py:96
|
|
||||||
msgid "post tag"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: blog/models.py:97
|
|
||||||
msgid "post tags"
|
|
||||||
msgstr ""
|
|
||||||
Binary file not shown.
|
|
@ -1,74 +0,0 @@
|
||||||
#
|
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
|
||||||
"Report-Msgid-Bugs-To: \n"
|
|
||||||
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
|
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language: nl-nl\n"
|
|
||||||
"MIME-Version: 1.0\n"
|
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
|
||||||
|
|
||||||
#: blog/apps.py:8
|
|
||||||
msgid "blog"
|
|
||||||
msgstr "Blog"
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "post title"
|
|
||||||
msgstr "Titel van de post"
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "title"
|
|
||||||
msgstr "Titel"
|
|
||||||
|
|
||||||
#: blog/models.py:64
|
|
||||||
msgid "post"
|
|
||||||
msgstr "Plaats"
|
|
||||||
|
|
||||||
#: blog/models.py:65
|
|
||||||
msgid "posts"
|
|
||||||
msgstr "Berichten"
|
|
||||||
|
|
||||||
#: blog/models.py:69
|
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
|
||||||
msgstr ""
|
|
||||||
"Markdown-bestanden worden niet ondersteund - gebruik in plaats daarvan "
|
|
||||||
"markdown-inhoud!"
|
|
||||||
|
|
||||||
#: blog/models.py:71
|
|
||||||
msgid ""
|
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
|
||||||
"er moet een markdown-bestand of markdown-inhoud worden geleverd - wederzijds "
|
|
||||||
"exclusief"
|
|
||||||
|
|
||||||
#: blog/models.py:82
|
|
||||||
msgid "internal tag identifier for the post tag"
|
|
||||||
msgstr "interne tagidentifier voor de posttag"
|
|
||||||
|
|
||||||
#: blog/models.py:83
|
|
||||||
msgid "tag name"
|
|
||||||
msgstr "Tag naam"
|
|
||||||
|
|
||||||
#: blog/models.py:87
|
|
||||||
msgid "user-friendly name for the post tag"
|
|
||||||
msgstr "Gebruiksvriendelijke naam voor de posttag"
|
|
||||||
|
|
||||||
#: blog/models.py:88
|
|
||||||
msgid "tag display name"
|
|
||||||
msgstr "Tag weergavenaam"
|
|
||||||
|
|
||||||
#: blog/models.py:96
|
|
||||||
msgid "post tag"
|
|
||||||
msgstr "Post tag"
|
|
||||||
|
|
||||||
#: blog/models.py:97
|
|
||||||
msgid "post tags"
|
|
||||||
msgstr "Post tags"
|
|
||||||
|
|
||||||
#~ msgid "eVibes Engine"
|
|
||||||
#~ msgstr "eVibes motor"
|
|
||||||
Binary file not shown.
|
|
@ -1,73 +0,0 @@
|
||||||
#
|
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
|
||||||
"Report-Msgid-Bugs-To: \n"
|
|
||||||
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
|
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language: pl-pl\n"
|
|
||||||
"MIME-Version: 1.0\n"
|
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
|
||||||
|
|
||||||
#: blog/apps.py:8
|
|
||||||
msgid "blog"
|
|
||||||
msgstr "Blog"
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "post title"
|
|
||||||
msgstr "Tytuł postu"
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "title"
|
|
||||||
msgstr "Tytuł"
|
|
||||||
|
|
||||||
#: blog/models.py:64
|
|
||||||
msgid "post"
|
|
||||||
msgstr "Post"
|
|
||||||
|
|
||||||
#: blog/models.py:65
|
|
||||||
msgid "posts"
|
|
||||||
msgstr "Posty"
|
|
||||||
|
|
||||||
#: blog/models.py:69
|
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
|
||||||
msgstr ""
|
|
||||||
"Pliki Markdown nie są obsługiwane - zamiast tego użyj zawartości Markdown!"
|
|
||||||
|
|
||||||
#: blog/models.py:71
|
|
||||||
msgid ""
|
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
|
||||||
"należy dostarczyć plik markdown lub zawartość markdown - wzajemnie się "
|
|
||||||
"wykluczające"
|
|
||||||
|
|
||||||
#: blog/models.py:82
|
|
||||||
msgid "internal tag identifier for the post tag"
|
|
||||||
msgstr "wewnętrzny identyfikator tagu posta"
|
|
||||||
|
|
||||||
#: blog/models.py:83
|
|
||||||
msgid "tag name"
|
|
||||||
msgstr "Nazwa tagu"
|
|
||||||
|
|
||||||
#: blog/models.py:87
|
|
||||||
msgid "user-friendly name for the post tag"
|
|
||||||
msgstr "Przyjazna dla użytkownika nazwa tagu posta"
|
|
||||||
|
|
||||||
#: blog/models.py:88
|
|
||||||
msgid "tag display name"
|
|
||||||
msgstr "Wyświetlana nazwa znacznika"
|
|
||||||
|
|
||||||
#: blog/models.py:96
|
|
||||||
msgid "post tag"
|
|
||||||
msgstr "Tag posta"
|
|
||||||
|
|
||||||
#: blog/models.py:97
|
|
||||||
msgid "post tags"
|
|
||||||
msgstr "Tagi postów"
|
|
||||||
|
|
||||||
#~ msgid "eVibes Engine"
|
|
||||||
#~ msgstr "Silnik eVibes"
|
|
||||||
Binary file not shown.
|
|
@ -1,72 +0,0 @@
|
||||||
#
|
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
|
||||||
"Report-Msgid-Bugs-To: \n"
|
|
||||||
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
|
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language: pt-br\n"
|
|
||||||
"MIME-Version: 1.0\n"
|
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
|
||||||
|
|
||||||
#: blog/apps.py:8
|
|
||||||
msgid "blog"
|
|
||||||
msgstr "Blog"
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "post title"
|
|
||||||
msgstr "Título da postagem"
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "title"
|
|
||||||
msgstr "Título"
|
|
||||||
|
|
||||||
#: blog/models.py:64
|
|
||||||
msgid "post"
|
|
||||||
msgstr "Postar"
|
|
||||||
|
|
||||||
#: blog/models.py:65
|
|
||||||
msgid "posts"
|
|
||||||
msgstr "Publicações"
|
|
||||||
|
|
||||||
#: blog/models.py:69
|
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
|
||||||
msgstr ""
|
|
||||||
"Os arquivos markdown não são suportados - use conteúdo markdown em vez disso!"
|
|
||||||
|
|
||||||
#: blog/models.py:71
|
|
||||||
msgid ""
|
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
|
||||||
"um arquivo ou conteúdo de markdown deve ser fornecido - mutuamente exclusivo"
|
|
||||||
|
|
||||||
#: blog/models.py:82
|
|
||||||
msgid "internal tag identifier for the post tag"
|
|
||||||
msgstr "identificador de tag interno para a tag de postagem"
|
|
||||||
|
|
||||||
#: blog/models.py:83
|
|
||||||
msgid "tag name"
|
|
||||||
msgstr "Nome da etiqueta"
|
|
||||||
|
|
||||||
#: blog/models.py:87
|
|
||||||
msgid "user-friendly name for the post tag"
|
|
||||||
msgstr "Nome de fácil utilização para a tag de postagem"
|
|
||||||
|
|
||||||
#: blog/models.py:88
|
|
||||||
msgid "tag display name"
|
|
||||||
msgstr "Nome de exibição da tag"
|
|
||||||
|
|
||||||
#: blog/models.py:96
|
|
||||||
msgid "post tag"
|
|
||||||
msgstr "Etiqueta de postagem"
|
|
||||||
|
|
||||||
#: blog/models.py:97
|
|
||||||
msgid "post tags"
|
|
||||||
msgstr "Tags de postagem"
|
|
||||||
|
|
||||||
#~ msgid "eVibes Engine"
|
|
||||||
#~ msgstr "Motor eVibes"
|
|
||||||
Binary file not shown.
|
|
@ -1,73 +0,0 @@
|
||||||
#
|
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
|
||||||
"Report-Msgid-Bugs-To: \n"
|
|
||||||
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
|
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language: ro-ro\n"
|
|
||||||
"MIME-Version: 1.0\n"
|
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
|
||||||
|
|
||||||
#: blog/apps.py:8
|
|
||||||
msgid "blog"
|
|
||||||
msgstr "Blog"
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "post title"
|
|
||||||
msgstr "Titlul postului"
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "title"
|
|
||||||
msgstr "Titlul"
|
|
||||||
|
|
||||||
#: blog/models.py:64
|
|
||||||
msgid "post"
|
|
||||||
msgstr "Post"
|
|
||||||
|
|
||||||
#: blog/models.py:65
|
|
||||||
msgid "posts"
|
|
||||||
msgstr "Mesaje"
|
|
||||||
|
|
||||||
#: blog/models.py:69
|
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
|
||||||
msgstr ""
|
|
||||||
"Fișierele Markdown nu sunt acceptate - utilizați în schimb conținut Markdown!"
|
|
||||||
|
|
||||||
#: blog/models.py:71
|
|
||||||
msgid ""
|
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
|
||||||
"trebuie furnizat un fișier markdown sau conținut markdown - se exclud "
|
|
||||||
"reciproc"
|
|
||||||
|
|
||||||
#: blog/models.py:82
|
|
||||||
msgid "internal tag identifier for the post tag"
|
|
||||||
msgstr "identificator intern de etichetă pentru eticheta postului"
|
|
||||||
|
|
||||||
#: blog/models.py:83
|
|
||||||
msgid "tag name"
|
|
||||||
msgstr "Nume etichetă"
|
|
||||||
|
|
||||||
#: blog/models.py:87
|
|
||||||
msgid "user-friendly name for the post tag"
|
|
||||||
msgstr "Nume ușor de utilizat pentru eticheta postului"
|
|
||||||
|
|
||||||
#: blog/models.py:88
|
|
||||||
msgid "tag display name"
|
|
||||||
msgstr "Nume afișare etichetă"
|
|
||||||
|
|
||||||
#: blog/models.py:96
|
|
||||||
msgid "post tag"
|
|
||||||
msgstr "Etichetă post"
|
|
||||||
|
|
||||||
#: blog/models.py:97
|
|
||||||
msgid "post tags"
|
|
||||||
msgstr "Etichete poștale"
|
|
||||||
|
|
||||||
#~ msgid "eVibes Engine"
|
|
||||||
#~ msgstr "Motorul eVibes"
|
|
||||||
Binary file not shown.
|
|
@ -1,74 +0,0 @@
|
||||||
#
|
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
|
||||||
"Report-Msgid-Bugs-To: \n"
|
|
||||||
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
|
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language: ru-ru\n"
|
|
||||||
"MIME-Version: 1.0\n"
|
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
|
||||||
|
|
||||||
#: blog/apps.py:8
|
|
||||||
msgid "blog"
|
|
||||||
msgstr "Блог"
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "post title"
|
|
||||||
msgstr "Заголовок сообщения"
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "title"
|
|
||||||
msgstr "Название"
|
|
||||||
|
|
||||||
#: blog/models.py:64
|
|
||||||
msgid "post"
|
|
||||||
msgstr "Пост"
|
|
||||||
|
|
||||||
#: blog/models.py:65
|
|
||||||
msgid "posts"
|
|
||||||
msgstr "Посты"
|
|
||||||
|
|
||||||
#: blog/models.py:69
|
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
|
||||||
msgstr ""
|
|
||||||
"Файлы в формате Markdown не поддерживаются - используйте вместо них "
|
|
||||||
"содержимое в формате Markdown!"
|
|
||||||
|
|
||||||
#: blog/models.py:71
|
|
||||||
msgid ""
|
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr ""
|
|
||||||
"необходимо предоставить файл разметки или содержимое разметки - "
|
|
||||||
"взаимоисключающие варианты"
|
|
||||||
|
|
||||||
#: blog/models.py:82
|
|
||||||
msgid "internal tag identifier for the post tag"
|
|
||||||
msgstr "внутренний идентификатор тега для тега post"
|
|
||||||
|
|
||||||
#: blog/models.py:83
|
|
||||||
msgid "tag name"
|
|
||||||
msgstr "Название тега"
|
|
||||||
|
|
||||||
#: blog/models.py:87
|
|
||||||
msgid "user-friendly name for the post tag"
|
|
||||||
msgstr "Удобное для пользователя название тега поста"
|
|
||||||
|
|
||||||
#: blog/models.py:88
|
|
||||||
msgid "tag display name"
|
|
||||||
msgstr "Отображаемое имя тега"
|
|
||||||
|
|
||||||
#: blog/models.py:96
|
|
||||||
msgid "post tag"
|
|
||||||
msgstr "Тэг поста"
|
|
||||||
|
|
||||||
#: blog/models.py:97
|
|
||||||
msgid "post tags"
|
|
||||||
msgstr "Тэги постов"
|
|
||||||
|
|
||||||
#~ msgid "eVibes Engine"
|
|
||||||
#~ msgstr "Движок eVibes"
|
|
||||||
Binary file not shown.
|
|
@ -1,70 +0,0 @@
|
||||||
#
|
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
"Project-Id-Version: EVIBES 2.8.10\n"
|
|
||||||
"Report-Msgid-Bugs-To: \n"
|
|
||||||
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
|
|
||||||
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
|
|
||||||
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
|
|
||||||
"Language: zh-hans\n"
|
|
||||||
"MIME-Version: 1.0\n"
|
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
|
||||||
|
|
||||||
#: blog/apps.py:8
|
|
||||||
msgid "blog"
|
|
||||||
msgstr "博客"
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "post title"
|
|
||||||
msgstr "帖子标题"
|
|
||||||
|
|
||||||
#: blog/models.py:17
|
|
||||||
msgid "title"
|
|
||||||
msgstr "标题"
|
|
||||||
|
|
||||||
#: blog/models.py:64
|
|
||||||
msgid "post"
|
|
||||||
msgstr "职位"
|
|
||||||
|
|
||||||
#: blog/models.py:65
|
|
||||||
msgid "posts"
|
|
||||||
msgstr "职位"
|
|
||||||
|
|
||||||
#: blog/models.py:69
|
|
||||||
msgid "markdown files are not supported yet - use markdown content instead"
|
|
||||||
msgstr "不支持 Markdown 文件,请使用 Markdown 内容!"
|
|
||||||
|
|
||||||
#: blog/models.py:71
|
|
||||||
msgid ""
|
|
||||||
"a markdown file or markdown content must be provided - mutually exclusive"
|
|
||||||
msgstr "必须提供标记符文件或标记符内容 - 相互排斥"
|
|
||||||
|
|
||||||
#: blog/models.py:82
|
|
||||||
msgid "internal tag identifier for the post tag"
|
|
||||||
msgstr "职位标签的内部标签标识符"
|
|
||||||
|
|
||||||
#: blog/models.py:83
|
|
||||||
msgid "tag name"
|
|
||||||
msgstr "标签名称"
|
|
||||||
|
|
||||||
#: blog/models.py:87
|
|
||||||
msgid "user-friendly name for the post tag"
|
|
||||||
msgstr "方便用户使用的帖子标签名称"
|
|
||||||
|
|
||||||
#: blog/models.py:88
|
|
||||||
msgid "tag display name"
|
|
||||||
msgstr "标签显示名称"
|
|
||||||
|
|
||||||
#: blog/models.py:96
|
|
||||||
msgid "post tag"
|
|
||||||
msgstr "职位标签"
|
|
||||||
|
|
||||||
#: blog/models.py:97
|
|
||||||
msgid "post tags"
|
|
||||||
msgstr "帖子标签"
|
|
||||||
|
|
||||||
#~ msgid "eVibes Engine"
|
|
||||||
#~ msgstr "eVibes 引擎"
|
|
||||||
|
|
@ -1,73 +0,0 @@
|
||||||
# Generated by Django 5.1.8 on 2025-04-28 11:56
|
|
||||||
|
|
||||||
import uuid
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
import django_extensions.db.fields
|
|
||||||
import markdown_field.fields
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
initial = True
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='PostTag',
|
|
||||||
fields=[
|
|
||||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
|
|
||||||
help_text='unique id is used to surely identify any database object',
|
|
||||||
primary_key=True, serialize=False, verbose_name='unique id')),
|
|
||||||
('is_active', models.BooleanField(default=True,
|
|
||||||
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={
|
|
||||||
'verbose_name': 'post tag',
|
|
||||||
'verbose_name_plural': 'post tags',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Post',
|
|
||||||
fields=[
|
|
||||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
|
|
||||||
help_text='unique id is used to surely identify any database object',
|
|
||||||
primary_key=True, serialize=False, verbose_name='unique id')),
|
|
||||||
('is_active', models.BooleanField(default=True,
|
|
||||||
help_text="if set to false, this object can't be seen by users without needed permission",
|
|
||||||
verbose_name='is active')),
|
|
||||||
('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True,
|
|
||||||
help_text='when the object first appeared on the database',
|
|
||||||
verbose_name='created')),
|
|
||||||
('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True,
|
|
||||||
help_text='when the object was last modified',
|
|
||||||
verbose_name='modified')),
|
|
||||||
('title', models.CharField()),
|
|
||||||
('content', markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name='content')),
|
|
||||||
('file', models.FileField(blank=True, null=True, upload_to='posts/')),
|
|
||||||
('slug', models.SlugField(allow_unicode=True)),
|
|
||||||
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='posts',
|
|
||||||
to=settings.AUTH_USER_MODEL)),
|
|
||||||
('tags', models.ManyToManyField(to='blog.posttag')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'post',
|
|
||||||
'verbose_name_plural': 'posts',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
# Generated by Django 5.1.8 on 2025-04-28 12:07
|
|
||||||
|
|
||||||
import django_extensions.db.fields
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('blog', '0001_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='post',
|
|
||||||
name='slug',
|
|
||||||
field=django_extensions.db.fields.AutoSlugField(allow_unicode=True, blank=True, editable=False, populate_from='title', unique=True),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='post',
|
|
||||||
name='title',
|
|
||||||
field=models.CharField(help_text='post title', max_length=128, unique=True, verbose_name='title'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
13
blog/urls.py
13
blog/urls.py
|
|
@ -1,13 +0,0 @@
|
||||||
from django.urls import include, path
|
|
||||||
from rest_framework.routers import DefaultRouter
|
|
||||||
|
|
||||||
from blog.viewsets import PostViewSet
|
|
||||||
|
|
||||||
app_name = "blog"
|
|
||||||
|
|
||||||
payment_router = DefaultRouter()
|
|
||||||
payment_router.register(prefix=r"posts", viewset=PostViewSet, basename="posts")
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path(r"", include(payment_router.urls)),
|
|
||||||
]
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
import logging
|
|
||||||
|
|
||||||
logger = logging.getLogger("evibes")
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
from django_filters.rest_framework import DjangoFilterBackend
|
|
||||||
from rest_framework.viewsets import ReadOnlyModelViewSet
|
|
||||||
|
|
||||||
from blog.filters import PostFilter
|
|
||||||
from blog.models import Post
|
|
||||||
from blog.serializers import PostSerializer
|
|
||||||
from core.permissions import EvibesPermission
|
|
||||||
|
|
||||||
|
|
||||||
class PostViewSet(ReadOnlyModelViewSet):
|
|
||||||
"""
|
|
||||||
Encapsulates operations for managing and retrieving Post entities in a read-only model view set.
|
|
||||||
|
|
||||||
This class is tailored to handle Post objects that are active and allows filtration based on defined
|
|
||||||
filters. It integrates with Django's backend filtering system and ensures operations align with the
|
|
||||||
defined permissions. The view set also includes an additional "retrieve" permission configuration.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
serializer_class: Specifies the serializer to be used for Post objects.
|
|
||||||
permission_classes: Defines the permissions required to interact with this view set.
|
|
||||||
queryset: Determines the initial queryset, filtered to include only active Post objects.
|
|
||||||
filter_backends: Lists the backends to be used for filtering querysets.
|
|
||||||
filterset_class: Defines the set of filters used for filtering Post objects.
|
|
||||||
additional: Contains additional configuration, such as specific action permissions.
|
|
||||||
"""
|
|
||||||
|
|
||||||
serializer_class = PostSerializer
|
|
||||||
permission_classes = (EvibesPermission,)
|
|
||||||
queryset = Post.objects.filter(is_active=True)
|
|
||||||
filter_backends = [DjangoFilterBackend]
|
|
||||||
filterset_class = PostFilter
|
|
||||||
additional = {"retrieve": "ALLOW"}
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
import uuid
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
from django.db.models import BooleanField, Model, UUIDField
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
from django_extensions.db.fields import CreationDateTimeField, ModificationDateTimeField
|
|
||||||
|
|
||||||
|
|
||||||
class NiceModel(Model):
|
|
||||||
id = None
|
|
||||||
uuid: uuid = UUIDField( # type: ignore
|
|
||||||
verbose_name=_("unique id"),
|
|
||||||
help_text=_("unique id is used to surely identify any database object"),
|
|
||||||
primary_key=True,
|
|
||||||
default=uuid.uuid4,
|
|
||||||
editable=False,
|
|
||||||
)
|
|
||||||
is_active: bool = BooleanField( # type: ignore
|
|
||||||
default=True,
|
|
||||||
verbose_name=_("is active"),
|
|
||||||
help_text=_("if set to false, this object can't be seen by users without needed permission"),
|
|
||||||
)
|
|
||||||
created: datetime = CreationDateTimeField( # type: ignore
|
|
||||||
_("created"), help_text=_("when the object first appeared on the database")
|
|
||||||
)
|
|
||||||
modified: datetime = ModificationDateTimeField( # type: ignore
|
|
||||||
_("modified"), help_text=_("when the object was last modified")
|
|
||||||
)
|
|
||||||
|
|
||||||
def save(self, **kwargs):
|
|
||||||
self.update_modified = kwargs.pop("update_modified", getattr(self, "update_modified", True))
|
|
||||||
super().save(**kwargs)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
abstract = True
|
|
||||||
get_latest_by = "modified"
|
|
||||||
527
core/admin.py
527
core/admin.py
|
|
@ -1,527 +0,0 @@
|
||||||
from contextlib import suppress
|
|
||||||
|
|
||||||
from constance.admin import Config
|
|
||||||
from constance.admin import ConstanceAdmin as BaseConstanceAdmin
|
|
||||||
from dalf.admin import DALFRelatedFieldAjax, DALFRelatedOnlyField
|
|
||||||
from django import forms
|
|
||||||
from django.apps import apps
|
|
||||||
from django.contrib import admin
|
|
||||||
from django.contrib.admin import ModelAdmin, TabularInline
|
|
||||||
from django.contrib.admin.widgets import get_select2_language
|
|
||||||
from django.contrib.gis.admin import GISModelAdmin
|
|
||||||
from django.db.models import Model
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
from modeltranslation.translator import NotRegistered, translator
|
|
||||||
from modeltranslation.utils import get_translation_fields
|
|
||||||
from mptt.admin import DraggableMPTTAdmin
|
|
||||||
|
|
||||||
from evibes.settings import CONSTANCE_CONFIG
|
|
||||||
|
|
||||||
from .forms import OrderForm, OrderProductForm, VendorForm
|
|
||||||
from .models import (
|
|
||||||
Address,
|
|
||||||
Attribute,
|
|
||||||
AttributeGroup,
|
|
||||||
AttributeValue,
|
|
||||||
Brand,
|
|
||||||
Category,
|
|
||||||
CategoryTag,
|
|
||||||
Feedback,
|
|
||||||
Order,
|
|
||||||
OrderProduct,
|
|
||||||
Product,
|
|
||||||
ProductImage,
|
|
||||||
ProductTag,
|
|
||||||
PromoCode,
|
|
||||||
Promotion,
|
|
||||||
Stock,
|
|
||||||
Vendor,
|
|
||||||
Wishlist,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class FieldsetsMixin:
|
|
||||||
general_fields: list = []
|
|
||||||
relation_fields: list = []
|
|
||||||
model: Model
|
|
||||||
|
|
||||||
def get_fieldsets(self, request, obj=None):
|
|
||||||
fieldsets = []
|
|
||||||
|
|
||||||
def add_translations_fieldset(fss):
|
|
||||||
with suppress(NotRegistered):
|
|
||||||
transoptions = translator.get_options_for_model(self.model)
|
|
||||||
translation_fields = []
|
|
||||||
for orig in transoptions.local_fields:
|
|
||||||
translation_fields += get_translation_fields(orig)
|
|
||||||
if translation_fields:
|
|
||||||
fss = list(fss) + [(_("translations"), {"fields": translation_fields})]
|
|
||||||
return fss
|
|
||||||
|
|
||||||
if self.general_fields:
|
|
||||||
fieldsets.append((_("general"), {"fields": self.general_fields}))
|
|
||||||
if self.relation_fields:
|
|
||||||
fieldsets.append((_("relations"), {"fields": self.relation_fields}))
|
|
||||||
opts = self.model._meta
|
|
||||||
|
|
||||||
if any(f.name == "uuid" for f in opts.fields):
|
|
||||||
if any(f.name == "slug" for f in opts.fields):
|
|
||||||
fieldsets.append((_("metadata"), {"fields": ["uuid", "slug"]}))
|
|
||||||
else:
|
|
||||||
fieldsets.append((_("metadata"), {"fields": ["uuid"]}))
|
|
||||||
|
|
||||||
ts = []
|
|
||||||
for name in ("created", "modified"):
|
|
||||||
if any(f.name == name for f in opts.fields):
|
|
||||||
ts.append(name)
|
|
||||||
if ts:
|
|
||||||
fieldsets.append((_("timestamps"), {"fields": ts, "classes": ["collapse"]}))
|
|
||||||
fieldsets = add_translations_fieldset(fieldsets)
|
|
||||||
return fieldsets
|
|
||||||
|
|
||||||
|
|
||||||
class BasicModelAdmin(ModelAdmin):
|
|
||||||
@admin.action(description=str(_("activate selected %(verbose_name_plural)s")))
|
|
||||||
def activate_selected(self, request, queryset) -> str:
|
|
||||||
if request:
|
|
||||||
pass
|
|
||||||
queryset.update(is_active=True)
|
|
||||||
return str(_("%(verbose_name_plural)s activated successfully!"))
|
|
||||||
|
|
||||||
@admin.action(description=str(_("deactivate selected %(verbose_name_plural)s")))
|
|
||||||
def deactivate_selected(self, request, queryset) -> str:
|
|
||||||
if request:
|
|
||||||
pass
|
|
||||||
queryset.update(is_active=False)
|
|
||||||
return str(_("%(verbose_name_plural)s deactivated successfully."))
|
|
||||||
|
|
||||||
def get_actions(self, request):
|
|
||||||
actions = super().get_actions(request)
|
|
||||||
actions["activate_selected"] = (
|
|
||||||
self.activate_selected,
|
|
||||||
"activate_selected",
|
|
||||||
str(_("activate selected %(verbose_name_plural)s")),
|
|
||||||
)
|
|
||||||
actions["deactivate_selected"] = (
|
|
||||||
self.deactivate_selected,
|
|
||||||
"deactivate_selected",
|
|
||||||
str(_("deactivate selected %(verbose_name_plural)s")),
|
|
||||||
)
|
|
||||||
return actions
|
|
||||||
|
|
||||||
|
|
||||||
class AttributeValueInline(TabularInline):
|
|
||||||
model = AttributeValue
|
|
||||||
extra = 0
|
|
||||||
autocomplete_fields = ["attribute"]
|
|
||||||
is_navtab = True
|
|
||||||
verbose_name = _("attribute value")
|
|
||||||
verbose_name_plural = _("attribute values")
|
|
||||||
icon = "fa-solid fa-list-ul"
|
|
||||||
|
|
||||||
|
|
||||||
class ProductImageInline(TabularInline):
|
|
||||||
model = ProductImage
|
|
||||||
extra = 0
|
|
||||||
is_navtab = True
|
|
||||||
verbose_name = _("image")
|
|
||||||
verbose_name_plural = _("images")
|
|
||||||
icon = "fa-regular fa-images"
|
|
||||||
|
|
||||||
|
|
||||||
class StockInline(TabularInline):
|
|
||||||
model = Stock
|
|
||||||
extra = 0
|
|
||||||
is_navtab = True
|
|
||||||
verbose_name = _("stock")
|
|
||||||
verbose_name_plural = _("stocks")
|
|
||||||
icon = "fa-solid fa-boxes-stacked"
|
|
||||||
|
|
||||||
|
|
||||||
class OrderProductInline(TabularInline):
|
|
||||||
model = OrderProduct
|
|
||||||
extra = 0
|
|
||||||
readonly_fields = ("product", "quantity", "buy_price")
|
|
||||||
form = OrderProductForm
|
|
||||||
is_navtab = True
|
|
||||||
verbose_name = _("order product")
|
|
||||||
verbose_name_plural = _("order products")
|
|
||||||
icon = "fa-solid fa-boxes-packing"
|
|
||||||
|
|
||||||
def get_queryset(self, request):
|
|
||||||
return super().get_queryset(request).select_related("product").only("product__name")
|
|
||||||
|
|
||||||
|
|
||||||
class CategoryChildrenInline(TabularInline):
|
|
||||||
model = Category
|
|
||||||
fk_name = "parent"
|
|
||||||
extra = 0
|
|
||||||
fields = ("name", "description", "is_active", "image", "markup_percent")
|
|
||||||
is_navtab = True
|
|
||||||
verbose_name = _("children")
|
|
||||||
verbose_name_plural = _("children")
|
|
||||||
icon = "fa-solid fa-leaf"
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(AttributeGroup)
|
|
||||||
class AttributeGroupAdmin(FieldsetsMixin, BasicModelAdmin):
|
|
||||||
model = AttributeGroup # type: ignore
|
|
||||||
list_display = ("name", "modified")
|
|
||||||
search_fields = ("uuid", "name")
|
|
||||||
readonly_fields = ("uuid", "modified", "created")
|
|
||||||
|
|
||||||
general_fields = ["is_active", "name", "parent"]
|
|
||||||
relation_fields = []
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Attribute)
|
|
||||||
class AttributeAdmin(FieldsetsMixin, BasicModelAdmin):
|
|
||||||
model = Attribute # type: ignore
|
|
||||||
list_display = ("name", "group", "value_type", "modified")
|
|
||||||
list_filter = ("value_type", "group", "is_active")
|
|
||||||
search_fields = ("uuid", "name", "group__name")
|
|
||||||
readonly_fields = ("uuid", "modified", "created")
|
|
||||||
autocomplete_fields = ["categories", "group"]
|
|
||||||
|
|
||||||
general_fields = ["is_active", "name", "value_type"]
|
|
||||||
relation_fields = ["group", "categories"]
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(AttributeValue)
|
|
||||||
class AttributeValueAdmin(FieldsetsMixin, BasicModelAdmin):
|
|
||||||
model = AttributeValue # type: ignore
|
|
||||||
list_display = ("attribute", "value", "modified")
|
|
||||||
list_filter = ("attribute__group", "is_active")
|
|
||||||
search_fields = ("uuid", "value", "attribute__name")
|
|
||||||
readonly_fields = ("uuid", "modified", "created")
|
|
||||||
autocomplete_fields = ["attribute"]
|
|
||||||
|
|
||||||
general_fields = ["is_active", "value"]
|
|
||||||
relation_fields = ["attribute", "product"]
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Category)
|
|
||||||
class CategoryAdmin(FieldsetsMixin, DraggableMPTTAdmin, BasicModelAdmin):
|
|
||||||
model = Category # type: ignore
|
|
||||||
list_display = ("indented_title", "parent", "is_active", "modified")
|
|
||||||
list_filter = ("is_active", "level", "created", "modified")
|
|
||||||
search_fields = ("uuid", "name")
|
|
||||||
inlines = [CategoryChildrenInline]
|
|
||||||
autocomplete_fields = ["parent", "tags"]
|
|
||||||
readonly_fields = ("slug", "uuid", "modified", "created")
|
|
||||||
|
|
||||||
general_fields = ["is_active", "name", "description", "image", "markup_percent", "priority"]
|
|
||||||
relation_fields = ["parent", "tags"]
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Brand)
|
|
||||||
class BrandAdmin(FieldsetsMixin, BasicModelAdmin):
|
|
||||||
model = Brand # type: ignore
|
|
||||||
list_display = ("name",)
|
|
||||||
list_filter = ("categories", "is_active")
|
|
||||||
search_fields = ("uuid", "name", "categories__name")
|
|
||||||
readonly_fields = ("uuid", "slug", "modified", "created")
|
|
||||||
|
|
||||||
general_fields = ["is_active", "name", "description", "priority"]
|
|
||||||
relation_fields = ["small_logo", "big_logo", "categories"]
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Product)
|
|
||||||
class ProductAdmin(FieldsetsMixin, BasicModelAdmin):
|
|
||||||
model = Product # type: ignore
|
|
||||||
list_display = (
|
|
||||||
"name",
|
|
||||||
"partnumber",
|
|
||||||
"is_active",
|
|
||||||
"category",
|
|
||||||
"brand",
|
|
||||||
"price",
|
|
||||||
"rating",
|
|
||||||
"modified",
|
|
||||||
)
|
|
||||||
list_filter = (
|
|
||||||
"is_active",
|
|
||||||
"is_digital",
|
|
||||||
("brand", DALFRelatedFieldAjax),
|
|
||||||
("category", DALFRelatedFieldAjax),
|
|
||||||
("tags", DALFRelatedFieldAjax),
|
|
||||||
("stocks__vendor", DALFRelatedOnlyField),
|
|
||||||
"created",
|
|
||||||
"modified",
|
|
||||||
)
|
|
||||||
search_fields = (
|
|
||||||
"name",
|
|
||||||
"partnumber",
|
|
||||||
"brand__name",
|
|
||||||
"category__name",
|
|
||||||
"uuid",
|
|
||||||
"slug",
|
|
||||||
)
|
|
||||||
readonly_fields = ("slug", "uuid", "modified", "created")
|
|
||||||
autocomplete_fields = ("category", "brand", "tags")
|
|
||||||
inlines = [AttributeValueInline, ProductImageInline, StockInline]
|
|
||||||
|
|
||||||
general_fields = ["is_active", "name", "partnumber", "is_digital"]
|
|
||||||
relation_fields = ["category", "brand", "tags"]
|
|
||||||
|
|
||||||
@property
|
|
||||||
def media(self):
|
|
||||||
i18n_name = get_select2_language()
|
|
||||||
i18n_file = (f"admin/js/vendor/select2/i18n/{i18n_name}.js",) if i18n_name else ()
|
|
||||||
return super().media + forms.Media(
|
|
||||||
js=(
|
|
||||||
"admin/js/vendor/jquery/jquery.min.js",
|
|
||||||
"admin/js/vendor/select2/select2.full.min.js",
|
|
||||||
*i18n_file,
|
|
||||||
"admin/js/jquery.init.js",
|
|
||||||
"admin/js/django_admin_list_filter.js",
|
|
||||||
),
|
|
||||||
css={
|
|
||||||
"screen": (
|
|
||||||
"admin/css/vendor/select2/select2.min.css",
|
|
||||||
"admin/css/autocomplete.css",
|
|
||||||
"admin/css/django_admin_list_filter.css",
|
|
||||||
),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(ProductTag)
|
|
||||||
class ProductTagAdmin(FieldsetsMixin, BasicModelAdmin):
|
|
||||||
model = ProductTag # type: ignore
|
|
||||||
list_display = ("tag_name",)
|
|
||||||
search_fields = ("tag_name",)
|
|
||||||
readonly_fields = ("uuid", "modified", "created")
|
|
||||||
|
|
||||||
general_fields = ["is_active", "tag_name", "name"]
|
|
||||||
relation_fields = []
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(CategoryTag)
|
|
||||||
class CategoryTagAdmin(FieldsetsMixin, BasicModelAdmin):
|
|
||||||
model = CategoryTag # type: ignore
|
|
||||||
list_display = ("tag_name",)
|
|
||||||
search_fields = ("tag_name",)
|
|
||||||
readonly_fields = ("uuid", "modified", "created")
|
|
||||||
|
|
||||||
general_fields = ["is_active", "tag_name", "name"]
|
|
||||||
relation_fields = []
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Vendor)
|
|
||||||
class VendorAdmin(FieldsetsMixin, BasicModelAdmin):
|
|
||||||
model = Vendor # type: ignore
|
|
||||||
list_display = ("name", "markup_percent", "modified")
|
|
||||||
list_filter = ("markup_percent", "is_active")
|
|
||||||
search_fields = ("name",)
|
|
||||||
readonly_fields = ("uuid", "modified", "created")
|
|
||||||
form = VendorForm
|
|
||||||
|
|
||||||
general_fields = ["is_active", "name", "markup_percent", "authentication"]
|
|
||||||
relation_fields = []
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Feedback)
|
|
||||||
class FeedbackAdmin(FieldsetsMixin, BasicModelAdmin):
|
|
||||||
model = Feedback # type: ignore
|
|
||||||
list_display = ("order_product", "rating", "comment", "modified")
|
|
||||||
list_filter = ("rating", "is_active")
|
|
||||||
search_fields = ("order_product__product__name", "comment")
|
|
||||||
readonly_fields = ("uuid", "modified", "created")
|
|
||||||
|
|
||||||
general_fields = ["is_active", "rating", "comment"]
|
|
||||||
relation_fields = ["order_product"]
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Order)
|
|
||||||
class OrderAdmin(FieldsetsMixin, BasicModelAdmin):
|
|
||||||
model = Order # type: ignore
|
|
||||||
list_display = (
|
|
||||||
"human_readable_id",
|
|
||||||
"user",
|
|
||||||
"status",
|
|
||||||
"total_price",
|
|
||||||
"buy_time",
|
|
||||||
"modified",
|
|
||||||
)
|
|
||||||
list_filter = ("status", "buy_time", "modified", "created")
|
|
||||||
search_fields = ("user__email", "status", "uuid", "human_readable_id")
|
|
||||||
readonly_fields = (
|
|
||||||
"total_price",
|
|
||||||
"total_quantity",
|
|
||||||
"human_readable_id",
|
|
||||||
"uuid",
|
|
||||||
"modified",
|
|
||||||
"created",
|
|
||||||
)
|
|
||||||
inlines = [OrderProductInline]
|
|
||||||
form = OrderForm
|
|
||||||
|
|
||||||
general_fields = ["is_active", "user", "status"]
|
|
||||||
relation_fields = ["promo_code", "billing_address", "shipping_address"]
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(OrderProduct)
|
|
||||||
class OrderProductAdmin(FieldsetsMixin, BasicModelAdmin):
|
|
||||||
model = OrderProduct # type: ignore
|
|
||||||
list_display = ("order", "product", "quantity", "buy_price", "status", "modified")
|
|
||||||
list_filter = ("status",)
|
|
||||||
search_fields = ("order__user__email", "product__name")
|
|
||||||
readonly_fields = ("uuid", "modified", "created")
|
|
||||||
form = OrderProductForm
|
|
||||||
|
|
||||||
general_fields = ["is_active", "quantity", "buy_price", "status"]
|
|
||||||
relation_fields = ["order", "product"]
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(PromoCode)
|
|
||||||
class PromoCodeAdmin(FieldsetsMixin, BasicModelAdmin):
|
|
||||||
model = PromoCode # type: ignore
|
|
||||||
list_display = (
|
|
||||||
"code",
|
|
||||||
"discount_percent",
|
|
||||||
"discount_amount",
|
|
||||||
"start_time",
|
|
||||||
"end_time",
|
|
||||||
"used_on",
|
|
||||||
)
|
|
||||||
list_filter = ("discount_percent", "discount_amount", "start_time", "end_time")
|
|
||||||
search_fields = ("code",)
|
|
||||||
readonly_fields = ("used_on", "uuid", "modified", "created")
|
|
||||||
autocomplete_fields = ("user",)
|
|
||||||
|
|
||||||
general_fields = [
|
|
||||||
"is_active",
|
|
||||||
"code",
|
|
||||||
"discount_amount",
|
|
||||||
"discount_percent",
|
|
||||||
"start_time",
|
|
||||||
"end_time",
|
|
||||||
"used_on",
|
|
||||||
]
|
|
||||||
relation_fields = ["user"]
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Promotion)
|
|
||||||
class PromotionAdmin(FieldsetsMixin, BasicModelAdmin):
|
|
||||||
model = Promotion # type: ignore
|
|
||||||
list_display = ("name", "discount_percent", "modified")
|
|
||||||
search_fields = ("name",)
|
|
||||||
readonly_fields = ("uuid", "modified", "created")
|
|
||||||
autocomplete_fields = ("products",)
|
|
||||||
|
|
||||||
general_fields = ["is_active", "name", "discount_percent", "description"]
|
|
||||||
relation_fields = ["products"]
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Stock)
|
|
||||||
class StockAdmin(FieldsetsMixin, BasicModelAdmin):
|
|
||||||
model = Stock # type: ignore
|
|
||||||
list_display = ("product", "vendor", "sku", "quantity", "price", "modified")
|
|
||||||
list_filter = ("vendor", "quantity")
|
|
||||||
search_fields = ("product__name", "vendor__name", "sku")
|
|
||||||
readonly_fields = ("uuid", "modified", "created")
|
|
||||||
autocomplete_fields = ("product", "vendor")
|
|
||||||
|
|
||||||
general_fields = [
|
|
||||||
"is_active",
|
|
||||||
"sku",
|
|
||||||
"quantity",
|
|
||||||
"price",
|
|
||||||
"purchase_price",
|
|
||||||
"digital_asset",
|
|
||||||
]
|
|
||||||
relation_fields = ["product", "vendor"]
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Wishlist)
|
|
||||||
class WishlistAdmin(FieldsetsMixin, BasicModelAdmin):
|
|
||||||
model = Wishlist # type: ignore
|
|
||||||
list_display = ("user", "modified")
|
|
||||||
search_fields = ("user__email",)
|
|
||||||
readonly_fields = ("uuid", "modified", "created")
|
|
||||||
|
|
||||||
general_fields = ["is_active", "user"]
|
|
||||||
relation_fields = ["products"]
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(ProductImage)
|
|
||||||
class ProductImageAdmin(FieldsetsMixin, BasicModelAdmin):
|
|
||||||
model = ProductImage # type: ignore
|
|
||||||
list_display = ("alt", "product", "priority", "modified")
|
|
||||||
list_filter = ("priority",)
|
|
||||||
search_fields = ("alt", "product__name")
|
|
||||||
readonly_fields = ("uuid", "modified", "created")
|
|
||||||
autocomplete_fields = ("product",)
|
|
||||||
|
|
||||||
general_fields = ["is_active", "alt", "priority", "image"]
|
|
||||||
relation_fields = ["product"]
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Address)
|
|
||||||
class AddressAdmin(FieldsetsMixin, GISModelAdmin):
|
|
||||||
model = Address # type: ignore
|
|
||||||
list_display = ("street", "city", "region", "country", "user")
|
|
||||||
list_filter = ("country", "region")
|
|
||||||
search_fields = ("street", "city", "postal_code", "user__email")
|
|
||||||
readonly_fields = ("uuid", "modified", "created")
|
|
||||||
gis_widget_kwargs = {
|
|
||||||
"attrs": {
|
|
||||||
"default_lon": 37.61556,
|
|
||||||
"default_lat": 55.75222,
|
|
||||||
"default_zoom": 6,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
general_fields = [
|
|
||||||
"is_active",
|
|
||||||
"address_line",
|
|
||||||
"street",
|
|
||||||
"district",
|
|
||||||
"city",
|
|
||||||
"region",
|
|
||||||
"postal_code",
|
|
||||||
"country",
|
|
||||||
"raw_data",
|
|
||||||
]
|
|
||||||
relation_fields = ["user", "api_response"]
|
|
||||||
|
|
||||||
|
|
||||||
# Constance configuration
|
|
||||||
class ConstanceConfig:
|
|
||||||
class Meta:
|
|
||||||
app_label = "core"
|
|
||||||
object_name = "Config"
|
|
||||||
concrete_model = None
|
|
||||||
model_name = module_name = "config"
|
|
||||||
verbose_name_plural = _("Config")
|
|
||||||
abstract = False
|
|
||||||
swapped = False
|
|
||||||
is_composite_pk = False
|
|
||||||
|
|
||||||
def get_change_permission(self):
|
|
||||||
return f"change_{self.model_name}"
|
|
||||||
|
|
||||||
@property
|
|
||||||
def app_config(self):
|
|
||||||
return apps.get_app_config(self.app_label)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def label(self):
|
|
||||||
return f"{self.app_label}.{self.object_name}"
|
|
||||||
|
|
||||||
@property
|
|
||||||
def label_lower(self):
|
|
||||||
return f"{self.app_label}.{self.model_name}"
|
|
||||||
|
|
||||||
def get_ordered_objects(self):
|
|
||||||
return False
|
|
||||||
|
|
||||||
_meta = Meta()
|
|
||||||
|
|
||||||
|
|
||||||
admin.site.unregister([Config]) # type: ignore
|
|
||||||
admin.site.register([ConstanceConfig], BaseConstanceAdmin) # type: ignore
|
|
||||||
admin.site.site_title = CONSTANCE_CONFIG["PROJECT_NAME"][0] # type: ignore
|
|
||||||
admin.site.site_header = "eVibes"
|
|
||||||
admin.site.index_title = CONSTANCE_CONFIG["PROJECT_NAME"][0] # type: ignore
|
|
||||||
|
|
@ -1,87 +0,0 @@
|
||||||
from django.urls import include, path
|
|
||||||
from rest_framework.routers import DefaultRouter
|
|
||||||
|
|
||||||
from core.sitemaps import BrandSitemap, CategorySitemap, ProductSitemap
|
|
||||||
from core.views import (
|
|
||||||
CacheOperatorView,
|
|
||||||
ContactUsView,
|
|
||||||
GlobalSearchView,
|
|
||||||
RequestCursedURLView,
|
|
||||||
SupportedLanguagesView,
|
|
||||||
WebsiteParametersView,
|
|
||||||
download_digital_asset_view,
|
|
||||||
sitemap_detail,
|
|
||||||
sitemap_index,
|
|
||||||
)
|
|
||||||
from core.viewsets import (
|
|
||||||
AddressViewSet,
|
|
||||||
AttributeGroupViewSet,
|
|
||||||
BrandViewSet,
|
|
||||||
CategoryViewSet,
|
|
||||||
FeedbackViewSet,
|
|
||||||
OrderProductViewSet,
|
|
||||||
OrderViewSet,
|
|
||||||
ProductTagViewSet,
|
|
||||||
ProductViewSet,
|
|
||||||
PromoCodeViewSet,
|
|
||||||
PromotionViewSet,
|
|
||||||
StockViewSet,
|
|
||||||
VendorViewSet,
|
|
||||||
WishlistViewSet,
|
|
||||||
)
|
|
||||||
|
|
||||||
app_name = "core"
|
|
||||||
|
|
||||||
core_router = DefaultRouter()
|
|
||||||
core_router.register(r"products", ProductViewSet, basename="products")
|
|
||||||
core_router.register(r"orders", OrderViewSet, basename="orders")
|
|
||||||
core_router.register(r"wishlists", WishlistViewSet, basename="wishlists")
|
|
||||||
core_router.register(r"attribute_groups", AttributeGroupViewSet, basename="attribute_groups")
|
|
||||||
core_router.register(r"brands", BrandViewSet, basename="brands")
|
|
||||||
core_router.register(r"categories", CategoryViewSet, basename="categories")
|
|
||||||
core_router.register(r"vendors", VendorViewSet, basename="vendors")
|
|
||||||
core_router.register(r"feedbacks", FeedbackViewSet, basename="feedbacks")
|
|
||||||
core_router.register(r"stocks", StockViewSet, basename="stocks")
|
|
||||||
core_router.register(r"promo_codes", PromoCodeViewSet, basename="promo_codes")
|
|
||||||
core_router.register(r"promotions", PromotionViewSet, basename="promotions")
|
|
||||||
core_router.register(r"addresses", AddressViewSet, basename="addresses")
|
|
||||||
core_router.register(r"product_tags", ProductTagViewSet, basename="product_tags")
|
|
||||||
core_router.register(r"order_products", OrderProductViewSet, basename="order_products")
|
|
||||||
|
|
||||||
sitemaps = {
|
|
||||||
"products": ProductSitemap,
|
|
||||||
"categories": CategorySitemap,
|
|
||||||
"brands": BrandSitemap,
|
|
||||||
}
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path("core/", include(core_router.urls)),
|
|
||||||
path(
|
|
||||||
"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("download/<str:order_product_uuid>/", download_digital_asset_view, name="download_digital_asset"),
|
|
||||||
path("search/", GlobalSearchView.as_view(), name="global_search"),
|
|
||||||
path("app/cache/", CacheOperatorView.as_view(), name="cache_operator"),
|
|
||||||
path("app/languages/", SupportedLanguagesView.as_view(), name="supported_languages"),
|
|
||||||
path("app/parameters/", WebsiteParametersView.as_view(), name="parameters"),
|
|
||||||
path("app/contact_us/", ContactUsView.as_view(), name="contact_us"),
|
|
||||||
path("app/request_cursed_url/", RequestCursedURLView.as_view(), name="request_cursed_url"),
|
|
||||||
]
|
|
||||||
|
|
@ -1,312 +0,0 @@
|
||||||
from django.conf import settings
|
|
||||||
from django.http import Http404
|
|
||||||
from django.shortcuts import get_object_or_404
|
|
||||||
from django.utils.text import slugify
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
from django_elasticsearch_dsl import fields
|
|
||||||
from django_elasticsearch_dsl.registries import registry
|
|
||||||
from elasticsearch import NotFoundError
|
|
||||||
from elasticsearch.dsl import Q, Search
|
|
||||||
from rest_framework.request import Request
|
|
||||||
|
|
||||||
from core.models import Brand, Category, Product
|
|
||||||
|
|
||||||
SMART_FIELDS = [
|
|
||||||
"name^6",
|
|
||||||
"name.ngram^5",
|
|
||||||
"name.phonetic",
|
|
||||||
"title^4",
|
|
||||||
"title.ngram^3",
|
|
||||||
"title.phonetic",
|
|
||||||
"description^2",
|
|
||||||
"description.ngram",
|
|
||||||
"description.phonetic",
|
|
||||||
"brand__name^3",
|
|
||||||
"brand__name.ngram",
|
|
||||||
"brand__name.auto",
|
|
||||||
"category__name^2",
|
|
||||||
"category__name.ngram",
|
|
||||||
"category__name.auto",
|
|
||||||
]
|
|
||||||
|
|
||||||
functions = [
|
|
||||||
# product-level boosts when searching for products
|
|
||||||
{
|
|
||||||
"filter": Q("term", **{"_index": "products"}),
|
|
||||||
"field_value_factor": {
|
|
||||||
"field": "brand_priority",
|
|
||||||
"modifier": "log1p",
|
|
||||||
"factor": 1.5,
|
|
||||||
"missing": 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filter": Q("term", **{"_index": "products"}),
|
|
||||||
"field_value_factor": {
|
|
||||||
"field": "rating",
|
|
||||||
"modifier": "log1p",
|
|
||||||
"factor": 2.0,
|
|
||||||
"missing": 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filter": Q("term", **{"_index": "products"}),
|
|
||||||
"field_value_factor": {
|
|
||||||
"field": "total_orders",
|
|
||||||
"modifier": "log1p",
|
|
||||||
"factor": 3.0,
|
|
||||||
"missing": 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filter": Q("term", **{"_index": "products"}),
|
|
||||||
"field_value_factor": {
|
|
||||||
"field": "category_priority",
|
|
||||||
"modifier": "log1p",
|
|
||||||
"factor": 1.2,
|
|
||||||
"missing": 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
# category-level boost when searching for categories
|
|
||||||
{
|
|
||||||
"filter": Q("term", **{"_index": "categories"}),
|
|
||||||
"field_value_factor": {
|
|
||||||
"field": "priority",
|
|
||||||
"modifier": "log1p",
|
|
||||||
"factor": 2.0,
|
|
||||||
"missing": 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
# brand-level boost when searching for brands
|
|
||||||
{
|
|
||||||
"filter": Q("term", **{"_index": "brands"}),
|
|
||||||
"field_value_factor": {
|
|
||||||
"field": "priority",
|
|
||||||
"modifier": "log1p",
|
|
||||||
"factor": 2.0,
|
|
||||||
"missing": 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def process_query(query: str = "", request: Request | None = None) -> dict[str, list[dict]] | None:
|
|
||||||
"""
|
|
||||||
Perform a lenient, typo‑tolerant, multi‑index search.
|
|
||||||
|
|
||||||
* Full‑text with fuzziness for spelling mistakes
|
|
||||||
* `bool_prefix` for edge‑ngram autocomplete / “icontains”
|
|
||||||
"""
|
|
||||||
if not query:
|
|
||||||
raise ValueError(_("no search term provided."))
|
|
||||||
|
|
||||||
query = query.strip()
|
|
||||||
try:
|
|
||||||
query_base = Q(
|
|
||||||
"bool",
|
|
||||||
should=[
|
|
||||||
Q(
|
|
||||||
"multi_match",
|
|
||||||
query=query,
|
|
||||||
fields=SMART_FIELDS,
|
|
||||||
fuzziness="AUTO",
|
|
||||||
operator="and",
|
|
||||||
),
|
|
||||||
Q(
|
|
||||||
"multi_match",
|
|
||||||
query=query,
|
|
||||||
fields=[f for f in SMART_FIELDS if f.endswith(".auto")],
|
|
||||||
type="bool_prefix",
|
|
||||||
),
|
|
||||||
],
|
|
||||||
minimum_should_match=1,
|
|
||||||
)
|
|
||||||
|
|
||||||
function_score_query = Q(
|
|
||||||
"function_score",
|
|
||||||
query=query_base,
|
|
||||||
functions=functions,
|
|
||||||
boost_mode="multiply",
|
|
||||||
score_mode="first",
|
|
||||||
)
|
|
||||||
|
|
||||||
search = Search(index=["products", "categories", "brands", "posts"]).query(function_score_query).extra(size=100)
|
|
||||||
response = search.execute()
|
|
||||||
|
|
||||||
results: dict = {"products": [], "categories": [], "brands": [], "posts": []}
|
|
||||||
for hit in response.hits:
|
|
||||||
obj_uuid = getattr(hit, "uuid", None) or hit.meta.id
|
|
||||||
obj_name = getattr(hit, "name", None) or getattr(hit, "title", None) or "N/A"
|
|
||||||
obj_slug = ""
|
|
||||||
raw_slug = getattr(hit, "slug", None)
|
|
||||||
if raw_slug:
|
|
||||||
obj_slug = raw_slug
|
|
||||||
elif hit.meta.index == "brands":
|
|
||||||
obj_slug = slugify(obj_name)
|
|
||||||
elif hit.meta.index == "categories":
|
|
||||||
obj_slug = slugify(f"{obj_name}")
|
|
||||||
|
|
||||||
image_url = None
|
|
||||||
idx = hit.meta.index
|
|
||||||
if idx == "products" and request:
|
|
||||||
prod = get_object_or_404(Product, uuid=obj_uuid)
|
|
||||||
first = prod.images.order_by("priority").first()
|
|
||||||
if first and first.image:
|
|
||||||
image_url = request.build_absolute_uri(first.image.url)
|
|
||||||
elif idx == "brands" and request:
|
|
||||||
brand = get_object_or_404(Brand, uuid=obj_uuid)
|
|
||||||
if brand.small_logo:
|
|
||||||
image_url = request.build_absolute_uri(brand.small_logo.url)
|
|
||||||
elif idx == "categories" and request:
|
|
||||||
cat = get_object_or_404(Category, uuid=obj_uuid)
|
|
||||||
if cat.image:
|
|
||||||
image_url = request.build_absolute_uri(cat.image.url)
|
|
||||||
|
|
||||||
hit_result = {
|
|
||||||
"uuid": str(obj_uuid),
|
|
||||||
"name": obj_name,
|
|
||||||
"slug": obj_slug,
|
|
||||||
"image": image_url,
|
|
||||||
}
|
|
||||||
|
|
||||||
if settings.DEBUG:
|
|
||||||
if idx == "products":
|
|
||||||
hit_result["rating_debug"] = getattr(hit, "rating", 0)
|
|
||||||
hit_result["total_orders_debug"] = getattr(hit, "total_orders", 0)
|
|
||||||
hit_result["brand_priority_debug"] = getattr(hit, "brand_priority", 0)
|
|
||||||
hit_result["category_priority_debug"] = getattr(hit, "category_priority", 0)
|
|
||||||
if idx == "brands":
|
|
||||||
hit_result["priority_debug"] = getattr(hit, "priority", 0)
|
|
||||||
if idx == "categories":
|
|
||||||
hit_result["priority_debug"] = getattr(hit, "priority", 0)
|
|
||||||
if idx == "posts":
|
|
||||||
pass
|
|
||||||
|
|
||||||
results[idx].append(hit_result)
|
|
||||||
|
|
||||||
return results
|
|
||||||
except NotFoundError:
|
|
||||||
raise Http404
|
|
||||||
|
|
||||||
|
|
||||||
LANGUAGE_ANALYZER_MAP = {
|
|
||||||
"ar": "arabic",
|
|
||||||
"cs": "czech",
|
|
||||||
"da": "danish",
|
|
||||||
"de": "german",
|
|
||||||
"en": "english",
|
|
||||||
"es": "spanish",
|
|
||||||
"fr": "french",
|
|
||||||
"hi": "hindi",
|
|
||||||
"it": "italian",
|
|
||||||
"ja": "standard",
|
|
||||||
"kk": "standard",
|
|
||||||
"nl": "dutch",
|
|
||||||
"pl": "standard",
|
|
||||||
"pt": "portuguese",
|
|
||||||
"ro": "romanian",
|
|
||||||
"ru": "russian",
|
|
||||||
"zh": "standard",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def _lang_analyzer(lang_code: str) -> str:
|
|
||||||
"""Return the best‑guess ES analyzer for an ISO language code."""
|
|
||||||
base = lang_code.split("-")[0].lower()
|
|
||||||
return LANGUAGE_ANALYZER_MAP.get(base, "standard")
|
|
||||||
|
|
||||||
|
|
||||||
class ActiveOnlyMixin:
|
|
||||||
"""QuerySet & indexing helpers, so only *active* objects are indexed."""
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
return super().get_queryset().filter(is_active=True)
|
|
||||||
|
|
||||||
def should_index_object(self, obj):
|
|
||||||
return getattr(obj, "is_active", False)
|
|
||||||
|
|
||||||
|
|
||||||
COMMON_ANALYSIS = {
|
|
||||||
"filter": {
|
|
||||||
"edge_ngram_filter": {"type": "edge_ngram", "min_gram": 1, "max_gram": 20},
|
|
||||||
"ngram_filter": {"type": "ngram", "min_gram": 2, "max_gram": 20},
|
|
||||||
"double_metaphone": {
|
|
||||||
"type": "phonetic",
|
|
||||||
"encoder": "double_metaphone",
|
|
||||||
"replace": False,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"analyzer": {
|
|
||||||
"autocomplete": {
|
|
||||||
"tokenizer": "standard",
|
|
||||||
"filter": ["lowercase", "asciifolding", "edge_ngram_filter"],
|
|
||||||
},
|
|
||||||
"autocomplete_search": {
|
|
||||||
"tokenizer": "standard",
|
|
||||||
"filter": ["lowercase", "asciifolding"],
|
|
||||||
},
|
|
||||||
"name_ngram": {
|
|
||||||
"tokenizer": "standard",
|
|
||||||
"filter": ["lowercase", "asciifolding", "ngram_filter"],
|
|
||||||
},
|
|
||||||
"name_phonetic": {
|
|
||||||
"tokenizer": "standard",
|
|
||||||
"filter": ["lowercase", "asciifolding", "double_metaphone"],
|
|
||||||
},
|
|
||||||
"query_lc": {"tokenizer": "standard", "filter": ["lowercase", "asciifolding"]},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def _add_multilang_fields(cls):
|
|
||||||
"""
|
|
||||||
Dynamically add multilingual name/description fields and prepare methods to guard against None.
|
|
||||||
"""
|
|
||||||
for code, _lang in settings.LANGUAGES:
|
|
||||||
lc = code.replace("-", "_").lower()
|
|
||||||
# name_{lc}
|
|
||||||
name_field = f"name_{lc}"
|
|
||||||
setattr(
|
|
||||||
cls,
|
|
||||||
name_field,
|
|
||||||
fields.TextField(
|
|
||||||
attr=name_field,
|
|
||||||
analyzer=_lang_analyzer(code),
|
|
||||||
copy_to="name",
|
|
||||||
fields={
|
|
||||||
"raw": fields.KeywordField(ignore_above=256),
|
|
||||||
"ngram": fields.TextField(analyzer="name_ngram", search_analyzer="query_lc"),
|
|
||||||
"phonetic": fields.TextField(analyzer="name_phonetic"),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
# prepare_name_{lc} to ensure no None values
|
|
||||||
def make_prepare(attr):
|
|
||||||
return lambda self, instance: getattr(instance, attr, "") or ""
|
|
||||||
|
|
||||||
setattr(cls, f"prepare_{name_field}", make_prepare(name_field))
|
|
||||||
|
|
||||||
# description_{lc}
|
|
||||||
desc_field = f"description_{lc}"
|
|
||||||
setattr(
|
|
||||||
cls,
|
|
||||||
desc_field,
|
|
||||||
fields.TextField(
|
|
||||||
attr=desc_field,
|
|
||||||
analyzer=_lang_analyzer(code),
|
|
||||||
copy_to="description",
|
|
||||||
fields={
|
|
||||||
"raw": fields.KeywordField(ignore_above=256),
|
|
||||||
"ngram": fields.TextField(analyzer="name_ngram", search_analyzer="query_lc"),
|
|
||||||
"phonetic": fields.TextField(analyzer="name_phonetic"),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
setattr(cls, f"prepare_{desc_field}", make_prepare(desc_field))
|
|
||||||
|
|
||||||
|
|
||||||
def populate_index():
|
|
||||||
for doc in registry.get_documents(set(registry.get_models())):
|
|
||||||
qs = doc().get_indexing_queryset()
|
|
||||||
doc().update(qs, parallel=True, refresh=True)
|
|
||||||
|
|
@ -1,125 +0,0 @@
|
||||||
from django_elasticsearch_dsl import Document, fields
|
|
||||||
from django_elasticsearch_dsl.registries import registry
|
|
||||||
from health_check.db.models import TestModel
|
|
||||||
|
|
||||||
from core.elasticsearch import COMMON_ANALYSIS, ActiveOnlyMixin, _add_multilang_fields
|
|
||||||
from core.models import Brand, Category, Product
|
|
||||||
|
|
||||||
|
|
||||||
class _BaseDoc(ActiveOnlyMixin, Document):
|
|
||||||
name = fields.TextField(
|
|
||||||
attr="name",
|
|
||||||
analyzer="standard",
|
|
||||||
fields={
|
|
||||||
"raw": fields.KeywordField(ignore_above=256),
|
|
||||||
"ngram": fields.TextField(analyzer="name_ngram", search_analyzer="query_lc"),
|
|
||||||
"phonetic": fields.TextField(analyzer="name_phonetic"),
|
|
||||||
"auto": fields.TextField(analyzer="autocomplete", search_analyzer="autocomplete_search"),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
description = fields.TextField(
|
|
||||||
attr="description",
|
|
||||||
analyzer="standard",
|
|
||||||
fields={
|
|
||||||
"raw": fields.KeywordField(ignore_above=256),
|
|
||||||
"ngram": fields.TextField(analyzer="name_ngram", search_analyzer="query_lc"),
|
|
||||||
"phonetic": fields.TextField(analyzer="name_phonetic"),
|
|
||||||
"auto": fields.TextField(analyzer="autocomplete", search_analyzer="autocomplete_search"),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
slug = fields.KeywordField(attr="slug", index=False)
|
|
||||||
|
|
||||||
class Index:
|
|
||||||
settings = {
|
|
||||||
"number_of_shards": 1,
|
|
||||||
"number_of_replicas": 0,
|
|
||||||
"analysis": COMMON_ANALYSIS,
|
|
||||||
"index": {"max_ngram_diff": 20},
|
|
||||||
}
|
|
||||||
|
|
||||||
def prepare_name(self, instance):
|
|
||||||
return getattr(instance, "name", "") or ""
|
|
||||||
|
|
||||||
def prepare_description(self, instance):
|
|
||||||
return getattr(instance, "description", "") or ""
|
|
||||||
|
|
||||||
|
|
||||||
class ProductDocument(_BaseDoc):
|
|
||||||
rating = fields.FloatField(attr="rating")
|
|
||||||
total_order = fields.IntegerField(attr="total_orders")
|
|
||||||
brand_priority = fields.IntegerField(
|
|
||||||
attr="brand.priority",
|
|
||||||
index=True,
|
|
||||||
fields={"raw": fields.KeywordField()},
|
|
||||||
)
|
|
||||||
category_priority = fields.IntegerField(
|
|
||||||
attr="category.priority",
|
|
||||||
index=True,
|
|
||||||
fields={"raw": fields.KeywordField()},
|
|
||||||
)
|
|
||||||
|
|
||||||
class Index(_BaseDoc.Index):
|
|
||||||
name = "products"
|
|
||||||
|
|
||||||
class Django:
|
|
||||||
model = Product
|
|
||||||
fields = ["uuid"]
|
|
||||||
|
|
||||||
|
|
||||||
_add_multilang_fields(ProductDocument)
|
|
||||||
registry.register_document(ProductDocument)
|
|
||||||
|
|
||||||
|
|
||||||
class CategoryDocument(_BaseDoc):
|
|
||||||
priority = fields.IntegerField(attr="priority")
|
|
||||||
|
|
||||||
class Index(_BaseDoc.Index):
|
|
||||||
name = "categories"
|
|
||||||
|
|
||||||
class Django:
|
|
||||||
model = Category
|
|
||||||
fields = ["uuid"]
|
|
||||||
|
|
||||||
|
|
||||||
_add_multilang_fields(CategoryDocument)
|
|
||||||
registry.register_document(CategoryDocument)
|
|
||||||
|
|
||||||
|
|
||||||
class BrandDocument(ActiveOnlyMixin, Document):
|
|
||||||
priority = fields.IntegerField(attr="priority")
|
|
||||||
|
|
||||||
class Index:
|
|
||||||
name = "brands"
|
|
||||||
settings = {
|
|
||||||
"number_of_shards": 1,
|
|
||||||
"number_of_replicas": 0,
|
|
||||||
"analysis": COMMON_ANALYSIS,
|
|
||||||
"index": {"max_ngram_diff": 18},
|
|
||||||
}
|
|
||||||
|
|
||||||
class Django:
|
|
||||||
model = Brand
|
|
||||||
fields = ["uuid"]
|
|
||||||
|
|
||||||
def prepare_name(self, instance):
|
|
||||||
return getattr(instance, "name", "") or ""
|
|
||||||
|
|
||||||
|
|
||||||
registry.register_document(BrandDocument)
|
|
||||||
|
|
||||||
|
|
||||||
class TestModelDocument(Document):
|
|
||||||
class Index:
|
|
||||||
name = "testmodels"
|
|
||||||
|
|
||||||
class Django:
|
|
||||||
model = TestModel
|
|
||||||
fields = [
|
|
||||||
"title",
|
|
||||||
]
|
|
||||||
ignore_signals = True
|
|
||||||
related_models: list = []
|
|
||||||
auto_refresh = False
|
|
||||||
|
|
||||||
|
|
||||||
registry.register_document(TestModelDocument)
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
from graphene import Mutation
|
|
||||||
|
|
||||||
|
|
||||||
class BaseMutation(Mutation):
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def mutate(**kwargs):
|
|
||||||
pass
|
|
||||||
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
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
|
|
@ -1,7 +0,0 @@
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
|
|
||||||
class RootDirectory:
|
|
||||||
def __init__(self):
|
|
||||||
self.label = "root"
|
|
||||||
self.path = settings.BASE_DIR / "evibes"
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
from django.core.management.base import BaseCommand
|
|
||||||
from django.db import transaction
|
|
||||||
|
|
||||||
from core.models import Product
|
|
||||||
|
|
||||||
CHUNK_SIZE = 5000
|
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
|
||||||
help = "Delete Product rows with no OrderProduct, in batches"
|
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
|
||||||
while True:
|
|
||||||
batch_ids = list(
|
|
||||||
Product.objects.filter(orderproduct__isnull=True).values_list("pk", flat=True)[:CHUNK_SIZE]
|
|
||||||
)
|
|
||||||
if not batch_ids:
|
|
||||||
break
|
|
||||||
with transaction.atomic():
|
|
||||||
Product.objects.filter(pk__in=batch_ids).delete()
|
|
||||||
self.stdout.write(f"Deleted {len(batch_ids)} products…")
|
|
||||||
|
|
||||||
self.stdout.write("✅ All unordered products removed.")
|
|
||||||
|
|
@ -1,996 +0,0 @@
|
||||||
# Generated by Django 5.1.5 on 2025-03-10 11:38
|
|
||||||
|
|
||||||
import uuid
|
|
||||||
|
|
||||||
import django.core.validators
|
|
||||||
import django.db.models.deletion
|
|
||||||
import django_extensions.db.fields
|
|
||||||
import mptt.fields
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
import core.utils
|
|
||||||
import core.validators
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
initial = True
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Feedback',
|
|
||||||
fields=[
|
|
||||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
|
|
||||||
help_text='unique id is used to surely identify any database object',
|
|
||||||
primary_key=True, serialize=False, verbose_name='unique id')),
|
|
||||||
('is_active', models.BooleanField(default=True,
|
|
||||||
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')),
|
|
||||||
('comment', models.TextField(blank=True,
|
|
||||||
help_text='user-provided comments about their experience with the product',
|
|
||||||
null=True, verbose_name='feedback comments')),
|
|
||||||
('rating', models.FloatField(blank=True, help_text='user-assigned rating for the product', null=True,
|
|
||||||
validators=[django.core.validators.MinValueValidator(0),
|
|
||||||
django.core.validators.MaxValueValidator(10)],
|
|
||||||
verbose_name='product rating')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'feedback',
|
|
||||||
'verbose_name_plural': 'feedbacks',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='OrderProduct',
|
|
||||||
fields=[
|
|
||||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
|
|
||||||
help_text='unique id is used to surely identify any database object',
|
|
||||||
primary_key=True, serialize=False, verbose_name='unique id')),
|
|
||||||
('is_active', models.BooleanField(default=True,
|
|
||||||
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')),
|
|
||||||
('buy_price', models.FloatField(blank=True,
|
|
||||||
help_text='the price paid by the customer for this product at purchase time',
|
|
||||||
null=True, verbose_name='purchase price at order time')),
|
|
||||||
('comments',
|
|
||||||
models.TextField(blank=True, help_text='internal comments for admins about this ordered product',
|
|
||||||
null=True, verbose_name='internal comments')),
|
|
||||||
('notifications',
|
|
||||||
models.JSONField(blank=True, help_text='json structure of notifications to display to users',
|
|
||||||
null=True, verbose_name='user notifications')),
|
|
||||||
('attributes',
|
|
||||||
models.JSONField(blank=True, help_text="json representation of this item's attributes", null=True,
|
|
||||||
verbose_name='ordered product attributes')),
|
|
||||||
('quantity',
|
|
||||||
models.PositiveIntegerField(default=1, help_text='quantity of this specific product in the order',
|
|
||||||
verbose_name='product quantity')),
|
|
||||||
('status', models.CharField(
|
|
||||||
choices=[('FINISHED', 'finished'), ('DELIVERING', 'delivering'), ('DELIVERED', 'delivered'),
|
|
||||||
('CANCELED', 'canceled'), ('FAILED', 'failed'), ('PENDING', 'pending'),
|
|
||||||
('ACCEPTED', 'accepted'), ('RETURNED', 'money returned')], default='PENDING',
|
|
||||||
help_text='current status of this product in the order', max_length=128,
|
|
||||||
verbose_name='product line status')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'order product',
|
|
||||||
'verbose_name_plural': 'order products',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Product',
|
|
||||||
fields=[
|
|
||||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
|
|
||||||
help_text='unique id is used to surely identify any database object',
|
|
||||||
primary_key=True, serialize=False, verbose_name='unique id')),
|
|
||||||
('is_active', models.BooleanField(default=True,
|
|
||||||
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')),
|
|
||||||
('is_digital',
|
|
||||||
models.BooleanField(default=False, help_text='indicates whether this product is digitally delivered',
|
|
||||||
verbose_name='is product digital')),
|
|
||||||
('name', models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
|
|
||||||
verbose_name='product name')),
|
|
||||||
('name_en_GB',
|
|
||||||
models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
|
|
||||||
null=True, verbose_name='product name')),
|
|
||||||
('name_ar_AR',
|
|
||||||
models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
|
|
||||||
null=True, verbose_name='product name')),
|
|
||||||
('name_cs_CZ',
|
|
||||||
models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
|
|
||||||
null=True, verbose_name='product name')),
|
|
||||||
('name_da_DK',
|
|
||||||
models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
|
|
||||||
null=True, verbose_name='product name')),
|
|
||||||
('name_de_DE',
|
|
||||||
models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
|
|
||||||
null=True, verbose_name='product name')),
|
|
||||||
('name_en_US',
|
|
||||||
models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
|
|
||||||
null=True, verbose_name='product name')),
|
|
||||||
('name_es_ES',
|
|
||||||
models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
|
|
||||||
null=True, verbose_name='product name')),
|
|
||||||
('name_fr_FR',
|
|
||||||
models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
|
|
||||||
null=True, verbose_name='product name')),
|
|
||||||
('name_hi_IN',
|
|
||||||
models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
|
|
||||||
null=True, verbose_name='product name')),
|
|
||||||
('name_it_IT',
|
|
||||||
models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
|
|
||||||
null=True, verbose_name='product name')),
|
|
||||||
('name_ja_JP',
|
|
||||||
models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
|
|
||||||
null=True, verbose_name='product name')),
|
|
||||||
('name_kk_KZ',
|
|
||||||
models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
|
|
||||||
null=True, verbose_name='product name')),
|
|
||||||
('name_nl_NL',
|
|
||||||
models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
|
|
||||||
null=True, verbose_name='product name')),
|
|
||||||
('name_pl_PL',
|
|
||||||
models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
|
|
||||||
null=True, verbose_name='product name')),
|
|
||||||
('name_pt_BR',
|
|
||||||
models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
|
|
||||||
null=True, verbose_name='product name')),
|
|
||||||
('name_ro_RO',
|
|
||||||
models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
|
|
||||||
null=True, verbose_name='product name')),
|
|
||||||
('name_ru_RU',
|
|
||||||
models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
|
|
||||||
null=True, verbose_name='product name')),
|
|
||||||
('name_zh_hans',
|
|
||||||
models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
|
|
||||||
null=True, verbose_name='product name')),
|
|
||||||
('description',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='product description')),
|
|
||||||
('description_en_GB',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='product description')),
|
|
||||||
('description_ar_AR',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='product description')),
|
|
||||||
('description_cs_CZ',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='product description')),
|
|
||||||
('description_da_DK',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='product description')),
|
|
||||||
('description_de_DE',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='product description')),
|
|
||||||
('description_en_US',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='product description')),
|
|
||||||
('description_es_ES',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='product description')),
|
|
||||||
('description_fr_FR',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='product description')),
|
|
||||||
('description_hi_IN',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='product description')),
|
|
||||||
('description_it_IT',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='product description')),
|
|
||||||
('description_ja_JP',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='product description')),
|
|
||||||
('description_kk_KZ',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='product description')),
|
|
||||||
('description_nl_NL',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='product description')),
|
|
||||||
('description_pl_PL',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='product description')),
|
|
||||||
('description_pt_BR',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='product description')),
|
|
||||||
('description_ro_RO',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='product description')),
|
|
||||||
('description_ru_RU',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='product description')),
|
|
||||||
('description_zh_hans',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='product description')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'product',
|
|
||||||
'verbose_name_plural': 'products',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='ProductImage',
|
|
||||||
fields=[
|
|
||||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
|
|
||||||
help_text='unique id is used to surely identify any database object',
|
|
||||||
primary_key=True, serialize=False, verbose_name='unique id')),
|
|
||||||
('is_active', models.BooleanField(default=True,
|
|
||||||
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')),
|
|
||||||
('alt',
|
|
||||||
models.CharField(help_text='provide alternative text for the image for accessibility', max_length=255,
|
|
||||||
verbose_name='image alt text')),
|
|
||||||
('image', models.ImageField(help_text='upload the image file for this product',
|
|
||||||
upload_to=core.utils.get_product_uuid_as_path,
|
|
||||||
verbose_name='product image')),
|
|
||||||
('priority',
|
|
||||||
models.IntegerField(default=1, help_text='determines the order in which images are displayed',
|
|
||||||
validators=[django.core.validators.MinValueValidator(1)],
|
|
||||||
verbose_name='display priority')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'product image',
|
|
||||||
'verbose_name_plural': 'product images',
|
|
||||||
'ordering': ('priority',),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='ProductTag',
|
|
||||||
fields=[
|
|
||||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
|
|
||||||
help_text='unique id is used to surely identify any database object',
|
|
||||||
primary_key=True, serialize=False, verbose_name='unique id')),
|
|
||||||
('is_active', models.BooleanField(default=True,
|
|
||||||
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 product tag', max_length=255,
|
|
||||||
verbose_name='tag name')),
|
|
||||||
('name', models.CharField(help_text='user-friendly name for the product tag', max_length=255,
|
|
||||||
verbose_name='tag display name')),
|
|
||||||
('name_en_GB',
|
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
|
||||||
verbose_name='tag display name')),
|
|
||||||
('name_ar_AR',
|
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
|
||||||
verbose_name='tag display name')),
|
|
||||||
('name_cs_CZ',
|
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
|
||||||
verbose_name='tag display name')),
|
|
||||||
('name_da_DK',
|
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
|
||||||
verbose_name='tag display name')),
|
|
||||||
('name_de_DE',
|
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
|
||||||
verbose_name='tag display name')),
|
|
||||||
('name_en_US',
|
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
|
||||||
verbose_name='tag display name')),
|
|
||||||
('name_es_ES',
|
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
|
||||||
verbose_name='tag display name')),
|
|
||||||
('name_fr_FR',
|
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
|
||||||
verbose_name='tag display name')),
|
|
||||||
('name_hi_IN',
|
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
|
||||||
verbose_name='tag display name')),
|
|
||||||
('name_it_IT',
|
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
|
||||||
verbose_name='tag display name')),
|
|
||||||
('name_ja_JP',
|
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
|
||||||
verbose_name='tag display name')),
|
|
||||||
('name_kk_KZ',
|
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
|
||||||
verbose_name='tag display name')),
|
|
||||||
('name_nl_NL',
|
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
|
||||||
verbose_name='tag display name')),
|
|
||||||
('name_pl_PL',
|
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
|
||||||
verbose_name='tag display name')),
|
|
||||||
('name_pt_BR',
|
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
|
||||||
verbose_name='tag display name')),
|
|
||||||
('name_ro_RO',
|
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
|
||||||
verbose_name='tag display name')),
|
|
||||||
('name_ru_RU',
|
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
|
||||||
verbose_name='tag display name')),
|
|
||||||
('name_zh_hans',
|
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
|
||||||
verbose_name='tag display name')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'product tag',
|
|
||||||
'verbose_name_plural': 'product tags',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='PromoCode',
|
|
||||||
fields=[
|
|
||||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
|
|
||||||
help_text='unique id is used to surely identify any database object',
|
|
||||||
primary_key=True, serialize=False, verbose_name='unique id')),
|
|
||||||
('is_active', models.BooleanField(default=True,
|
|
||||||
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')),
|
|
||||||
('code', models.CharField(default=core.utils.get_random_code,
|
|
||||||
help_text='unique code used by a user to redeem a discount', max_length=20,
|
|
||||||
unique=True, verbose_name='promo code identifier')),
|
|
||||||
('discount_amount', models.DecimalField(blank=True, decimal_places=2,
|
|
||||||
help_text='fixed discount amount applied if percent is not used',
|
|
||||||
max_digits=10, null=True,
|
|
||||||
verbose_name='fixed discount amount')),
|
|
||||||
('discount_percent',
|
|
||||||
models.IntegerField(blank=True, help_text='percentage discount applied if fixed amount is not used',
|
|
||||||
null=True, validators=[django.core.validators.MinValueValidator(1),
|
|
||||||
django.core.validators.MaxValueValidator(100)],
|
|
||||||
verbose_name='percentage discount')),
|
|
||||||
('end_time',
|
|
||||||
models.DateTimeField(blank=True, help_text='timestamp when the promocode expires', null=True,
|
|
||||||
verbose_name='end validity time')),
|
|
||||||
('start_time',
|
|
||||||
models.DateTimeField(blank=True, help_text='timestamp from which this promocode is valid', null=True,
|
|
||||||
verbose_name='start validity time')),
|
|
||||||
('used_on', models.DateTimeField(blank=True,
|
|
||||||
help_text='timestamp when the promocode was used, blank if not used yet',
|
|
||||||
null=True, verbose_name='usage timestamp')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'promo code',
|
|
||||||
'verbose_name_plural': 'promo codes',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Promotion',
|
|
||||||
fields=[
|
|
||||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
|
|
||||||
help_text='unique id is used to surely identify any database object',
|
|
||||||
primary_key=True, serialize=False, verbose_name='unique id')),
|
|
||||||
('is_active', models.BooleanField(default=True,
|
|
||||||
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')),
|
|
||||||
('discount_percent', models.IntegerField(help_text='percentage discount for the selected products',
|
|
||||||
validators=[django.core.validators.MinValueValidator(1),
|
|
||||||
django.core.validators.MaxValueValidator(100)],
|
|
||||||
verbose_name='discount percentage')),
|
|
||||||
('name',
|
|
||||||
models.CharField(help_text='provide a unique name for this promotion', max_length=256, unique=True,
|
|
||||||
verbose_name='promotion name')),
|
|
||||||
('name_en_GB',
|
|
||||||
models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
|
|
||||||
unique=True, verbose_name='promotion name')),
|
|
||||||
('name_ar_AR',
|
|
||||||
models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
|
|
||||||
unique=True, verbose_name='promotion name')),
|
|
||||||
('name_cs_CZ',
|
|
||||||
models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
|
|
||||||
unique=True, verbose_name='promotion name')),
|
|
||||||
('name_da_DK',
|
|
||||||
models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
|
|
||||||
unique=True, verbose_name='promotion name')),
|
|
||||||
('name_de_DE',
|
|
||||||
models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
|
|
||||||
unique=True, verbose_name='promotion name')),
|
|
||||||
('name_en_US',
|
|
||||||
models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
|
|
||||||
unique=True, verbose_name='promotion name')),
|
|
||||||
('name_es_ES',
|
|
||||||
models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
|
|
||||||
unique=True, verbose_name='promotion name')),
|
|
||||||
('name_fr_FR',
|
|
||||||
models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
|
|
||||||
unique=True, verbose_name='promotion name')),
|
|
||||||
('name_hi_IN',
|
|
||||||
models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
|
|
||||||
unique=True, verbose_name='promotion name')),
|
|
||||||
('name_it_IT',
|
|
||||||
models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
|
|
||||||
unique=True, verbose_name='promotion name')),
|
|
||||||
('name_ja_JP',
|
|
||||||
models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
|
|
||||||
unique=True, verbose_name='promotion name')),
|
|
||||||
('name_kk_KZ',
|
|
||||||
models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
|
|
||||||
unique=True, verbose_name='promotion name')),
|
|
||||||
('name_nl_NL',
|
|
||||||
models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
|
|
||||||
unique=True, verbose_name='promotion name')),
|
|
||||||
('name_pl_PL',
|
|
||||||
models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
|
|
||||||
unique=True, verbose_name='promotion name')),
|
|
||||||
('name_pt_BR',
|
|
||||||
models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
|
|
||||||
unique=True, verbose_name='promotion name')),
|
|
||||||
('name_ro_RO',
|
|
||||||
models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
|
|
||||||
unique=True, verbose_name='promotion name')),
|
|
||||||
('name_ru_RU',
|
|
||||||
models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
|
|
||||||
unique=True, verbose_name='promotion name')),
|
|
||||||
('name_zh_hans',
|
|
||||||
models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
|
|
||||||
unique=True, verbose_name='promotion name')),
|
|
||||||
('description',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='promotion description')),
|
|
||||||
('description_en_GB',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='promotion description')),
|
|
||||||
('description_ar_AR',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='promotion description')),
|
|
||||||
('description_cs_CZ',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='promotion description')),
|
|
||||||
('description_da_DK',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='promotion description')),
|
|
||||||
('description_de_DE',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='promotion description')),
|
|
||||||
('description_en_US',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='promotion description')),
|
|
||||||
('description_es_ES',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='promotion description')),
|
|
||||||
('description_fr_FR',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='promotion description')),
|
|
||||||
('description_hi_IN',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='promotion description')),
|
|
||||||
('description_it_IT',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='promotion description')),
|
|
||||||
('description_ja_JP',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='promotion description')),
|
|
||||||
('description_kk_KZ',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='promotion description')),
|
|
||||||
('description_nl_NL',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='promotion description')),
|
|
||||||
('description_pl_PL',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='promotion description')),
|
|
||||||
('description_pt_BR',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='promotion description')),
|
|
||||||
('description_ro_RO',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='promotion description')),
|
|
||||||
('description_ru_RU',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='promotion description')),
|
|
||||||
('description_zh_hans',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
|
|
||||||
verbose_name='promotion description')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'promotion',
|
|
||||||
'verbose_name_plural': 'promotions',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Stock',
|
|
||||||
fields=[
|
|
||||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
|
|
||||||
help_text='unique id is used to surely identify any database object',
|
|
||||||
primary_key=True, serialize=False, verbose_name='unique id')),
|
|
||||||
('is_active', models.BooleanField(default=True,
|
|
||||||
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')),
|
|
||||||
('price', models.FloatField(default=0.0, help_text='final price to the customer after markups',
|
|
||||||
verbose_name='selling price')),
|
|
||||||
('purchase_price',
|
|
||||||
models.FloatField(default=0.0, help_text='the price paid to the vendor for this product',
|
|
||||||
verbose_name='vendor purchase price')),
|
|
||||||
('quantity', models.IntegerField(default=0, help_text='available quantity of the product in stock',
|
|
||||||
verbose_name='quantity in stock')),
|
|
||||||
('sku', models.CharField(help_text='vendor-assigned SKU for identifying the product', max_length=255,
|
|
||||||
verbose_name='vendor sku')),
|
|
||||||
('digital_asset', models.FileField(blank=True, default=None,
|
|
||||||
help_text='digital file associated with this stock if applicable',
|
|
||||||
null=True, upload_to='downloadables/', verbose_name='digital file')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'stock',
|
|
||||||
'verbose_name_plural': 'stock entries',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Vendor',
|
|
||||||
fields=[
|
|
||||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
|
|
||||||
help_text='unique id is used to surely identify any database object',
|
|
||||||
primary_key=True, serialize=False, verbose_name='unique id')),
|
|
||||||
('is_active', models.BooleanField(default=True,
|
|
||||||
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')),
|
|
||||||
('authentication', models.JSONField(blank=True,
|
|
||||||
help_text='stores credentials and endpoints required for vendor communication',
|
|
||||||
null=True, verbose_name='authentication info')),
|
|
||||||
('markup_percent',
|
|
||||||
models.IntegerField(default=0, help_text='define the markup for products retrieved from this vendor',
|
|
||||||
validators=[django.core.validators.MinValueValidator(0),
|
|
||||||
django.core.validators.MaxValueValidator(100)],
|
|
||||||
verbose_name='vendor markup percentage')),
|
|
||||||
('name', models.CharField(help_text='name of this vendor', max_length=255, verbose_name='vendor name')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'vendor',
|
|
||||||
'verbose_name_plural': 'vendors',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Wishlist',
|
|
||||||
fields=[
|
|
||||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
|
|
||||||
help_text='unique id is used to surely identify any database object',
|
|
||||||
primary_key=True, serialize=False, verbose_name='unique id')),
|
|
||||||
('is_active', models.BooleanField(default=True,
|
|
||||||
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')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'wishlist',
|
|
||||||
'verbose_name_plural': 'wishlists',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='AttributeGroup',
|
|
||||||
fields=[
|
|
||||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
|
|
||||||
help_text='unique id is used to surely identify any database object',
|
|
||||||
primary_key=True, serialize=False, verbose_name='unique id')),
|
|
||||||
('is_active', models.BooleanField(default=True,
|
|
||||||
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')),
|
|
||||||
('name', models.CharField(help_text="attribute group's name", max_length=255,
|
|
||||||
verbose_name="attribute group's name")),
|
|
||||||
('name_en_GB', models.CharField(help_text="attribute group's name", max_length=255, null=True,
|
|
||||||
verbose_name="attribute group's name")),
|
|
||||||
('name_ar_AR', models.CharField(help_text="attribute group's name", max_length=255, null=True,
|
|
||||||
verbose_name="attribute group's name")),
|
|
||||||
('name_cs_CZ', models.CharField(help_text="attribute group's name", max_length=255, null=True,
|
|
||||||
verbose_name="attribute group's name")),
|
|
||||||
('name_da_DK', models.CharField(help_text="attribute group's name", max_length=255, null=True,
|
|
||||||
verbose_name="attribute group's name")),
|
|
||||||
('name_de_DE', models.CharField(help_text="attribute group's name", max_length=255, null=True,
|
|
||||||
verbose_name="attribute group's name")),
|
|
||||||
('name_en_US', models.CharField(help_text="attribute group's name", max_length=255, null=True,
|
|
||||||
verbose_name="attribute group's name")),
|
|
||||||
('name_es_ES', models.CharField(help_text="attribute group's name", max_length=255, null=True,
|
|
||||||
verbose_name="attribute group's name")),
|
|
||||||
('name_fr_FR', models.CharField(help_text="attribute group's name", max_length=255, null=True,
|
|
||||||
verbose_name="attribute group's name")),
|
|
||||||
('name_hi_IN', models.CharField(help_text="attribute group's name", max_length=255, null=True,
|
|
||||||
verbose_name="attribute group's name")),
|
|
||||||
('name_it_IT', models.CharField(help_text="attribute group's name", max_length=255, null=True,
|
|
||||||
verbose_name="attribute group's name")),
|
|
||||||
('name_ja_JP', models.CharField(help_text="attribute group's name", max_length=255, null=True,
|
|
||||||
verbose_name="attribute group's name")),
|
|
||||||
('name_kk_KZ', models.CharField(help_text="attribute group's name", max_length=255, null=True,
|
|
||||||
verbose_name="attribute group's name")),
|
|
||||||
('name_nl_NL', models.CharField(help_text="attribute group's name", max_length=255, null=True,
|
|
||||||
verbose_name="attribute group's name")),
|
|
||||||
('name_pl_PL', models.CharField(help_text="attribute group's name", max_length=255, null=True,
|
|
||||||
verbose_name="attribute group's name")),
|
|
||||||
('name_pt_BR', models.CharField(help_text="attribute group's name", max_length=255, null=True,
|
|
||||||
verbose_name="attribute group's name")),
|
|
||||||
('name_ro_RO', models.CharField(help_text="attribute group's name", max_length=255, null=True,
|
|
||||||
verbose_name="attribute group's name")),
|
|
||||||
('name_ru_RU', models.CharField(help_text="attribute group's name", max_length=255, null=True,
|
|
||||||
verbose_name="attribute group's name")),
|
|
||||||
('name_zh_hans', models.CharField(help_text="attribute group's name", max_length=255, null=True,
|
|
||||||
verbose_name="attribute group's name")),
|
|
||||||
('parent', models.ForeignKey(blank=True, help_text='parent of this group', null=True,
|
|
||||||
on_delete=django.db.models.deletion.CASCADE, related_name='children',
|
|
||||||
to='core.attributegroup', verbose_name='parent attribute group')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'attribute group',
|
|
||||||
'verbose_name_plural': 'attribute groups',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Attribute',
|
|
||||||
fields=[
|
|
||||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
|
|
||||||
help_text='unique id is used to surely identify any database object',
|
|
||||||
primary_key=True, serialize=False, verbose_name='unique id')),
|
|
||||||
('is_active', models.BooleanField(default=True,
|
|
||||||
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')),
|
|
||||||
('value_type', models.CharField(
|
|
||||||
choices=[('string', 'string'), ('integer', 'integer'), ('float', 'float'), ('boolean', 'boolean'),
|
|
||||||
('array', 'array'), ('object', 'object')], help_text="type of the attribute's value",
|
|
||||||
max_length=50, verbose_name='value type')),
|
|
||||||
('name',
|
|
||||||
models.CharField(help_text='name of this attribute', max_length=255, verbose_name="attribute's name")),
|
|
||||||
('name_en_GB', models.CharField(help_text='name of this attribute', max_length=255, null=True,
|
|
||||||
verbose_name="attribute's name")),
|
|
||||||
('name_ar_AR', models.CharField(help_text='name of this attribute', max_length=255, null=True,
|
|
||||||
verbose_name="attribute's name")),
|
|
||||||
('name_cs_CZ', models.CharField(help_text='name of this attribute', max_length=255, null=True,
|
|
||||||
verbose_name="attribute's name")),
|
|
||||||
('name_da_DK', models.CharField(help_text='name of this attribute', max_length=255, null=True,
|
|
||||||
verbose_name="attribute's name")),
|
|
||||||
('name_de_DE', models.CharField(help_text='name of this attribute', max_length=255, null=True,
|
|
||||||
verbose_name="attribute's name")),
|
|
||||||
('name_en_US', models.CharField(help_text='name of this attribute', max_length=255, null=True,
|
|
||||||
verbose_name="attribute's name")),
|
|
||||||
('name_es_ES', models.CharField(help_text='name of this attribute', max_length=255, null=True,
|
|
||||||
verbose_name="attribute's name")),
|
|
||||||
('name_fr_FR', models.CharField(help_text='name of this attribute', max_length=255, null=True,
|
|
||||||
verbose_name="attribute's name")),
|
|
||||||
('name_hi_IN', models.CharField(help_text='name of this attribute', max_length=255, null=True,
|
|
||||||
verbose_name="attribute's name")),
|
|
||||||
('name_it_IT', models.CharField(help_text='name of this attribute', max_length=255, null=True,
|
|
||||||
verbose_name="attribute's name")),
|
|
||||||
('name_ja_JP', models.CharField(help_text='name of this attribute', max_length=255, null=True,
|
|
||||||
verbose_name="attribute's name")),
|
|
||||||
('name_kk_KZ', models.CharField(help_text='name of this attribute', max_length=255, null=True,
|
|
||||||
verbose_name="attribute's name")),
|
|
||||||
('name_nl_NL', models.CharField(help_text='name of this attribute', max_length=255, null=True,
|
|
||||||
verbose_name="attribute's name")),
|
|
||||||
('name_pl_PL', models.CharField(help_text='name of this attribute', max_length=255, null=True,
|
|
||||||
verbose_name="attribute's name")),
|
|
||||||
('name_pt_BR', models.CharField(help_text='name of this attribute', max_length=255, null=True,
|
|
||||||
verbose_name="attribute's name")),
|
|
||||||
('name_ro_RO', models.CharField(help_text='name of this attribute', max_length=255, null=True,
|
|
||||||
verbose_name="attribute's name")),
|
|
||||||
('name_ru_RU', models.CharField(help_text='name of this attribute', max_length=255, null=True,
|
|
||||||
verbose_name="attribute's name")),
|
|
||||||
('name_zh_hans', models.CharField(help_text='name of this attribute', max_length=255, null=True,
|
|
||||||
verbose_name="attribute's name")),
|
|
||||||
('group',
|
|
||||||
models.ForeignKey(help_text='group of this attribute', on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
related_name='attributes', to='core.attributegroup',
|
|
||||||
verbose_name='attribute group')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'attribute',
|
|
||||||
'verbose_name_plural': 'attributes',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='AttributeValue',
|
|
||||||
fields=[
|
|
||||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
|
|
||||||
help_text='unique id is used to surely identify any database object',
|
|
||||||
primary_key=True, serialize=False, verbose_name='unique id')),
|
|
||||||
('is_active', models.BooleanField(default=True,
|
|
||||||
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')),
|
|
||||||
('value',
|
|
||||||
models.TextField(help_text='the specific value for this attribute', verbose_name='attribute value')),
|
|
||||||
('value_en_GB', models.TextField(help_text='the specific value for this attribute', null=True,
|
|
||||||
verbose_name='attribute value')),
|
|
||||||
('value_ar_AR', models.TextField(help_text='the specific value for this attribute', null=True,
|
|
||||||
verbose_name='attribute value')),
|
|
||||||
('value_cs_CZ', models.TextField(help_text='the specific value for this attribute', null=True,
|
|
||||||
verbose_name='attribute value')),
|
|
||||||
('value_da_DK', models.TextField(help_text='the specific value for this attribute', null=True,
|
|
||||||
verbose_name='attribute value')),
|
|
||||||
('value_de_DE', models.TextField(help_text='the specific value for this attribute', null=True,
|
|
||||||
verbose_name='attribute value')),
|
|
||||||
('value_en_US', models.TextField(help_text='the specific value for this attribute', null=True,
|
|
||||||
verbose_name='attribute value')),
|
|
||||||
('value_es_ES', models.TextField(help_text='the specific value for this attribute', null=True,
|
|
||||||
verbose_name='attribute value')),
|
|
||||||
('value_fr_FR', models.TextField(help_text='the specific value for this attribute', null=True,
|
|
||||||
verbose_name='attribute value')),
|
|
||||||
('value_hi_IN', models.TextField(help_text='the specific value for this attribute', null=True,
|
|
||||||
verbose_name='attribute value')),
|
|
||||||
('value_it_IT', models.TextField(help_text='the specific value for this attribute', null=True,
|
|
||||||
verbose_name='attribute value')),
|
|
||||||
('value_ja_JP', models.TextField(help_text='the specific value for this attribute', null=True,
|
|
||||||
verbose_name='attribute value')),
|
|
||||||
('value_kk_KZ', models.TextField(help_text='the specific value for this attribute', null=True,
|
|
||||||
verbose_name='attribute value')),
|
|
||||||
('value_nl_NL', models.TextField(help_text='the specific value for this attribute', null=True,
|
|
||||||
verbose_name='attribute value')),
|
|
||||||
('value_pl_PL', models.TextField(help_text='the specific value for this attribute', null=True,
|
|
||||||
verbose_name='attribute value')),
|
|
||||||
('value_pt_BR', models.TextField(help_text='the specific value for this attribute', null=True,
|
|
||||||
verbose_name='attribute value')),
|
|
||||||
('value_ro_RO', models.TextField(help_text='the specific value for this attribute', null=True,
|
|
||||||
verbose_name='attribute value')),
|
|
||||||
('value_ru_RU', models.TextField(help_text='the specific value for this attribute', null=True,
|
|
||||||
verbose_name='attribute value')),
|
|
||||||
('value_zh_hans', models.TextField(help_text='the specific value for this attribute', null=True,
|
|
||||||
verbose_name='attribute value')),
|
|
||||||
('attribute',
|
|
||||||
models.ForeignKey(help_text='attribute of this value', on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
related_name='values', to='core.attribute', verbose_name='attribute')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'attribute value',
|
|
||||||
'verbose_name_plural': 'attribute values',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Category',
|
|
||||||
fields=[
|
|
||||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
|
|
||||||
help_text='unique id is used to surely identify any database object',
|
|
||||||
primary_key=True, serialize=False, verbose_name='unique id')),
|
|
||||||
('is_active', models.BooleanField(default=True,
|
|
||||||
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')),
|
|
||||||
('image', models.ImageField(help_text='upload an image representing this category', null=True,
|
|
||||||
upload_to='categories/',
|
|
||||||
validators=[core.validators.validate_category_image_dimensions],
|
|
||||||
verbose_name='category image')),
|
|
||||||
('markup_percent',
|
|
||||||
models.IntegerField(default=0, help_text='define a markup percentage for products in this category',
|
|
||||||
validators=[django.core.validators.MinValueValidator(0),
|
|
||||||
django.core.validators.MaxValueValidator(100)],
|
|
||||||
verbose_name='markup percentage')),
|
|
||||||
('name', models.CharField(help_text='provide a name for this category', max_length=255,
|
|
||||||
verbose_name='category name')),
|
|
||||||
('name_en_GB', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
|
|
||||||
verbose_name='category name')),
|
|
||||||
('name_ar_AR', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
|
|
||||||
verbose_name='category name')),
|
|
||||||
('name_cs_CZ', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
|
|
||||||
verbose_name='category name')),
|
|
||||||
('name_da_DK', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
|
|
||||||
verbose_name='category name')),
|
|
||||||
('name_de_DE', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
|
|
||||||
verbose_name='category name')),
|
|
||||||
('name_en_US', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
|
|
||||||
verbose_name='category name')),
|
|
||||||
('name_es_ES', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
|
|
||||||
verbose_name='category name')),
|
|
||||||
('name_fr_FR', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
|
|
||||||
verbose_name='category name')),
|
|
||||||
('name_hi_IN', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
|
|
||||||
verbose_name='category name')),
|
|
||||||
('name_it_IT', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
|
|
||||||
verbose_name='category name')),
|
|
||||||
('name_ja_JP', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
|
|
||||||
verbose_name='category name')),
|
|
||||||
('name_kk_KZ', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
|
|
||||||
verbose_name='category name')),
|
|
||||||
('name_nl_NL', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
|
|
||||||
verbose_name='category name')),
|
|
||||||
('name_pl_PL', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
|
|
||||||
verbose_name='category name')),
|
|
||||||
('name_pt_BR', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
|
|
||||||
verbose_name='category name')),
|
|
||||||
('name_ro_RO', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
|
|
||||||
verbose_name='category name')),
|
|
||||||
('name_ru_RU', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
|
|
||||||
verbose_name='category name')),
|
|
||||||
('name_zh_hans',
|
|
||||||
models.CharField(help_text='provide a name for this category', max_length=255, null=True,
|
|
||||||
verbose_name='category name')),
|
|
||||||
('description',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
|
|
||||||
verbose_name='category description')),
|
|
||||||
('description_en_GB',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
|
|
||||||
verbose_name='category description')),
|
|
||||||
('description_ar_AR',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
|
|
||||||
verbose_name='category description')),
|
|
||||||
('description_cs_CZ',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
|
|
||||||
verbose_name='category description')),
|
|
||||||
('description_da_DK',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
|
|
||||||
verbose_name='category description')),
|
|
||||||
('description_de_DE',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
|
|
||||||
verbose_name='category description')),
|
|
||||||
('description_en_US',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
|
|
||||||
verbose_name='category description')),
|
|
||||||
('description_es_ES',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
|
|
||||||
verbose_name='category description')),
|
|
||||||
('description_fr_FR',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
|
|
||||||
verbose_name='category description')),
|
|
||||||
('description_hi_IN',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
|
|
||||||
verbose_name='category description')),
|
|
||||||
('description_it_IT',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
|
|
||||||
verbose_name='category description')),
|
|
||||||
('description_ja_JP',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
|
|
||||||
verbose_name='category description')),
|
|
||||||
('description_kk_KZ',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
|
|
||||||
verbose_name='category description')),
|
|
||||||
('description_nl_NL',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
|
|
||||||
verbose_name='category description')),
|
|
||||||
('description_pl_PL',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
|
|
||||||
verbose_name='category description')),
|
|
||||||
('description_pt_BR',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
|
|
||||||
verbose_name='category description')),
|
|
||||||
('description_ro_RO',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
|
|
||||||
verbose_name='category description')),
|
|
||||||
('description_ru_RU',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
|
|
||||||
verbose_name='category description')),
|
|
||||||
('description_zh_hans',
|
|
||||||
models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
|
|
||||||
verbose_name='category description')),
|
|
||||||
('lft', models.PositiveIntegerField(editable=False)),
|
|
||||||
('rght', models.PositiveIntegerField(editable=False)),
|
|
||||||
('tree_id', models.PositiveIntegerField(db_index=True, editable=False)),
|
|
||||||
('level', models.PositiveIntegerField(editable=False)),
|
|
||||||
('parent', mptt.fields.TreeForeignKey(blank=True,
|
|
||||||
help_text='parent of this category to form a hierarchical structure',
|
|
||||||
null=True, on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
related_name='children', to='core.category',
|
|
||||||
verbose_name='parent category')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'category',
|
|
||||||
'verbose_name_plural': 'categories',
|
|
||||||
'ordering': ['tree_id', 'lft'],
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Brand',
|
|
||||||
fields=[
|
|
||||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
|
|
||||||
help_text='unique id is used to surely identify any database object',
|
|
||||||
primary_key=True, serialize=False, verbose_name='unique id')),
|
|
||||||
('is_active', models.BooleanField(default=True,
|
|
||||||
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')),
|
|
||||||
('name', models.CharField(help_text='name of this brand', max_length=255, verbose_name='brand name')),
|
|
||||||
('category',
|
|
||||||
models.ForeignKey(blank=True, help_text='optional category that this brand is associated with',
|
|
||||||
null=True, on_delete=django.db.models.deletion.PROTECT, to='core.category',
|
|
||||||
verbose_name='associated category')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'brand',
|
|
||||||
'verbose_name_plural': 'brands',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='attribute',
|
|
||||||
name='categories',
|
|
||||||
field=models.ManyToManyField(help_text='category of this attribute', related_name='attributes',
|
|
||||||
to='core.category', verbose_name='categories'),
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Order',
|
|
||||||
fields=[
|
|
||||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
|
|
||||||
help_text='unique id is used to surely identify any database object',
|
|
||||||
primary_key=True, serialize=False, verbose_name='unique id')),
|
|
||||||
('is_active', models.BooleanField(default=True,
|
|
||||||
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')),
|
|
||||||
('status', models.CharField(
|
|
||||||
choices=[('PENDING', 'pending'), ('FAILED', 'failed'), ('PAYMENT', 'payment'),
|
|
||||||
('CREATED', 'created'), ('DELIVERING', 'delivering'), ('FINISHED', 'finished')],
|
|
||||||
default='PENDING', help_text='current status of the order in its lifecycle', max_length=64,
|
|
||||||
verbose_name='order status')),
|
|
||||||
('notifications',
|
|
||||||
models.JSONField(blank=True, help_text='json structure of notifications to display to users',
|
|
||||||
null=True, verbose_name='notifications')),
|
|
||||||
('attributes',
|
|
||||||
models.JSONField(blank=True, help_text='json representation of order attributes for this order',
|
|
||||||
null=True, verbose_name='attributes')),
|
|
||||||
('buy_time',
|
|
||||||
models.DateTimeField(blank=True, default=None, help_text='the timestamp when the order was finalized',
|
|
||||||
null=True, verbose_name='buy time')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'order',
|
|
||||||
'verbose_name_plural': 'orders',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
@ -1,107 +0,0 @@
|
||||||
# Generated by Django 5.1.5 on 2025-03-10 11:38
|
|
||||||
|
|
||||||
import django.contrib.postgres.indexes
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
initial = True
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('core', '0001_initial'),
|
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='order',
|
|
||||||
name='user',
|
|
||||||
field=models.ForeignKey(help_text='the user who placed the order', on_delete=django.db.models.deletion.CASCADE, related_name='orders', to=settings.AUTH_USER_MODEL, verbose_name='user'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='orderproduct',
|
|
||||||
name='order',
|
|
||||||
field=models.ForeignKey(help_text='reference to the parent order that contains this product', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='order_products', to='core.order', verbose_name='parent order'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='feedback',
|
|
||||||
name='order_product',
|
|
||||||
field=models.OneToOneField(help_text='references the specific product in an order that this feedback is about', on_delete=django.db.models.deletion.CASCADE, to='core.orderproduct', verbose_name='related order product'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='product',
|
|
||||||
name='brand',
|
|
||||||
field=models.ForeignKey(blank=True, help_text='optionally associate this product with a brand', null=True, on_delete=django.db.models.deletion.CASCADE, to='core.brand', verbose_name='brand'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='product',
|
|
||||||
name='category',
|
|
||||||
field=models.ForeignKey(help_text='category this product belongs to', on_delete=django.db.models.deletion.CASCADE, to='core.category', verbose_name='category'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='orderproduct',
|
|
||||||
name='product',
|
|
||||||
field=models.ForeignKey(blank=True, help_text='the specific product associated with this order line', null=True, on_delete=django.db.models.deletion.PROTECT, to='core.product', verbose_name='associated product'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='attributevalue',
|
|
||||||
name='product',
|
|
||||||
field=models.ForeignKey(help_text="the specific product associated with this attribute's value", null=True, on_delete=django.db.models.deletion.CASCADE, related_name='attributes', to='core.product', verbose_name='associated product'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='productimage',
|
|
||||||
name='product',
|
|
||||||
field=models.ForeignKey(help_text='the product that this image represents', on_delete=django.db.models.deletion.CASCADE, related_name='images', to='core.product', verbose_name='associated product'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='product',
|
|
||||||
name='tags',
|
|
||||||
field=models.ManyToManyField(blank=True, help_text='tags that help describe or group this product', to='core.producttag', verbose_name='product tags'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='promocode',
|
|
||||||
name='user',
|
|
||||||
field=models.ForeignKey(blank=True, help_text='user assigned to this promocode if applicable', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='promocodes', to=settings.AUTH_USER_MODEL, verbose_name='assigned user'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='order',
|
|
||||||
name='promo_code',
|
|
||||||
field=models.ForeignKey(blank=True, help_text='optional promo code applied to this order', null=True, on_delete=django.db.models.deletion.PROTECT, to='core.promocode', verbose_name='applied promo code'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='promotion',
|
|
||||||
name='products',
|
|
||||||
field=models.ManyToManyField(blank=True, help_text='select which products are included in this promotion', to='core.product', verbose_name='included products'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='stock',
|
|
||||||
name='product',
|
|
||||||
field=models.ForeignKey(blank=True, help_text='the product associated with this stock entry', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='stocks', to='core.product', verbose_name='associated product'),
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='vendor',
|
|
||||||
index=django.contrib.postgres.indexes.GinIndex(fields=['authentication'], name='core_vendor_authent_80dc1f_gin'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='stock',
|
|
||||||
name='vendor',
|
|
||||||
field=models.ForeignKey(help_text='the vendor supplying this product stock', on_delete=django.db.models.deletion.CASCADE, to='core.vendor', verbose_name='associated vendor'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='wishlist',
|
|
||||||
name='products',
|
|
||||||
field=models.ManyToManyField(blank=True, help_text='products that the user has marked as wanted', to='core.product', verbose_name='wishlisted products'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='wishlist',
|
|
||||||
name='user',
|
|
||||||
field=models.OneToOneField(blank=True, help_text='user who owns this wishlist', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='user_related_wishlist', to=settings.AUTH_USER_MODEL, verbose_name='wishlist owner'),
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='orderproduct',
|
|
||||||
index=django.contrib.postgres.indexes.GinIndex(fields=['notifications', 'attributes'], name='core_orderp_notific_cd27e9_gin'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
@ -1,498 +0,0 @@
|
||||||
# Generated by Django 5.1.5 on 2025-03-10 12:09
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('core', '0002_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attribute',
|
|
||||||
name='name',
|
|
||||||
field=models.CharField(help_text='name of this attribute', max_length=255, unique=True, verbose_name="attribute's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attribute',
|
|
||||||
name='name_ar_AR',
|
|
||||||
field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attribute',
|
|
||||||
name='name_cs_CZ',
|
|
||||||
field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attribute',
|
|
||||||
name='name_da_DK',
|
|
||||||
field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attribute',
|
|
||||||
name='name_de_DE',
|
|
||||||
field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attribute',
|
|
||||||
name='name_en_GB',
|
|
||||||
field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attribute',
|
|
||||||
name='name_en_US',
|
|
||||||
field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attribute',
|
|
||||||
name='name_es_ES',
|
|
||||||
field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attribute',
|
|
||||||
name='name_fr_FR',
|
|
||||||
field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attribute',
|
|
||||||
name='name_hi_IN',
|
|
||||||
field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attribute',
|
|
||||||
name='name_it_IT',
|
|
||||||
field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attribute',
|
|
||||||
name='name_ja_JP',
|
|
||||||
field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attribute',
|
|
||||||
name='name_kk_KZ',
|
|
||||||
field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attribute',
|
|
||||||
name='name_nl_NL',
|
|
||||||
field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attribute',
|
|
||||||
name='name_pl_PL',
|
|
||||||
field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attribute',
|
|
||||||
name='name_pt_BR',
|
|
||||||
field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attribute',
|
|
||||||
name='name_ro_RO',
|
|
||||||
field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attribute',
|
|
||||||
name='name_ru_RU',
|
|
||||||
field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attribute',
|
|
||||||
name='name_zh_hans',
|
|
||||||
field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attributegroup',
|
|
||||||
name='name',
|
|
||||||
field=models.CharField(help_text="attribute group's name", max_length=255, unique=True, verbose_name="attribute group's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attributegroup',
|
|
||||||
name='name_ar_AR',
|
|
||||||
field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attributegroup',
|
|
||||||
name='name_cs_CZ',
|
|
||||||
field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attributegroup',
|
|
||||||
name='name_da_DK',
|
|
||||||
field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attributegroup',
|
|
||||||
name='name_de_DE',
|
|
||||||
field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attributegroup',
|
|
||||||
name='name_en_GB',
|
|
||||||
field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attributegroup',
|
|
||||||
name='name_en_US',
|
|
||||||
field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attributegroup',
|
|
||||||
name='name_es_ES',
|
|
||||||
field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attributegroup',
|
|
||||||
name='name_fr_FR',
|
|
||||||
field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attributegroup',
|
|
||||||
name='name_hi_IN',
|
|
||||||
field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attributegroup',
|
|
||||||
name='name_it_IT',
|
|
||||||
field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attributegroup',
|
|
||||||
name='name_ja_JP',
|
|
||||||
field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attributegroup',
|
|
||||||
name='name_kk_KZ',
|
|
||||||
field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attributegroup',
|
|
||||||
name='name_nl_NL',
|
|
||||||
field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attributegroup',
|
|
||||||
name='name_pl_PL',
|
|
||||||
field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attributegroup',
|
|
||||||
name='name_pt_BR',
|
|
||||||
field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attributegroup',
|
|
||||||
name='name_ro_RO',
|
|
||||||
field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attributegroup',
|
|
||||||
name='name_ru_RU',
|
|
||||||
field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='attributegroup',
|
|
||||||
name='name_zh_hans',
|
|
||||||
field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='brand',
|
|
||||||
name='name',
|
|
||||||
field=models.CharField(help_text='name of this brand', max_length=255, unique=True, verbose_name='brand name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='category',
|
|
||||||
name='name',
|
|
||||||
field=models.CharField(help_text='provide a name for this category', max_length=255, unique=True, verbose_name='category name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='category',
|
|
||||||
name='name_ar_AR',
|
|
||||||
field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='category',
|
|
||||||
name='name_cs_CZ',
|
|
||||||
field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='category',
|
|
||||||
name='name_da_DK',
|
|
||||||
field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='category',
|
|
||||||
name='name_de_DE',
|
|
||||||
field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='category',
|
|
||||||
name='name_en_GB',
|
|
||||||
field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='category',
|
|
||||||
name='name_en_US',
|
|
||||||
field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='category',
|
|
||||||
name='name_es_ES',
|
|
||||||
field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='category',
|
|
||||||
name='name_fr_FR',
|
|
||||||
field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='category',
|
|
||||||
name='name_hi_IN',
|
|
||||||
field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='category',
|
|
||||||
name='name_it_IT',
|
|
||||||
field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='category',
|
|
||||||
name='name_ja_JP',
|
|
||||||
field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='category',
|
|
||||||
name='name_kk_KZ',
|
|
||||||
field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='category',
|
|
||||||
name='name_nl_NL',
|
|
||||||
field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='category',
|
|
||||||
name='name_pl_PL',
|
|
||||||
field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='category',
|
|
||||||
name='name_pt_BR',
|
|
||||||
field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='category',
|
|
||||||
name='name_ro_RO',
|
|
||||||
field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='category',
|
|
||||||
name='name_ru_RU',
|
|
||||||
field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='category',
|
|
||||||
name='name_zh_hans',
|
|
||||||
field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, unique=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_ar_AR',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_cs_CZ',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_da_DK',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_de_DE',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_en_GB',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_en_US',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_es_ES',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_fr_FR',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_hi_IN',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_it_IT',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_ja_JP',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_kk_KZ',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_nl_NL',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_pl_PL',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_pt_BR',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_ro_RO',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_ru_RU',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_zh_hans',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='producttag',
|
|
||||||
name='name',
|
|
||||||
field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, unique=True, verbose_name='tag display name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='producttag',
|
|
||||||
name='name_ar_AR',
|
|
||||||
field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='producttag',
|
|
||||||
name='name_cs_CZ',
|
|
||||||
field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='producttag',
|
|
||||||
name='name_da_DK',
|
|
||||||
field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='producttag',
|
|
||||||
name='name_de_DE',
|
|
||||||
field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='producttag',
|
|
||||||
name='name_en_GB',
|
|
||||||
field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='producttag',
|
|
||||||
name='name_en_US',
|
|
||||||
field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='producttag',
|
|
||||||
name='name_es_ES',
|
|
||||||
field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='producttag',
|
|
||||||
name='name_fr_FR',
|
|
||||||
field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='producttag',
|
|
||||||
name='name_hi_IN',
|
|
||||||
field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='producttag',
|
|
||||||
name='name_it_IT',
|
|
||||||
field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='producttag',
|
|
||||||
name='name_ja_JP',
|
|
||||||
field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='producttag',
|
|
||||||
name='name_kk_KZ',
|
|
||||||
field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='producttag',
|
|
||||||
name='name_nl_NL',
|
|
||||||
field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='producttag',
|
|
||||||
name='name_pl_PL',
|
|
||||||
field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='producttag',
|
|
||||||
name='name_pt_BR',
|
|
||||||
field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='producttag',
|
|
||||||
name='name_ro_RO',
|
|
||||||
field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='producttag',
|
|
||||||
name='name_ru_RU',
|
|
||||||
field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='producttag',
|
|
||||||
name='name_zh_hans',
|
|
||||||
field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='vendor',
|
|
||||||
name='name',
|
|
||||||
field=models.CharField(help_text='name of this vendor', max_length=255, unique=True, verbose_name='vendor name'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
@ -1,108 +0,0 @@
|
||||||
# Generated by Django 5.1.5 on 2025-03-10 20:13
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('core', '0003_alter_attribute_name_alter_attribute_name_ar_ar_and_more'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_ar_AR',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_cs_CZ',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_da_DK',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_de_DE',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_en_GB',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_en_US',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_es_ES',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_fr_FR',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_hi_IN',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_it_IT',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_ja_JP',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_kk_KZ',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_nl_NL',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_pl_PL',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_pt_BR',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_ro_RO',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_ru_RU',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='name_zh_hans',
|
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
# Generated by Django 5.1.5 on 2025-03-16 12:53
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('core', '0004_alter_product_name_alter_product_name_ar_ar_and_more'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='brand',
|
|
||||||
name='category',
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='brand',
|
|
||||||
name='categories',
|
|
||||||
field=models.ManyToManyField(blank=True, help_text='optional categories that this brand is associated with', to='core.category', verbose_name='associated categories'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
# Generated by Django 5.1.5 on 2025-03-20 15:27
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('core', '0005_remove_brand_category_brand_categories'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='order',
|
|
||||||
name='status',
|
|
||||||
field=models.CharField(choices=[('PENDING', 'pending'), ('FAILED', 'failed'), ('PAYMENT', 'payment'), ('CREATED', 'created'), ('DELIVERING', 'delivering'), ('FINISHED', 'finished'), ('MOMENTAL', 'momental')], default='PENDING', help_text='current status of the order in its lifecycle', max_length=64, verbose_name='order status'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue