2025.4 BETA
This commit is contained in:
parent
c09c0d8753
commit
3fbe6883c7
189 changed files with 3768 additions and 3905 deletions
|
|
@ -75,7 +75,7 @@ static/
|
||||||
media/
|
media/
|
||||||
!engine/core/static
|
!engine/core/static
|
||||||
!engine/blog/static
|
!engine/blog/static
|
||||||
!engine/authv/static
|
!engine/vibes_auth/static
|
||||||
!engine/payments/static
|
!engine/payments/static
|
||||||
|
|
||||||
# Environment file
|
# Environment file
|
||||||
|
|
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -111,7 +111,7 @@ media/
|
||||||
# Allow checked-in static from apps
|
# Allow checked-in static from apps
|
||||||
!engine/core/static/
|
!engine/core/static/
|
||||||
!engine/payments/static/
|
!engine/payments/static/
|
||||||
!engine/authv/static/
|
!engine/vibes_auth/static/
|
||||||
!engine/blog/static/
|
!engine/blog/static/
|
||||||
|
|
||||||
# Webassets
|
# Webassets
|
||||||
|
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from django.contrib import admin
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
|
|
||||||
from engine.authv.messaging.models import ChatMessage, ChatThread, ThreadStatus
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyUnusedLocal
|
|
||||||
@admin.register(ChatThread)
|
|
||||||
class ChatThreadAdmin(admin.ModelAdmin):
|
|
||||||
list_display = (
|
|
||||||
"uuid",
|
|
||||||
"user",
|
|
||||||
"email",
|
|
||||||
"assigned_to",
|
|
||||||
"status",
|
|
||||||
"last_message_at",
|
|
||||||
"is_active",
|
|
||||||
"created",
|
|
||||||
"modified",
|
|
||||||
)
|
|
||||||
list_filter = (
|
|
||||||
"status",
|
|
||||||
"is_active",
|
|
||||||
("assigned_to", admin.EmptyFieldListFilter),
|
|
||||||
)
|
|
||||||
search_fields = ("uuid", "email", "user__email", "user__username")
|
|
||||||
autocomplete_fields = ("user", "assigned_to")
|
|
||||||
actions = (
|
|
||||||
"close_threads",
|
|
||||||
"open_threads",
|
|
||||||
"delete_selected",
|
|
||||||
)
|
|
||||||
readonly_fields = ("created", "modified")
|
|
||||||
|
|
||||||
@admin.action(description=_("Close selected threads"))
|
|
||||||
def close_threads(self, request, queryset): # type: ignore[no-untyped-def]
|
|
||||||
queryset.update(status=ThreadStatus.CLOSED)
|
|
||||||
|
|
||||||
@admin.action(description=_("Open selected threads"))
|
|
||||||
def open_threads(self, request, queryset): # type: ignore[no-untyped-def]
|
|
||||||
queryset.update(status=ThreadStatus.OPEN)
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(ChatMessage)
|
|
||||||
class ChatMessageAdmin(admin.ModelAdmin):
|
|
||||||
list_display = ("uuid", "thread", "sender_type", "sender_user", "sent_at")
|
|
||||||
list_filter = ("sender_type",)
|
|
||||||
search_fields = ("uuid", "thread__uuid", "sender_user__email")
|
|
||||||
autocomplete_fields = ("thread", "sender_user")
|
|
||||||
readonly_fields = ("created", "modified")
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.1.8 on 2025-04-28 11:56
|
|
||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.1.8 on 2025-04-28 12:07
|
|
||||||
|
|
||||||
import django_extensions.db.fields
|
import django_extensions.db.fields
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.1.8 on 2025-04-28 12:39
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2 on 2025-06-29 13:09
|
|
||||||
|
|
||||||
import markdown_field.fields
|
import markdown_field.fields
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2 on 2025-09-19 11:59
|
|
||||||
|
|
||||||
import markdown_field.fields
|
import markdown_field.fields
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2 on 2025-10-07 12:46
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2 on 2025-10-21 09:24
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import logging
|
import logging
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from constance import config
|
from constance import config
|
||||||
|
|
@ -165,7 +164,7 @@ class AmoCRM:
|
||||||
def process_order_changes(self, order: Order) -> str:
|
def process_order_changes(self, order: Order) -> str:
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
try:
|
try:
|
||||||
link: Optional[OrderCrmLink] = OrderCrmLink.objects.get(order=order)
|
link: OrderCrmLink | None = OrderCrmLink.objects.get(order=order)
|
||||||
except OrderCrmLink.MultipleObjectsReturned:
|
except OrderCrmLink.MultipleObjectsReturned:
|
||||||
link = OrderCrmLink.objects.filter(order=order).first()
|
link = OrderCrmLink.objects.filter(order=order).first()
|
||||||
except OrderCrmLink.DoesNotExist:
|
except OrderCrmLink.DoesNotExist:
|
||||||
|
|
|
||||||
|
|
@ -86,8 +86,8 @@ from engine.core.utils import get_project_parameters
|
||||||
from engine.core.utils.languages import get_flag_by_language
|
from engine.core.utils.languages import get_flag_by_language
|
||||||
from engine.core.utils.messages import permission_denied_message
|
from engine.core.utils.messages import permission_denied_message
|
||||||
from engine.payments.graphene.mutations import Deposit
|
from engine.payments.graphene.mutations import Deposit
|
||||||
from engine.authv.filters import UserFilter
|
from engine.vibes_auth.filters import UserFilter
|
||||||
from engine.authv.graphene.mutations import (
|
from engine.vibes_auth.graphene.mutations import (
|
||||||
ActivateUser,
|
ActivateUser,
|
||||||
ConfirmResetPassword,
|
ConfirmResetPassword,
|
||||||
CreateUser,
|
CreateUser,
|
||||||
|
|
@ -99,8 +99,8 @@ from engine.authv.graphene.mutations import (
|
||||||
UploadAvatar,
|
UploadAvatar,
|
||||||
VerifyJSONWebToken,
|
VerifyJSONWebToken,
|
||||||
)
|
)
|
||||||
from engine.authv.graphene.object_types import UserType
|
from engine.vibes_auth.graphene.object_types import UserType
|
||||||
from engine.authv.models import User
|
from engine.vibes_auth.models import User
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -207,7 +207,7 @@ class Query(ObjectType):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def resolve_users(_parent, info, **_kwargs):
|
def resolve_users(_parent, info, **_kwargs):
|
||||||
if info.context.user.has_perm("authv.view_user"):
|
if info.context.user.has_perm("vibes_auth.view_user"):
|
||||||
return User.objects.all()
|
return User.objects.all()
|
||||||
users = User.objects.filter(uuid=info.context.user.pk)
|
users = User.objects.filter(uuid=info.context.user.pk)
|
||||||
return users if users.exists() else User.objects.none()
|
return users if users.exists() else User.objects.none()
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -662,7 +662,7 @@ msgstr ""
|
||||||
"deepl_translate -l en-gb -l ar-ar -l cs-cz -l da-dk -l de-de-de -l en-us -l "
|
"deepl_translate -l en-gb -l ar-ar -l cs-cz -l da-dk -l de-de-de -l en-us -l "
|
||||||
"es-es -l fr-fr -l hi-in -l it-it -l ja-jp -l kk-kz -l nl-nl -l nl-nl -l pl-"
|
"es-es -l fr-fr -l hi-in -l it-it -l ja-jp -l kk-kz -l nl-nl -l nl-nl -l pl-"
|
||||||
"pl -l pt-br -l ro-ro -l ru-ru -l zh-hans -l zh-ans -a core -a geo -a geo -a "
|
"pl -l pt-br -l ro-ro -l ru-ru -l zh-hans -l zh-ans -a core -a geo -a geo -a "
|
||||||
"payments -a authv -a blog"
|
"payments -a vibes_auth -a blog"
|
||||||
|
|
||||||
#: engine/core/docs/drf/viewsets.py:592
|
#: engine/core/docs/drf/viewsets.py:592
|
||||||
msgid "limit the results amount, 1 < limit < 10, default: 5"
|
msgid "limit the results amount, 1 < limit < 10, default: 5"
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -711,7 +711,7 @@ msgstr ""
|
||||||
"docker compose exec app poetry run python manage.py deepl_translate -l en-gb"
|
"docker compose exec app poetry run python manage.py deepl_translate -l en-gb"
|
||||||
" -l ar-ar -l cs-cz -l da-dk -l de-de -l en-us -l es-es -l fr-fr -l hi-in -l "
|
" -l ar-ar -l cs-cz -l da-dk -l de-de -l en-us -l es-es -l fr-fr -l hi-in -l "
|
||||||
"it-it -l ja-jp -l kk-kz -l nl-nl -l pl -l pt-br -l ro-ro -l ru-ru -l zh-hans"
|
"it-it -l ja-jp -l kk-kz -l nl-nl -l pl -l pt-br -l ro-ro -l ru-ru -l zh-hans"
|
||||||
" -a core -a geo -a payments -a authv -a blog"
|
" -a core -a geo -a payments -a vibes_auth -a blog"
|
||||||
|
|
||||||
#: engine/core/docs/drf/viewsets.py:592
|
#: engine/core/docs/drf/viewsets.py:592
|
||||||
msgid "limit the results amount, 1 < limit < 10, default: 5"
|
msgid "limit the results amount, 1 < limit < 10, default: 5"
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -647,7 +647,7 @@ msgstr ""
|
||||||
"docker compose exec app poetry run python manage.py deepl_translate -l en-gb"
|
"docker compose exec app poetry run python manage.py deepl_translate -l en-gb"
|
||||||
" -l ar-ar -l cs-cz -l da-dk -l de-de -l en-us -l es-es -l fr-fr -l hi-in -l "
|
" -l ar-ar -l cs-cz -l da-dk -l de-de -l en-us -l es-es -l fr-fr -l hi-in -l "
|
||||||
"it-it -l ja-jp -l kk-kz -l n-nl -l pl-pl -l pt-br -l ro-ro -l ru-ru -l zh-"
|
"it-it -l ja-jp -l kk-kz -l n-nl -l pl-pl -l pt-br -l ro-ro -l ru-ru -l zh-"
|
||||||
"hans -a core -a geo -a payments -a authv -a blog"
|
"hans -a core -a geo -a payments -a vibes_auth -a blog"
|
||||||
|
|
||||||
#: engine/core/docs/drf/viewsets.py:592
|
#: engine/core/docs/drf/viewsets.py:592
|
||||||
msgid "limit the results amount, 1 < limit < 10, default: 5"
|
msgid "limit the results amount, 1 < limit < 10, default: 5"
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -700,7 +700,7 @@ msgstr ""
|
||||||
"docker compose exec app poetry run python manage.py deepl_translate -l en-gb"
|
"docker compose exec app poetry run python manage.py deepl_translate -l en-gb"
|
||||||
" -l ar-ar -l cs-cz -l da-dk -l de-de -l en-us -l es-es -l fr-fr -l hi-in -l "
|
" -l ar-ar -l cs-cz -l da-dk -l de-de -l en-us -l es-es -l fr-fr -l hi-in -l "
|
||||||
"it-it -l ja-jp -l kk-kz -l nl-nl -l pl-pl -l pt-br -l ro-ro -l ru-ru -l zh-"
|
"it-it -l ja-jp -l kk-kz -l nl-nl -l pl-pl -l pt-br -l ro-ro -l ru-ru -l zh-"
|
||||||
"hans -a core -a geo -a plăți -a authv -a blog"
|
"hans -a core -a geo -a plăți -a vibes_auth -a blog"
|
||||||
|
|
||||||
#: engine/core/docs/drf/viewsets.py:592
|
#: engine/core/docs/drf/viewsets.py:592
|
||||||
msgid "limit the results amount, 1 < limit < 10, default: 5"
|
msgid "limit the results amount, 1 < limit < 10, default: 5"
|
||||||
|
|
|
||||||
|
|
@ -39,4 +39,4 @@ DEEPL_TARGET_LANGUAGES_MAPPING = {
|
||||||
"zh-hans": "ZH-HANS",
|
"zh-hans": "ZH-HANS",
|
||||||
}
|
}
|
||||||
|
|
||||||
TRANSLATABLE_APPS = ["core", "authv", "blog", "payments", "root"]
|
TRANSLATABLE_APPS = ["core", "vibes_auth", "blog", "payments", "root"]
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ from typing import Any
|
||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import BaseCommand
|
||||||
|
|
||||||
from engine.core.models import Vendor
|
from engine.core.models import Vendor
|
||||||
from engine.authv.models import Group
|
from engine.vibes_auth.models import Group
|
||||||
from django.contrib.auth.models import Permission
|
from django.contrib.auth.models import Permission
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.1.5 on 2025-03-10 11:38
|
|
||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
import django.core.validators
|
import django.core.validators
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.1.5 on 2025-03-10 11:38
|
|
||||||
|
|
||||||
import django.contrib.postgres.indexes
|
import django.contrib.postgres.indexes
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.1.5 on 2025-03-10 12:09
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.1.5 on 2025-03-10 20:13
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.1.5 on 2025-03-16 12:53
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.1.5 on 2025-03-20 15:27
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.1.5 on 2025-03-24 14:04
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
import engine.core.validators
|
import engine.core.validators
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.1.5 on 2025-04-10 15:55
|
|
||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.1.5 on 2025-04-15 09:15
|
|
||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.1.8 on 2025-04-17 14:22
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.1.8 on 2025-04-18 11:34
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
import engine.core.validators
|
import engine.core.validators
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.1.8 on 2025-04-28 11:56
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.1.8 on 2025-04-30 13:29
|
|
||||||
|
|
||||||
import django_extensions.db.fields
|
import django_extensions.db.fields
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.1.8 on 2025-04-30 13:42
|
|
||||||
|
|
||||||
import django_extensions.db.fields
|
import django_extensions.db.fields
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.1.8 on 2025-04-30 14:03
|
|
||||||
|
|
||||||
import django_extensions.db.fields
|
import django_extensions.db.fields
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.1.8 on 2025-05-05 12:56
|
|
||||||
|
|
||||||
import django_extensions.db.fields
|
import django_extensions.db.fields
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.1.8 on 2025-05-06 13:58
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
import engine.core.utils
|
import engine.core.utils
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2 on 2025-05-20 04:57
|
|
||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
import django.contrib.gis.db.models.fields
|
import django.contrib.gis.db.models.fields
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2 on 2025-05-20 19:06
|
|
||||||
|
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2 on 2025-05-21 09:35
|
|
||||||
|
|
||||||
import django_extensions.db.fields
|
import django_extensions.db.fields
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2 on 2025-05-28 19:06
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2 on 2025-06-10 02:42
|
|
||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
import django_extensions.db.fields
|
import django_extensions.db.fields
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2 on 2025-06-17 08:25
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2 on 2025-06-18 19:21
|
|
||||||
|
|
||||||
import django_extensions.db.fields
|
import django_extensions.db.fields
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2 on 2025-06-20 02:25
|
|
||||||
|
|
||||||
import django_extensions.db.fields
|
import django_extensions.db.fields
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2 on 2025-06-21 16:04
|
|
||||||
|
|
||||||
import django_extensions.db.fields
|
import django_extensions.db.fields
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2 on 2025-06-21 16:29
|
|
||||||
|
|
||||||
import django_extensions.db.fields
|
import django_extensions.db.fields
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2 on 2025-06-21 16:34
|
|
||||||
|
|
||||||
import django_extensions.db.fields
|
import django_extensions.db.fields
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2 on 2025-06-21 16:40
|
|
||||||
|
|
||||||
import django_extensions.db.fields
|
import django_extensions.db.fields
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2 on 2025-06-21 17:14
|
|
||||||
|
|
||||||
import django_extensions.db.fields
|
import django_extensions.db.fields
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2 on 2025-06-21 17:38
|
|
||||||
|
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
|
|
||||||
import engine.core.utils.db
|
import engine.core.utils.db
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2 on 2025-06-21 21:40
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2 on 2025-06-29 13:09
|
|
||||||
|
|
||||||
import engine.core.utils.db
|
import engine.core.utils.db
|
||||||
import django_extensions.db.fields
|
import django_extensions.db.fields
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2 on 2025-07-28 08:55
|
|
||||||
|
|
||||||
import engine.core.utils
|
import engine.core.utils
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2 on 2025-09-01 17:33
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2 on 2025-09-01 17:36
|
|
||||||
|
|
||||||
import engine.core.utils
|
import engine.core.utils
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2 on 2025-09-06 22:05
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
import django_extensions.db.fields
|
import django_extensions.db.fields
|
||||||
import django_prometheus.models
|
import django_prometheus.models
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2 on 2025-09-06 22:16
|
|
||||||
|
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2 on 2025-09-19 11:59
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2 on 2025-09-22 11:10
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2 on 2025-10-13 12:15
|
|
||||||
|
|
||||||
import engine.core.utils
|
import engine.core.utils
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2 on 2025-10-17 11:27
|
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2 on 2025-10-18 19:41
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2 on 2025-10-18 21:16
|
|
||||||
|
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2 on 2025-10-21 09:24
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2.7 on 2025-10-24 23:17
|
|
||||||
|
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2.7 on 2025-10-26 14:10
|
|
||||||
|
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2.7 on 2025-10-26 16:59
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2.7 on 2025-11-01 23:45
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import datetime
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
from typing import Any, Optional, Self, Iterable
|
from typing import Any, Iterable, Self
|
||||||
|
|
||||||
from constance import config
|
from constance import config
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
@ -36,8 +36,8 @@ from django.db.models import (
|
||||||
TextField,
|
TextField,
|
||||||
URLField,
|
URLField,
|
||||||
)
|
)
|
||||||
from django.db.models.indexes import Index
|
|
||||||
from django.db.models.functions import Length
|
from django.db.models.functions import Length
|
||||||
|
from django.db.models.indexes import Index
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.encoding import force_bytes
|
from django.utils.encoding import force_bytes
|
||||||
|
|
@ -64,8 +64,8 @@ from engine.core.utils import (
|
||||||
from engine.core.utils.db import TweakedAutoSlugField, unicode_slugify_function
|
from engine.core.utils.db import TweakedAutoSlugField, unicode_slugify_function
|
||||||
from engine.core.utils.lists import FAILED_STATUSES
|
from engine.core.utils.lists import FAILED_STATUSES
|
||||||
from engine.core.validators import validate_category_image_dimensions
|
from engine.core.validators import validate_category_image_dimensions
|
||||||
from evibes.utils.misc import create_object
|
|
||||||
from engine.payments.models import Transaction
|
from engine.payments.models import Transaction
|
||||||
|
from evibes.utils.misc import create_object
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -369,10 +369,10 @@ class Category(ExportModelOperationsMixin("category"), NiceModel, MPTTModel): #
|
||||||
.distinct()
|
.distinct()
|
||||||
)
|
)
|
||||||
|
|
||||||
per_cat: dict[int, dict[int, dict[str, Any]]] = {}
|
per_cat: dict[Any, Any] = {}
|
||||||
for cat_id, attr_id, attr_name, value_type, value in rows:
|
for cat_id, attr_id, attr_name, value_type, value in rows:
|
||||||
cat_bucket = per_cat.get(cat_id)
|
cat_bucket = per_cat.get(cat_id, "")
|
||||||
if cat_bucket is None:
|
if not cat_bucket:
|
||||||
cat_bucket = {}
|
cat_bucket = {}
|
||||||
per_cat[cat_id] = cat_bucket
|
per_cat[cat_id] = cat_bucket
|
||||||
bucket = cat_bucket.get(attr_id)
|
bucket = cat_bucket.get(attr_id)
|
||||||
|
|
@ -405,7 +405,7 @@ class Category(ExportModelOperationsMixin("category"), NiceModel, MPTTModel): #
|
||||||
.distinct()
|
.distinct()
|
||||||
)
|
)
|
||||||
|
|
||||||
by_attr: dict[int, dict] = {}
|
by_attr: dict[Any, Any] = {}
|
||||||
for attr_id, attr_name, value_type, value in rows:
|
for attr_id, attr_name, value_type, value in rows:
|
||||||
bucket = by_attr.get(attr_id)
|
bucket = by_attr.get(attr_id)
|
||||||
if bucket is None:
|
if bucket is None:
|
||||||
|
|
@ -913,7 +913,7 @@ class Wishlist(ExportModelOperationsMixin("wishlist"), NiceModel): # type: igno
|
||||||
verbose_name=_("wishlisted products"),
|
verbose_name=_("wishlisted products"),
|
||||||
)
|
)
|
||||||
user = OneToOneField(
|
user = OneToOneField(
|
||||||
"authv.User",
|
"vibes_auth.User",
|
||||||
on_delete=CASCADE,
|
on_delete=CASCADE,
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
|
|
@ -1107,7 +1107,7 @@ class PromoCode(ExportModelOperationsMixin("promocode"), NiceModel): # type: ig
|
||||||
verbose_name=_("usage timestamp"),
|
verbose_name=_("usage timestamp"),
|
||||||
)
|
)
|
||||||
user = ForeignKey(
|
user = ForeignKey(
|
||||||
"authv.User",
|
"vibes_auth.User",
|
||||||
on_delete=CASCADE,
|
on_delete=CASCADE,
|
||||||
help_text=_("user assigned to this promocode if applicable"),
|
help_text=_("user assigned to this promocode if applicable"),
|
||||||
verbose_name=_("assigned user"),
|
verbose_name=_("assigned user"),
|
||||||
|
|
@ -1236,7 +1236,7 @@ class Order(ExportModelOperationsMixin("order"), NiceModel): # type: ignore [mi
|
||||||
verbose_name=_("attributes"),
|
verbose_name=_("attributes"),
|
||||||
)
|
)
|
||||||
user = ForeignKey(
|
user = ForeignKey(
|
||||||
"authv.User",
|
"vibes_auth.User",
|
||||||
on_delete=CASCADE,
|
on_delete=CASCADE,
|
||||||
help_text=_("the user who placed the order"),
|
help_text=_("the user who placed the order"),
|
||||||
verbose_name=_("user"),
|
verbose_name=_("user"),
|
||||||
|
|
@ -1680,6 +1680,49 @@ class Order(ExportModelOperationsMixin("order"), NiceModel): # type: ignore [mi
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class Feedback(ExportModelOperationsMixin("feedback"), NiceModel): # type: ignore [misc]
|
||||||
|
__doc__ = _( # type: ignore
|
||||||
|
"Manages user feedback for products. "
|
||||||
|
"This class is designed to capture and store user feedback for specific products "
|
||||||
|
"that they have purchased. It contains attributes to store user comments, "
|
||||||
|
"a reference to the related product in the order, and a user-assigned rating. The "
|
||||||
|
"class uses database fields to effectively model and manage feedback data."
|
||||||
|
)
|
||||||
|
|
||||||
|
is_publicly_visible = True
|
||||||
|
|
||||||
|
comment = TextField(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
help_text=_("user-provided comments about their experience with the product"),
|
||||||
|
verbose_name=_("feedback comments"),
|
||||||
|
)
|
||||||
|
order_product = OneToOneField(
|
||||||
|
"core.OrderProduct",
|
||||||
|
on_delete=CASCADE,
|
||||||
|
blank=False,
|
||||||
|
null=False,
|
||||||
|
help_text=_("references the specific product in an order that this feedback is about"),
|
||||||
|
verbose_name=_("related order product"),
|
||||||
|
)
|
||||||
|
rating = FloatField(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
help_text=_("user-assigned rating for the product"),
|
||||||
|
verbose_name=_("product rating"),
|
||||||
|
validators=[MinValueValidator(0), MaxValueValidator(10)],
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
if self.order_product and self.order_product.order and self.order_product.order.user:
|
||||||
|
return f"{self.rating} by {self.order_product.order.user.email}"
|
||||||
|
return f"{self.rating} | {self.uuid}"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("feedback")
|
||||||
|
verbose_name_plural = _("feedbacks")
|
||||||
|
|
||||||
|
|
||||||
class OrderProduct(ExportModelOperationsMixin("order_product"), NiceModel): # type: ignore [misc]
|
class OrderProduct(ExportModelOperationsMixin("order_product"), NiceModel): # type: ignore [misc]
|
||||||
__doc__ = _( # type: ignore
|
__doc__ = _( # type: ignore
|
||||||
"Represents products associated with orders and their attributes. "
|
"Represents products associated with orders and their attributes. "
|
||||||
|
|
@ -1810,7 +1853,7 @@ class OrderProduct(ExportModelOperationsMixin("order_product"), NiceModel): # t
|
||||||
return DigitalAssetDownload.objects.create(order_product=self).url
|
return DigitalAssetDownload.objects.create(order_product=self).url
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
def do_feedback(self, rating=10, comment="", action="add") -> Optional["Feedback"] | int:
|
def do_feedback(self, rating=10, comment="", action="add") -> Feedback | int | None:
|
||||||
if not self.order:
|
if not self.order:
|
||||||
raise ValueError(_("order product must have an order"))
|
raise ValueError(_("order product must have an order"))
|
||||||
if action not in ["add", "remove"]:
|
if action not in ["add", "remove"]:
|
||||||
|
|
@ -1912,46 +1955,3 @@ class DigitalAssetDownload(ExportModelOperationsMixin("attribute_group"), NiceMo
|
||||||
return (
|
return (
|
||||||
f"https://api.{config.BASE_DOMAIN}/download/{urlsafe_base64_encode(force_bytes(self.order_product.uuid))}"
|
f"https://api.{config.BASE_DOMAIN}/download/{urlsafe_base64_encode(force_bytes(self.order_product.uuid))}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class Feedback(ExportModelOperationsMixin("feedback"), NiceModel): # type: ignore [misc]
|
|
||||||
__doc__ = _( # type: ignore
|
|
||||||
"Manages user feedback for products. "
|
|
||||||
"This class is designed to capture and store user feedback for specific products "
|
|
||||||
"that they have purchased. It contains attributes to store user comments, "
|
|
||||||
"a reference to the related product in the order, and a user-assigned rating. The "
|
|
||||||
"class uses database fields to effectively model and manage feedback data."
|
|
||||||
)
|
|
||||||
|
|
||||||
is_publicly_visible = True
|
|
||||||
|
|
||||||
comment = TextField(
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
help_text=_("user-provided comments about their experience with the product"),
|
|
||||||
verbose_name=_("feedback comments"),
|
|
||||||
)
|
|
||||||
order_product = OneToOneField(
|
|
||||||
"core.OrderProduct",
|
|
||||||
on_delete=CASCADE,
|
|
||||||
blank=False,
|
|
||||||
null=False,
|
|
||||||
help_text=_("references the specific product in an order that this feedback is about"),
|
|
||||||
verbose_name=_("related order product"),
|
|
||||||
)
|
|
||||||
rating = FloatField(
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
help_text=_("user-assigned rating for the product"),
|
|
||||||
verbose_name=_("product rating"),
|
|
||||||
validators=[MinValueValidator(0), MaxValueValidator(10)],
|
|
||||||
)
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
if self.order_product and self.order_product.order and self.order_product.order.user:
|
|
||||||
return f"{self.rating} by {self.order_product.order.user.email}"
|
|
||||||
return f"{self.rating} | {self.uuid}"
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
verbose_name = _("feedback")
|
|
||||||
verbose_name_plural = _("feedbacks")
|
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ class CategoryDetailSerializer(ModelSerializer):
|
||||||
else:
|
else:
|
||||||
children = obj.children.filter(is_active=True)
|
children = obj.children.filter(is_active=True)
|
||||||
|
|
||||||
return CategorySimpleSerializer(children, many=True, context=self.context).data if obj.children.exists() else []
|
return CategorySimpleSerializer(children, many=True, context=self.context).data if obj.children.exists() else [] # type: ignore [return-value]
|
||||||
|
|
||||||
|
|
||||||
class BrandDetailSerializer(ModelSerializer):
|
class BrandDetailSerializer(ModelSerializer):
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ class CategorySimpleSerializer(ModelSerializer): # type: ignore [type-arg]
|
||||||
else:
|
else:
|
||||||
children = obj.children.filter(is_active=True)
|
children = obj.children.filter(is_active=True)
|
||||||
|
|
||||||
return CategorySimpleSerializer(children, many=True, context=self.context).data if obj.children.exists() else []
|
return CategorySimpleSerializer(children, many=True, context=self.context).data if obj.children.exists() else [] # type: ignore [return-value]
|
||||||
|
|
||||||
|
|
||||||
class BrandSimpleSerializer(ModelSerializer): # type: ignore [type-arg]
|
class BrandSimpleSerializer(ModelSerializer): # type: ignore [type-arg]
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ from engine.core.utils import (
|
||||||
)
|
)
|
||||||
from engine.core.utils.emailing import send_order_created_email, send_order_finished_email, send_promocode_created_email
|
from engine.core.utils.emailing import send_order_created_email, send_order_finished_email, send_promocode_created_email
|
||||||
from evibes.utils.misc import create_object
|
from evibes.utils.misc import create_object
|
||||||
from engine.authv.models import User
|
from engine.vibes_auth.models import User
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import shutil
|
||||||
import uuid
|
import uuid
|
||||||
from datetime import date, timedelta
|
from datetime import date, timedelta
|
||||||
from time import sleep
|
from time import sleep
|
||||||
from typing import Any, Type
|
from typing import Any
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from celery.app import shared_task
|
from celery.app import shared_task
|
||||||
|
|
@ -40,10 +40,11 @@ def update_products_task() -> tuple[bool, str]:
|
||||||
|
|
||||||
if not update_products_task_running:
|
if not update_products_task_running:
|
||||||
cache.set("update_products_task_running", True, 86400)
|
cache.set("update_products_task_running", True, 86400)
|
||||||
vendors: list[Type[AbstractVendor]] = get_vendors_integrations()
|
vendors: list[AbstractVendor] = get_vendors_integrations()
|
||||||
|
|
||||||
for vendor in vendors:
|
for vendor in vendors:
|
||||||
try:
|
try:
|
||||||
|
# noinspection PyArgumentList
|
||||||
vendor.update_stock()
|
vendor.update_stock()
|
||||||
except VendorInactiveError:
|
except VendorInactiveError:
|
||||||
logger.info("Skipping %s due to inactivity", str(vendor))
|
logger.info("Skipping %s due to inactivity", str(vendor))
|
||||||
|
|
@ -70,9 +71,10 @@ def update_orderproducts_task() -> tuple[bool, str]:
|
||||||
message confirming the successful execution of the task.
|
message confirming the successful execution of the task.
|
||||||
:rtype: Tuple[bool, str]
|
:rtype: Tuple[bool, str]
|
||||||
"""
|
"""
|
||||||
vendors: list[Type[AbstractVendor]] = get_vendors_integrations()
|
vendors: list[AbstractVendor] = get_vendors_integrations()
|
||||||
|
|
||||||
for vendor in vendors:
|
for vendor in vendors:
|
||||||
|
# noinspection PyArgumentList
|
||||||
vendor.update_order_products_statuses()
|
vendor.update_order_products_statuses()
|
||||||
|
|
||||||
return True, "Success"
|
return True, "Success"
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ from django.utils.translation import gettext_lazy as _
|
||||||
from graphene import Context
|
from graphene import Context
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
|
|
||||||
from engine.authv.models import User
|
from engine.vibes_auth.models import User
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import logging
|
import logging
|
||||||
from typing import Type
|
|
||||||
|
|
||||||
from engine.core.models import Vendor
|
from engine.core.models import Vendor
|
||||||
from engine.core.vendors import AbstractVendor
|
from engine.core.vendors import AbstractVendor
|
||||||
|
|
@ -8,8 +7,8 @@ from evibes.utils.misc import create_object
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def get_vendors_integrations(name: str | None = None) -> list[Type[AbstractVendor]]:
|
def get_vendors_integrations(name: str | None = None) -> list[AbstractVendor]:
|
||||||
vendors_integrations: list[Type[AbstractVendor]] = []
|
vendors_integrations: list[AbstractVendor] = []
|
||||||
|
|
||||||
vendors = Vendor.objects.filter(is_active=True, integration_path__isnull=False)
|
vendors = Vendor.objects.filter(is_active=True, integration_path__isnull=False)
|
||||||
if name:
|
if name:
|
||||||
|
|
@ -17,7 +16,7 @@ def get_vendors_integrations(name: str | None = None) -> list[Type[AbstractVendo
|
||||||
|
|
||||||
for vendor in vendors:
|
for vendor in vendors:
|
||||||
try:
|
try:
|
||||||
module_name, class_name = vendor.integration_path.rsplit(".", 1)
|
module_name, class_name = vendor.integration_path.rsplit(".", 1) # type: ignore [union-attr]
|
||||||
vendors_integrations.append(create_object(module_name, class_name))
|
vendors_integrations.append(create_object(module_name, class_name))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning("Couldn't load integration for vendor %s: %s", vendor.name, e)
|
logger.warning("Couldn't load integration for vendor %s: %s", vendor.name, e)
|
||||||
|
|
|
||||||
2
engine/core/vendors/__init__.py
vendored
2
engine/core/vendors/__init__.py
vendored
|
|
@ -95,7 +95,7 @@ class AbstractVendor:
|
||||||
deletions on inactive objects.
|
deletions on inactive objects.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, vendor_name: str | None = None, currency: str = "USD") -> None:
|
def __init__(self, vendor_name: str = "", currency: str = "USD") -> None:
|
||||||
self.vendor_name = vendor_name
|
self.vendor_name = vendor_name
|
||||||
self.currency = currency
|
self.currency = currency
|
||||||
self.blocked_attributes: list[Any] = []
|
self.blocked_attributes: list[Any] = []
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.1.5 on 2025-03-10 11:38
|
|
||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
import django_extensions.db.fields
|
import django_extensions.db.fields
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.1.5 on 2025-03-10 11:38
|
|
||||||
|
|
||||||
import django.contrib.postgres.indexes
|
import django.contrib.postgres.indexes
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.1.8 on 2025-04-29 11:32
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.1.8 on 2025-04-30 13:29
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2 on 2025-10-21 09:24
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
import django_extensions.db.fields
|
import django_extensions.db.fields
|
||||||
import uuid
|
import uuid
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
# Generated by Django 5.2.7 on 2025-10-24 23:17
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
from datetime import datetime, time
|
from datetime import datetime, time
|
||||||
from typing import Type
|
|
||||||
|
|
||||||
from constance import config
|
from constance import config
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
@ -9,20 +8,20 @@ from django.db.models import (
|
||||||
CharField,
|
CharField,
|
||||||
FloatField,
|
FloatField,
|
||||||
ForeignKey,
|
ForeignKey,
|
||||||
|
Index,
|
||||||
JSONField,
|
JSONField,
|
||||||
OneToOneField,
|
OneToOneField,
|
||||||
PositiveIntegerField,
|
PositiveIntegerField,
|
||||||
QuerySet,
|
QuerySet,
|
||||||
Sum,
|
Sum,
|
||||||
Index,
|
|
||||||
)
|
)
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from engine.core.abstract import NiceModel
|
from engine.core.abstract import NiceModel
|
||||||
from evibes.utils.misc import create_object
|
|
||||||
from engine.payments.gateways import AbstractGateway
|
from engine.payments.gateways import AbstractGateway
|
||||||
from engine.payments.managers import GatewayManager
|
from engine.payments.managers import GatewayManager
|
||||||
|
from evibes.utils.misc import create_object
|
||||||
|
|
||||||
|
|
||||||
class Transaction(NiceModel):
|
class Transaction(NiceModel):
|
||||||
|
|
@ -172,7 +171,7 @@ class Gateway(NiceModel):
|
||||||
def can_be_used(self, value: bool):
|
def can_be_used(self, value: bool):
|
||||||
self.__dict__["can_be_used"] = value
|
self.__dict__["can_be_used"] = value
|
||||||
|
|
||||||
def get_integration_class_object(self, raise_exc: bool = True) -> Type[AbstractGateway] | None:
|
def get_integration_class_object(self, raise_exc: bool = True) -> AbstractGateway | None:
|
||||||
if not self.integration_path:
|
if not self.integration_path:
|
||||||
if raise_exc:
|
if raise_exc:
|
||||||
raise ValueError(_("gateway integration path is not set"))
|
raise ValueError(_("gateway integration path is not set"))
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ from django.dispatch import receiver
|
||||||
|
|
||||||
from engine.payments.models import Balance, Transaction, Gateway
|
from engine.payments.models import Balance, Transaction, Gateway
|
||||||
from engine.payments.utils.emailing import balance_deposit_email
|
from engine.payments.utils.emailing import balance_deposit_email
|
||||||
from engine.authv.models import User
|
from engine.vibes_auth.models import User
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -27,7 +27,7 @@ def process_transaction_changes(instance: Transaction, created: bool, **kwargs:
|
||||||
instance.gateway = Gateway.objects.can_be_used().first()
|
instance.gateway = Gateway.objects.can_be_used().first()
|
||||||
try:
|
try:
|
||||||
gateway = instance.gateway.get_integration_class_object()
|
gateway = instance.gateway.get_integration_class_object()
|
||||||
gateway.process_transaction(instance)
|
gateway.process_transaction(instance) # type: ignore [union-attr]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
instance.process = {"status": "ERRORED", "error": str(e)}
|
instance.process = {"status": "ERRORED", "error": str(e)}
|
||||||
logger.error(f"Error processing transaction {instance.uuid}: {e}\n{traceback.format_exc()}")
|
logger.error(f"Error processing transaction {instance.uuid}: {e}\n{traceback.format_exc()}")
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,9 @@ from rest_framework_simplejwt.token_blacklist.models import (
|
||||||
from engine.core.admin import ActivationActionsMixin
|
from engine.core.admin import ActivationActionsMixin
|
||||||
from engine.core.models import Order
|
from engine.core.models import Order
|
||||||
from engine.payments.models import Balance
|
from engine.payments.models import Balance
|
||||||
from engine.authv.forms import UserForm
|
from engine.vibes_auth.forms import UserForm
|
||||||
from engine.authv.models import BlacklistedToken, Group, OutstandingToken, User
|
from engine.vibes_auth.messaging.models import ChatMessage, ChatThread, ThreadStatus
|
||||||
|
from engine.vibes_auth.models import BlacklistedToken, Group, OutstandingToken, User
|
||||||
|
|
||||||
|
|
||||||
class BalanceInline(admin.TabularInline): # type: ignore [type-arg]
|
class BalanceInline(admin.TabularInline): # type: ignore [type-arg]
|
||||||
|
|
@ -113,6 +114,52 @@ class UserAdmin(ActivationActionsMixin, BaseUserAdmin): # type: ignore [misc, t
|
||||||
super().save_model(request, obj, form, change)
|
super().save_model(request, obj, form, change)
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal
|
||||||
|
@admin.register(ChatThread)
|
||||||
|
class ChatThreadAdmin(admin.ModelAdmin):
|
||||||
|
list_display = (
|
||||||
|
"uuid",
|
||||||
|
"user",
|
||||||
|
"email",
|
||||||
|
"assigned_to",
|
||||||
|
"status",
|
||||||
|
"last_message_at",
|
||||||
|
"is_active",
|
||||||
|
"created",
|
||||||
|
"modified",
|
||||||
|
)
|
||||||
|
list_filter = (
|
||||||
|
"status",
|
||||||
|
"is_active",
|
||||||
|
("assigned_to", admin.EmptyFieldListFilter),
|
||||||
|
)
|
||||||
|
search_fields = ("uuid", "email", "user__email", "user__username")
|
||||||
|
autocomplete_fields = ("user", "assigned_to")
|
||||||
|
actions = (
|
||||||
|
"close_threads",
|
||||||
|
"open_threads",
|
||||||
|
"delete_selected",
|
||||||
|
)
|
||||||
|
readonly_fields = ("created", "modified")
|
||||||
|
|
||||||
|
@admin.action(description=_("Close selected threads"))
|
||||||
|
def close_threads(self, request, queryset): # type: ignore[no-untyped-def]
|
||||||
|
queryset.update(status=ThreadStatus.CLOSED)
|
||||||
|
|
||||||
|
@admin.action(description=_("Open selected threads"))
|
||||||
|
def open_threads(self, request, queryset): # type: ignore[no-untyped-def]
|
||||||
|
queryset.update(status=ThreadStatus.OPEN)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(ChatMessage)
|
||||||
|
class ChatMessageAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ("uuid", "thread", "sender_type", "sender_user", "sent_at")
|
||||||
|
list_filter = ("sender_type",)
|
||||||
|
search_fields = ("uuid", "thread__uuid", "sender_user__email")
|
||||||
|
autocomplete_fields = ("thread", "sender_user")
|
||||||
|
readonly_fields = ("created", "modified")
|
||||||
|
|
||||||
|
|
||||||
class GroupAdmin(BaseGroupAdmin):
|
class GroupAdmin(BaseGroupAdmin):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
@ -4,11 +4,11 @@ from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
class VibesAuthConfig(AppConfig):
|
class VibesAuthConfig(AppConfig):
|
||||||
default_auto_field = "django.db.models.BigAutoField"
|
default_auto_field = "django.db.models.BigAutoField"
|
||||||
name = "engine.authv"
|
name = "engine.vibes_auth"
|
||||||
verbose_name = _("authentication")
|
verbose_name = _("authentication")
|
||||||
icon = "fa fa-solid fa-user"
|
icon = "fa fa-solid fa-user"
|
||||||
priority = 89
|
priority = 89
|
||||||
hide = False
|
hide = False
|
||||||
|
|
||||||
def ready(self) -> None:
|
def ready(self) -> None:
|
||||||
import engine.authv.signals # noqa: F401
|
import engine.vibes_auth.signals # noqa: F401
|
||||||
|
|
@ -3,7 +3,7 @@ from drf_spectacular.utils import extend_schema, inline_serializer
|
||||||
from rest_framework import serializers, status
|
from rest_framework import serializers, status
|
||||||
|
|
||||||
from engine.core.docs.drf import error
|
from engine.core.docs.drf import error
|
||||||
from engine.authv.serializers import (
|
from engine.vibes_auth.serializers import (
|
||||||
TokenObtainPairSerializer,
|
TokenObtainPairSerializer,
|
||||||
TokenRefreshSerializer,
|
TokenRefreshSerializer,
|
||||||
TokenVerifySerializer,
|
TokenVerifySerializer,
|
||||||
|
|
@ -3,7 +3,7 @@ from drf_spectacular.utils import extend_schema
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
|
|
||||||
from engine.core.docs.drf import BASE_ERRORS
|
from engine.core.docs.drf import BASE_ERRORS
|
||||||
from engine.authv.serializers import (
|
from engine.vibes_auth.serializers import (
|
||||||
ActivateEmailSerializer,
|
ActivateEmailSerializer,
|
||||||
ConfirmPasswordResetSerializer,
|
ConfirmPasswordResetSerializer,
|
||||||
MergeRecentlyViewedSerializer,
|
MergeRecentlyViewedSerializer,
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import django_filters
|
import django_filters
|
||||||
|
|
||||||
from engine.authv.models import User
|
from engine.vibes_auth.models import User
|
||||||
|
|
||||||
|
|
||||||
class UserFilter(django_filters.FilterSet):
|
class UserFilter(django_filters.FilterSet):
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
from django.forms import ModelForm
|
from django.forms import ModelForm
|
||||||
|
|
||||||
from engine.core.widgets import JSONTableWidget
|
from engine.core.widgets import JSONTableWidget
|
||||||
from engine.authv.models import User
|
from engine.vibes_auth.models import User
|
||||||
|
|
||||||
|
|
||||||
class UserForm(ModelForm): # type: ignore [type-arg]
|
class UserForm(ModelForm): # type: ignore [type-arg]
|
||||||
|
|
@ -15,15 +15,15 @@ from graphene_file_upload.scalars import Upload
|
||||||
|
|
||||||
from engine.core.graphene import BaseMutation
|
from engine.core.graphene import BaseMutation
|
||||||
from engine.core.utils.messages import permission_denied_message
|
from engine.core.utils.messages import permission_denied_message
|
||||||
from engine.authv.graphene.object_types import UserType
|
from engine.vibes_auth.graphene.object_types import UserType
|
||||||
from engine.authv.models import User
|
from engine.vibes_auth.models import User
|
||||||
from engine.authv.serializers import (
|
from engine.vibes_auth.serializers import (
|
||||||
TokenObtainPairSerializer,
|
TokenObtainPairSerializer,
|
||||||
TokenRefreshSerializer,
|
TokenRefreshSerializer,
|
||||||
TokenVerifySerializer,
|
TokenVerifySerializer,
|
||||||
)
|
)
|
||||||
from engine.authv.utils.emailing import send_reset_password_email_task
|
from engine.vibes_auth.utils.emailing import send_reset_password_email_task
|
||||||
from engine.authv.validators import is_valid_email, is_valid_phone_number
|
from engine.vibes_auth.validators import is_valid_email, is_valid_phone_number
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -109,7 +109,7 @@ class UpdateUser(BaseMutation):
|
||||||
name = "User"
|
name = "User"
|
||||||
raise Http404(_(f"{name} does not exist: {uuid}")) from dne
|
raise Http404(_(f"{name} does not exist: {uuid}")) from dne
|
||||||
|
|
||||||
if not (info.context.user.has_perm("authv.change_user") or info.context.user == user):
|
if not (info.context.user.has_perm("vibes_auth.change_user") or info.context.user == user):
|
||||||
raise PermissionDenied(permission_denied_message)
|
raise PermissionDenied(permission_denied_message)
|
||||||
|
|
||||||
email = kwargs.get("email")
|
email = kwargs.get("email")
|
||||||
|
|
@ -158,7 +158,7 @@ class UpdateUser(BaseMutation):
|
||||||
"is_staff",
|
"is_staff",
|
||||||
"is_active",
|
"is_active",
|
||||||
"is_superuser",
|
"is_superuser",
|
||||||
] or info.context.user.has_perm("authv.change_user"):
|
] or info.context.user.has_perm("vibes_auth.change_user"):
|
||||||
setattr(user, attr, value)
|
setattr(user, attr, value)
|
||||||
|
|
||||||
user.save()
|
user.save()
|
||||||
|
|
@ -174,7 +174,7 @@ class DeleteUser(BaseMutation):
|
||||||
success = Boolean()
|
success = Boolean()
|
||||||
|
|
||||||
def mutate(self, info, uuid=None, email=None):
|
def mutate(self, info, uuid=None, email=None):
|
||||||
if info.context.user.has_perm("authv.delete_user"):
|
if info.context.user.has_perm("vibes_auth.delete_user"):
|
||||||
try:
|
try:
|
||||||
if uuid is not None:
|
if uuid is not None:
|
||||||
User.objects.get(uuid=uuid).delete()
|
User.objects.get(uuid=uuid).delete()
|
||||||
|
|
@ -10,7 +10,7 @@ from engine.core.graphene.object_types import OrderType, ProductType, WishlistTy
|
||||||
from engine.core.models import Product, Wishlist
|
from engine.core.models import Product, Wishlist
|
||||||
from engine.payments.graphene.object_types import BalanceType
|
from engine.payments.graphene.object_types import BalanceType
|
||||||
from engine.payments.models import Balance
|
from engine.payments.models import Balance
|
||||||
from engine.authv.models import User
|
from engine.vibes_auth.models import User
|
||||||
|
|
||||||
|
|
||||||
class GroupType(DjangoObjectType):
|
class GroupType(DjangoObjectType):
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue