Features: 1) RUFFVCKED
This commit is contained in:
parent
d17839abed
commit
aa8f15d0ee
87 changed files with 6187 additions and 3160 deletions
|
|
@ -5,6 +5,7 @@
|
||||||
<option name="myDocStringFormat" value="Google" />
|
<option name="myDocStringFormat" value="Google" />
|
||||||
</component>
|
</component>
|
||||||
<component name="TemplatesService">
|
<component name="TemplatesService">
|
||||||
|
<option name="TEMPLATE_CONFIGURATION" value="Django" />
|
||||||
<option name="TEMPLATE_FOLDERS">
|
<option name="TEMPLATE_FOLDERS">
|
||||||
<list>
|
<list>
|
||||||
<option value="$MODULE_DIR$/blog/templates" />
|
<option value="$MODULE_DIR$/blog/templates" />
|
||||||
|
|
|
||||||
|
|
@ -18,56 +18,113 @@ class Migration(migrations.Migration):
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='PostTag',
|
name="PostTag",
|
||||||
fields=[
|
fields=[
|
||||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
|
(
|
||||||
help_text='unique id is used to surely identify any database object',
|
"uuid",
|
||||||
primary_key=True, serialize=False, verbose_name='unique id')),
|
models.UUIDField(
|
||||||
('is_active', models.BooleanField(default=True,
|
default=uuid.uuid4,
|
||||||
|
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",
|
help_text="if set to false, this object can't be seen by users without needed permission",
|
||||||
verbose_name='is active')),
|
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,
|
"created",
|
||||||
help_text='when the object was last modified',
|
django_extensions.db.fields.CreationDateTimeField(
|
||||||
verbose_name='modified')),
|
auto_now_add=True,
|
||||||
('tag_name', models.CharField(help_text='internal tag identifier for the post tag', max_length=255,
|
help_text="when the object first appeared on the database",
|
||||||
verbose_name='tag name')),
|
verbose_name="created",
|
||||||
('name', models.CharField(help_text='user-friendly name for the post tag', max_length=255, unique=True,
|
),
|
||||||
verbose_name='tag display name')),
|
),
|
||||||
|
(
|
||||||
|
"modified",
|
||||||
|
django_extensions.db.fields.ModificationDateTimeField(
|
||||||
|
auto_now=True, help_text="when the object was last modified", verbose_name="modified"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"tag_name",
|
||||||
|
models.CharField(
|
||||||
|
help_text="internal tag identifier for the post tag", max_length=255, verbose_name="tag name"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"name",
|
||||||
|
models.CharField(
|
||||||
|
help_text="user-friendly name for the post tag",
|
||||||
|
max_length=255,
|
||||||
|
unique=True,
|
||||||
|
verbose_name="tag display name",
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'post tag',
|
"verbose_name": "post tag",
|
||||||
'verbose_name_plural': 'post tags',
|
"verbose_name_plural": "post tags",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Post',
|
name="Post",
|
||||||
fields=[
|
fields=[
|
||||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
|
(
|
||||||
help_text='unique id is used to surely identify any database object',
|
"uuid",
|
||||||
primary_key=True, serialize=False, verbose_name='unique id')),
|
models.UUIDField(
|
||||||
('is_active', models.BooleanField(default=True,
|
default=uuid.uuid4,
|
||||||
|
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",
|
help_text="if set to false, this object can't be seen by users without needed permission",
|
||||||
verbose_name='is active')),
|
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,
|
"created",
|
||||||
help_text='when the object was last modified',
|
django_extensions.db.fields.CreationDateTimeField(
|
||||||
verbose_name='modified')),
|
auto_now_add=True,
|
||||||
('title', models.CharField()),
|
help_text="when the object first appeared on the database",
|
||||||
('content', markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name='content')),
|
verbose_name="created",
|
||||||
('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)),
|
"modified",
|
||||||
('tags', models.ManyToManyField(to='blog.posttag')),
|
django_extensions.db.fields.ModificationDateTimeField(
|
||||||
|
auto_now=True, help_text="when the object was last modified", verbose_name="modified"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("title", models.CharField()),
|
||||||
|
("content", markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content")),
|
||||||
|
("file", models.FileField(blank=True, null=True, upload_to="posts/")),
|
||||||
|
("slug", models.SlugField(allow_unicode=True)),
|
||||||
|
(
|
||||||
|
"author",
|
||||||
|
models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE, related_name="posts", to=settings.AUTH_USER_MODEL
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("tags", models.ManyToManyField(to="blog.posttag")),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'post',
|
"verbose_name": "post",
|
||||||
'verbose_name_plural': 'posts',
|
"verbose_name_plural": "posts",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -5,20 +5,21 @@ from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('blog', '0001_initial'),
|
("blog", "0001_initial"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='post',
|
model_name="post",
|
||||||
name='slug',
|
name="slug",
|
||||||
field=django_extensions.db.fields.AutoSlugField(allow_unicode=True, blank=True, editable=False, populate_from='title', unique=True),
|
field=django_extensions.db.fields.AutoSlugField(
|
||||||
|
allow_unicode=True, blank=True, editable=False, populate_from="title", unique=True
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='post',
|
model_name="post",
|
||||||
name='title',
|
name="title",
|
||||||
field=models.CharField(help_text='post title', max_length=128, unique=True, verbose_name='title'),
|
field=models.CharField(help_text="post title", max_length=128, unique=True, verbose_name="title"),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -4,15 +4,14 @@ from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('blog', '0002_alter_post_slug_alter_post_title'),
|
("blog", "0002_alter_post_slug_alter_post_title"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='post',
|
model_name="post",
|
||||||
name='tags',
|
name="tags",
|
||||||
field=models.ManyToManyField(blank=True, related_name='posts', to='blog.posttag'),
|
field=models.ManyToManyField(blank=True, related_name="posts", to="blog.posttag"),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("blog", "0003_alter_post_tags"),
|
("blog", "0003_alter_post_tags"),
|
||||||
]
|
]
|
||||||
|
|
@ -14,128 +13,92 @@ class Migration(migrations.Migration):
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name="post",
|
model_name="post",
|
||||||
name="content_ar_ar",
|
name="content_ar_ar",
|
||||||
field=markdown_field.fields.MarkdownField(
|
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||||
blank=True, null=True, verbose_name="content"
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name="post",
|
model_name="post",
|
||||||
name="content_cs_cz",
|
name="content_cs_cz",
|
||||||
field=markdown_field.fields.MarkdownField(
|
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||||
blank=True, null=True, verbose_name="content"
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name="post",
|
model_name="post",
|
||||||
name="content_da_dk",
|
name="content_da_dk",
|
||||||
field=markdown_field.fields.MarkdownField(
|
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||||
blank=True, null=True, verbose_name="content"
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name="post",
|
model_name="post",
|
||||||
name="content_de_de",
|
name="content_de_de",
|
||||||
field=markdown_field.fields.MarkdownField(
|
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||||
blank=True, null=True, verbose_name="content"
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name="post",
|
model_name="post",
|
||||||
name="content_en_gb",
|
name="content_en_gb",
|
||||||
field=markdown_field.fields.MarkdownField(
|
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||||
blank=True, null=True, verbose_name="content"
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name="post",
|
model_name="post",
|
||||||
name="content_en_us",
|
name="content_en_us",
|
||||||
field=markdown_field.fields.MarkdownField(
|
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||||
blank=True, null=True, verbose_name="content"
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name="post",
|
model_name="post",
|
||||||
name="content_es_es",
|
name="content_es_es",
|
||||||
field=markdown_field.fields.MarkdownField(
|
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||||
blank=True, null=True, verbose_name="content"
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name="post",
|
model_name="post",
|
||||||
name="content_fr_fr",
|
name="content_fr_fr",
|
||||||
field=markdown_field.fields.MarkdownField(
|
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||||
blank=True, null=True, verbose_name="content"
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name="post",
|
model_name="post",
|
||||||
name="content_hi_in",
|
name="content_hi_in",
|
||||||
field=markdown_field.fields.MarkdownField(
|
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||||
blank=True, null=True, verbose_name="content"
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name="post",
|
model_name="post",
|
||||||
name="content_it_it",
|
name="content_it_it",
|
||||||
field=markdown_field.fields.MarkdownField(
|
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||||
blank=True, null=True, verbose_name="content"
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name="post",
|
model_name="post",
|
||||||
name="content_ja_jp",
|
name="content_ja_jp",
|
||||||
field=markdown_field.fields.MarkdownField(
|
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||||
blank=True, null=True, verbose_name="content"
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name="post",
|
model_name="post",
|
||||||
name="content_kk_kz",
|
name="content_kk_kz",
|
||||||
field=markdown_field.fields.MarkdownField(
|
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||||
blank=True, null=True, verbose_name="content"
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name="post",
|
model_name="post",
|
||||||
name="content_nl_nl",
|
name="content_nl_nl",
|
||||||
field=markdown_field.fields.MarkdownField(
|
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||||
blank=True, null=True, verbose_name="content"
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name="post",
|
model_name="post",
|
||||||
name="content_pl_pl",
|
name="content_pl_pl",
|
||||||
field=markdown_field.fields.MarkdownField(
|
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||||
blank=True, null=True, verbose_name="content"
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name="post",
|
model_name="post",
|
||||||
name="content_pt_br",
|
name="content_pt_br",
|
||||||
field=markdown_field.fields.MarkdownField(
|
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||||
blank=True, null=True, verbose_name="content"
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name="post",
|
model_name="post",
|
||||||
name="content_ro_ro",
|
name="content_ro_ro",
|
||||||
field=markdown_field.fields.MarkdownField(
|
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||||
blank=True, null=True, verbose_name="content"
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name="post",
|
model_name="post",
|
||||||
name="content_ru_ru",
|
name="content_ru_ru",
|
||||||
field=markdown_field.fields.MarkdownField(
|
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||||
blank=True, null=True, verbose_name="content"
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name="post",
|
model_name="post",
|
||||||
name="content_zh_hans",
|
name="content_zh_hans",
|
||||||
field=markdown_field.fields.MarkdownField(
|
field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
|
||||||
blank=True, null=True, verbose_name="content"
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name="post",
|
model_name="post",
|
||||||
|
|
|
||||||
|
|
@ -31,10 +31,8 @@ class Post(NiceModel):
|
||||||
|
|
||||||
is_publicly_visible = True
|
is_publicly_visible = True
|
||||||
|
|
||||||
author: ForeignKey = ForeignKey(
|
author = ForeignKey(to="vibes_auth.User", on_delete=CASCADE, blank=False, null=False, related_name="posts")
|
||||||
to="vibes_auth.User", on_delete=CASCADE, blank=False, null=False, related_name="posts"
|
title = CharField(
|
||||||
)
|
|
||||||
title: CharField = CharField(
|
|
||||||
unique=True, max_length=128, blank=False, null=False, help_text=_("post title"), verbose_name=_("title")
|
unique=True, max_length=128, blank=False, null=False, help_text=_("post title"), verbose_name=_("title")
|
||||||
)
|
)
|
||||||
content: MarkdownField = MarkdownField(
|
content: MarkdownField = MarkdownField(
|
||||||
|
|
@ -74,9 +72,9 @@ class Post(NiceModel):
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
)
|
)
|
||||||
file: FileField = FileField(upload_to="posts/", blank=True, null=True)
|
file = FileField(upload_to="posts/", blank=True, null=True)
|
||||||
slug: AutoSlugField = AutoSlugField(populate_from="title", allow_unicode=True, unique=True, editable=False)
|
slug = AutoSlugField(populate_from="title", allow_unicode=True, unique=True, editable=False)
|
||||||
tags: ManyToManyField = ManyToManyField(to="blog.PostTag", blank=True, related_name="posts")
|
tags = ManyToManyField(to="blog.PostTag", blank=True, related_name="posts")
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.title} | {self.author.first_name} {self.author.last_name}"
|
return f"{self.title} | {self.author.first_name} {self.author.last_name}"
|
||||||
|
|
@ -115,15 +113,16 @@ class PostTag(NiceModel):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
is_publicly_visible = True
|
is_publicly_visible = True
|
||||||
|
posts: "Post"
|
||||||
|
|
||||||
tag_name: CharField = CharField(
|
tag_name = CharField(
|
||||||
blank=False,
|
blank=False,
|
||||||
null=False,
|
null=False,
|
||||||
max_length=255,
|
max_length=255,
|
||||||
help_text=_("internal tag identifier for the post tag"),
|
help_text=_("internal tag identifier for the post tag"),
|
||||||
verbose_name=_("tag name"),
|
verbose_name=_("tag name"),
|
||||||
)
|
)
|
||||||
name: CharField = CharField(
|
name = CharField(
|
||||||
max_length=255,
|
max_length=255,
|
||||||
help_text=_("user-friendly name for the post tag"),
|
help_text=_("user-friendly name for the post tag"),
|
||||||
verbose_name=_("tag display name"),
|
verbose_name=_("tag display name"),
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import uuid
|
import uuid
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
from django.db.models import BooleanField, Model, UUIDField
|
from django.db.models import BooleanField, Model, UUIDField
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
@ -7,25 +6,21 @@ from django_extensions.db.fields import CreationDateTimeField, ModificationDateT
|
||||||
|
|
||||||
|
|
||||||
class NiceModel(Model):
|
class NiceModel(Model):
|
||||||
id = None
|
id: None = None
|
||||||
uuid: uuid = UUIDField( # type: ignore
|
uuid = UUIDField(
|
||||||
verbose_name=_("unique id"),
|
verbose_name=_("unique id"),
|
||||||
help_text=_("unique id is used to surely identify any database object"),
|
help_text=_("unique id is used to surely identify any database object"),
|
||||||
primary_key=True,
|
primary_key=True,
|
||||||
default=uuid.uuid4,
|
default=uuid.uuid4,
|
||||||
editable=False,
|
editable=False,
|
||||||
)
|
)
|
||||||
is_active: bool = BooleanField( # type: ignore
|
is_active = BooleanField(
|
||||||
default=True,
|
default=True,
|
||||||
verbose_name=_("is active"),
|
verbose_name=_("is active"),
|
||||||
help_text=_("if set to false, this object can't be seen by users without needed permission"),
|
help_text=_("if set to false, this object can't be seen by users without needed permission"),
|
||||||
)
|
)
|
||||||
created: datetime = CreationDateTimeField( # type: ignore
|
created = CreationDateTimeField(_("created"), help_text=_("when the object first appeared on the database"))
|
||||||
_("created"), help_text=_("when the object first appeared on the database")
|
modified = ModificationDateTimeField(_("modified"), help_text=_("when the object was last modified"))
|
||||||
)
|
|
||||||
modified: datetime = ModificationDateTimeField( # type: ignore
|
|
||||||
_("modified"), help_text=_("when the object was last modified")
|
|
||||||
)
|
|
||||||
|
|
||||||
def save(self, **kwargs):
|
def save(self, **kwargs):
|
||||||
self.update_modified = kwargs.pop("update_modified", getattr(self, "update_modified", True))
|
self.update_modified = kwargs.pop("update_modified", getattr(self, "update_modified", True))
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
|
from typing import ClassVar, Type
|
||||||
|
|
||||||
from constance.admin import Config
|
from constance.admin import Config
|
||||||
from constance.admin import ConstanceAdmin as BaseConstanceAdmin
|
from constance.admin import ConstanceAdmin as BaseConstanceAdmin
|
||||||
|
|
@ -38,7 +39,7 @@ from evibes.settings import CONSTANCE_CONFIG
|
||||||
class FieldsetsMixin:
|
class FieldsetsMixin:
|
||||||
general_fields: list = []
|
general_fields: list = []
|
||||||
relation_fields: list = []
|
relation_fields: list = []
|
||||||
model: Model
|
model: ClassVar[Type[Model]]
|
||||||
|
|
||||||
def get_fieldsets(self, request, obj=None):
|
def get_fieldsets(self, request, obj=None):
|
||||||
if request:
|
if request:
|
||||||
|
|
@ -172,7 +173,7 @@ class CategoryChildrenInline(TabularInline):
|
||||||
|
|
||||||
@register(AttributeGroup)
|
@register(AttributeGroup)
|
||||||
class AttributeGroupAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
class AttributeGroupAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
model = AttributeGroup # type: ignore
|
model = AttributeGroup
|
||||||
list_display = ("name", "modified")
|
list_display = ("name", "modified")
|
||||||
search_fields = ("uuid", "name")
|
search_fields = ("uuid", "name")
|
||||||
readonly_fields = ("uuid", "modified", "created")
|
readonly_fields = ("uuid", "modified", "created")
|
||||||
|
|
@ -183,7 +184,7 @@ class AttributeGroupAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
|
|
||||||
@register(Attribute)
|
@register(Attribute)
|
||||||
class AttributeAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
class AttributeAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
model = Attribute # type: ignore
|
model = Attribute
|
||||||
list_display = ("name", "group", "value_type", "modified")
|
list_display = ("name", "group", "value_type", "modified")
|
||||||
list_filter = ("value_type", "group", "is_active")
|
list_filter = ("value_type", "group", "is_active")
|
||||||
search_fields = ("uuid", "name", "group__name")
|
search_fields = ("uuid", "name", "group__name")
|
||||||
|
|
@ -196,7 +197,7 @@ class AttributeAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
|
|
||||||
@register(AttributeValue)
|
@register(AttributeValue)
|
||||||
class AttributeValueAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
class AttributeValueAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
model = AttributeValue # type: ignore
|
model = AttributeValue
|
||||||
list_display = ("attribute", "value", "modified")
|
list_display = ("attribute", "value", "modified")
|
||||||
list_filter = ("attribute__group", "is_active")
|
list_filter = ("attribute__group", "is_active")
|
||||||
search_fields = ("uuid", "value", "attribute__name")
|
search_fields = ("uuid", "value", "attribute__name")
|
||||||
|
|
@ -209,7 +210,7 @@ class AttributeValueAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
|
|
||||||
@register(Category)
|
@register(Category)
|
||||||
class CategoryAdmin(FieldsetsMixin, ActivationActionsMixin, DraggableMPTTAdmin):
|
class CategoryAdmin(FieldsetsMixin, ActivationActionsMixin, DraggableMPTTAdmin):
|
||||||
model = Category # type: ignore
|
model = Category
|
||||||
list_display = ("indented_title", "parent", "is_active", "modified")
|
list_display = ("indented_title", "parent", "is_active", "modified")
|
||||||
# noinspection PyUnresolvedReferences
|
# noinspection PyUnresolvedReferences
|
||||||
list_filter = ("is_active", "level", "created", "modified")
|
list_filter = ("is_active", "level", "created", "modified")
|
||||||
|
|
@ -224,7 +225,7 @@ class CategoryAdmin(FieldsetsMixin, ActivationActionsMixin, DraggableMPTTAdmin):
|
||||||
|
|
||||||
@register(Brand)
|
@register(Brand)
|
||||||
class BrandAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
class BrandAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
model = Brand # type: ignore
|
model = Brand
|
||||||
list_display = ("name",)
|
list_display = ("name",)
|
||||||
list_filter = ("categories", "is_active")
|
list_filter = ("categories", "is_active")
|
||||||
search_fields = ("uuid", "name", "categories__name")
|
search_fields = ("uuid", "name", "categories__name")
|
||||||
|
|
@ -236,7 +237,7 @@ class BrandAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
|
|
||||||
@register(Product)
|
@register(Product)
|
||||||
class ProductAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
class ProductAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
model = Product # type: ignore
|
model = Product
|
||||||
list_display = (
|
list_display = (
|
||||||
"name",
|
"name",
|
||||||
"partnumber",
|
"partnumber",
|
||||||
|
|
@ -275,7 +276,7 @@ class ProductAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
|
|
||||||
@register(ProductTag)
|
@register(ProductTag)
|
||||||
class ProductTagAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
class ProductTagAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
model = ProductTag # type: ignore
|
model = ProductTag
|
||||||
list_display = ("tag_name",)
|
list_display = ("tag_name",)
|
||||||
search_fields = ("tag_name",)
|
search_fields = ("tag_name",)
|
||||||
readonly_fields = ("uuid", "modified", "created")
|
readonly_fields = ("uuid", "modified", "created")
|
||||||
|
|
@ -286,7 +287,7 @@ class ProductTagAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
|
|
||||||
@register(CategoryTag)
|
@register(CategoryTag)
|
||||||
class CategoryTagAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
class CategoryTagAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
model = CategoryTag # type: ignore
|
model = CategoryTag
|
||||||
list_display = ("tag_name",)
|
list_display = ("tag_name",)
|
||||||
search_fields = ("tag_name",)
|
search_fields = ("tag_name",)
|
||||||
readonly_fields = ("uuid", "modified", "created")
|
readonly_fields = ("uuid", "modified", "created")
|
||||||
|
|
@ -297,7 +298,7 @@ class CategoryTagAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
|
|
||||||
@register(Vendor)
|
@register(Vendor)
|
||||||
class VendorAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
class VendorAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
model = Vendor # type: ignore
|
model = Vendor
|
||||||
list_display = ("name", "markup_percent", "modified")
|
list_display = ("name", "markup_percent", "modified")
|
||||||
list_filter = ("markup_percent", "is_active")
|
list_filter = ("markup_percent", "is_active")
|
||||||
search_fields = ("name",)
|
search_fields = ("name",)
|
||||||
|
|
@ -310,7 +311,7 @@ class VendorAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
|
|
||||||
@register(Feedback)
|
@register(Feedback)
|
||||||
class FeedbackAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
class FeedbackAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
model = Feedback # type: ignore
|
model = Feedback
|
||||||
list_display = ("order_product", "rating", "comment", "modified")
|
list_display = ("order_product", "rating", "comment", "modified")
|
||||||
list_filter = ("rating", "is_active")
|
list_filter = ("rating", "is_active")
|
||||||
search_fields = ("order_product__product__name", "comment")
|
search_fields = ("order_product__product__name", "comment")
|
||||||
|
|
@ -322,7 +323,7 @@ class FeedbackAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
|
|
||||||
@register(Order)
|
@register(Order)
|
||||||
class OrderAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
class OrderAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
model = Order # type: ignore
|
model = Order
|
||||||
list_display = (
|
list_display = (
|
||||||
"human_readable_id",
|
"human_readable_id",
|
||||||
"user",
|
"user",
|
||||||
|
|
@ -350,7 +351,7 @@ class OrderAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
|
|
||||||
@register(OrderProduct)
|
@register(OrderProduct)
|
||||||
class OrderProductAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
class OrderProductAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
model = OrderProduct # type: ignore
|
model = OrderProduct
|
||||||
list_display = ("order", "product", "quantity", "buy_price", "status", "modified")
|
list_display = ("order", "product", "quantity", "buy_price", "status", "modified")
|
||||||
list_filter = ("status",)
|
list_filter = ("status",)
|
||||||
search_fields = ("order__user__email", "product__name")
|
search_fields = ("order__user__email", "product__name")
|
||||||
|
|
@ -363,7 +364,7 @@ class OrderProductAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
|
|
||||||
@register(PromoCode)
|
@register(PromoCode)
|
||||||
class PromoCodeAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
class PromoCodeAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
model = PromoCode # type: ignore
|
model = PromoCode
|
||||||
list_display = (
|
list_display = (
|
||||||
"code",
|
"code",
|
||||||
"discount_percent",
|
"discount_percent",
|
||||||
|
|
@ -391,7 +392,7 @@ class PromoCodeAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
|
|
||||||
@register(Promotion)
|
@register(Promotion)
|
||||||
class PromotionAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
class PromotionAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
model = Promotion # type: ignore
|
model = Promotion
|
||||||
list_display = ("name", "discount_percent", "modified")
|
list_display = ("name", "discount_percent", "modified")
|
||||||
search_fields = ("name",)
|
search_fields = ("name",)
|
||||||
readonly_fields = ("uuid", "modified", "created")
|
readonly_fields = ("uuid", "modified", "created")
|
||||||
|
|
@ -403,7 +404,7 @@ class PromotionAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
|
|
||||||
@register(Stock)
|
@register(Stock)
|
||||||
class StockAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
class StockAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
model = Stock # type: ignore
|
model = Stock
|
||||||
list_display = ("product", "vendor", "sku", "quantity", "price", "modified")
|
list_display = ("product", "vendor", "sku", "quantity", "price", "modified")
|
||||||
list_filter = ("vendor", "quantity")
|
list_filter = ("vendor", "quantity")
|
||||||
search_fields = ("product__name", "vendor__name", "sku")
|
search_fields = ("product__name", "vendor__name", "sku")
|
||||||
|
|
@ -423,7 +424,7 @@ class StockAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
|
|
||||||
@register(Wishlist)
|
@register(Wishlist)
|
||||||
class WishlistAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
class WishlistAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
model = Wishlist # type: ignore
|
model = Wishlist
|
||||||
list_display = ("user", "modified")
|
list_display = ("user", "modified")
|
||||||
search_fields = ("user__email",)
|
search_fields = ("user__email",)
|
||||||
readonly_fields = ("uuid", "modified", "created")
|
readonly_fields = ("uuid", "modified", "created")
|
||||||
|
|
@ -434,7 +435,7 @@ class WishlistAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
|
|
||||||
@register(ProductImage)
|
@register(ProductImage)
|
||||||
class ProductImageAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
class ProductImageAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
model = ProductImage # type: ignore
|
model = ProductImage
|
||||||
list_display = ("alt", "product", "priority", "modified")
|
list_display = ("alt", "product", "priority", "modified")
|
||||||
list_filter = ("priority",)
|
list_filter = ("priority",)
|
||||||
search_fields = ("alt", "product__name")
|
search_fields = ("alt", "product__name")
|
||||||
|
|
@ -447,7 +448,7 @@ class ProductImageAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
||||||
|
|
||||||
@register(Address)
|
@register(Address)
|
||||||
class AddressAdmin(FieldsetsMixin, GISModelAdmin):
|
class AddressAdmin(FieldsetsMixin, GISModelAdmin):
|
||||||
model = Address # type: ignore
|
model = Address
|
||||||
list_display = ("street", "city", "region", "country", "user")
|
list_display = ("street", "city", "region", "country", "user")
|
||||||
list_filter = ("country", "region")
|
list_filter = ("country", "region")
|
||||||
search_fields = ("street", "city", "postal_code", "user__email")
|
search_fields = ("street", "city", "postal_code", "user__email")
|
||||||
|
|
@ -507,8 +508,10 @@ class ConstanceConfig:
|
||||||
_meta = Meta()
|
_meta = Meta()
|
||||||
|
|
||||||
|
|
||||||
site.unregister([Config]) # type: ignore
|
# noinspection PyTypeChecker
|
||||||
site.register([ConstanceConfig], BaseConstanceAdmin) # type: ignore
|
site.unregister([Config])
|
||||||
site.site_title = CONSTANCE_CONFIG["PROJECT_NAME"][0] # type: ignore
|
# noinspection PyTypeChecker
|
||||||
|
site.register([ConstanceConfig], BaseConstanceAdmin)
|
||||||
|
site.site_title = CONSTANCE_CONFIG["PROJECT_NAME"][0]
|
||||||
site.site_header = "eVibes"
|
site.site_header = "eVibes"
|
||||||
site.index_title = CONSTANCE_CONFIG["PROJECT_NAME"][0] # type: ignore
|
site.index_title = CONSTANCE_CONFIG["PROJECT_NAME"][0]
|
||||||
|
|
|
||||||
|
|
@ -185,8 +185,8 @@ def process_query(query: str = "", request: Request | None = None) -> dict[str,
|
||||||
results[idx].append(hit_result)
|
results[idx].append(hit_result)
|
||||||
|
|
||||||
return results
|
return results
|
||||||
except NotFoundError:
|
except NotFoundError as nfe:
|
||||||
raise Http404
|
raise Http404 from nfe
|
||||||
|
|
||||||
|
|
||||||
LANGUAGE_ANALYZER_MAP = {
|
LANGUAGE_ANALYZER_MAP = {
|
||||||
|
|
|
||||||
|
|
@ -96,8 +96,8 @@ class AddOrderProduct(BaseMutation):
|
||||||
order = order.add_product(product_uuid=product_uuid, attributes=format_attributes(attributes))
|
order = order.add_product(product_uuid=product_uuid, attributes=format_attributes(attributes))
|
||||||
|
|
||||||
return AddOrderProduct(order=order)
|
return AddOrderProduct(order=order)
|
||||||
except Order.DoesNotExist:
|
except Order.DoesNotExist as dne:
|
||||||
raise Http404(_(f"order {order_uuid} not found"))
|
raise Http404(_(f"order {order_uuid} not found")) from dne
|
||||||
|
|
||||||
|
|
||||||
class RemoveOrderProduct(BaseMutation):
|
class RemoveOrderProduct(BaseMutation):
|
||||||
|
|
@ -122,8 +122,8 @@ class RemoveOrderProduct(BaseMutation):
|
||||||
order = order.remove_product(product_uuid=product_uuid, attributes=format_attributes(attributes))
|
order = order.remove_product(product_uuid=product_uuid, attributes=format_attributes(attributes))
|
||||||
|
|
||||||
return AddOrderProduct(order=order)
|
return AddOrderProduct(order=order)
|
||||||
except Order.DoesNotExist:
|
except Order.DoesNotExist as dne:
|
||||||
raise Http404(_(f"order {order_uuid} not found"))
|
raise Http404(_(f"order {order_uuid} not found")) from dne
|
||||||
|
|
||||||
|
|
||||||
class RemoveAllOrderProducts(BaseMutation):
|
class RemoveAllOrderProducts(BaseMutation):
|
||||||
|
|
@ -224,8 +224,8 @@ class BuyOrder(BaseMutation):
|
||||||
case _:
|
case _:
|
||||||
raise TypeError(_(f"wrong type came from order.buy() method: {type(instance)!s}"))
|
raise TypeError(_(f"wrong type came from order.buy() method: {type(instance)!s}"))
|
||||||
|
|
||||||
except Order.DoesNotExist:
|
except Order.DoesNotExist as dne:
|
||||||
raise Http404(_(f"order {order_uuid} not found"))
|
raise Http404(_(f"order {order_uuid} not found")) from dne
|
||||||
|
|
||||||
|
|
||||||
class BulkOrderAction(BaseMutation):
|
class BulkOrderAction(BaseMutation):
|
||||||
|
|
@ -271,8 +271,8 @@ class BulkOrderAction(BaseMutation):
|
||||||
|
|
||||||
return BulkOrderAction(order=order)
|
return BulkOrderAction(order=order)
|
||||||
|
|
||||||
except Order.DoesNotExist:
|
except Order.DoesNotExist as dne:
|
||||||
raise Http404(_(f"order {order_uuid} not found"))
|
raise Http404(_(f"order {order_uuid} not found")) from dne
|
||||||
|
|
||||||
|
|
||||||
class BuyUnregisteredOrder(BaseMutation):
|
class BuyUnregisteredOrder(BaseMutation):
|
||||||
|
|
@ -344,8 +344,8 @@ class AddWishlistProduct(BaseMutation):
|
||||||
|
|
||||||
return AddWishlistProduct(wishlist=wishlist)
|
return AddWishlistProduct(wishlist=wishlist)
|
||||||
|
|
||||||
except Wishlist.DoesNotExist:
|
except Wishlist.DoesNotExist as dne:
|
||||||
raise Http404(_(f"wishlist {wishlist_uuid} not found"))
|
raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
|
||||||
|
|
||||||
|
|
||||||
class RemoveWishlistProduct(BaseMutation):
|
class RemoveWishlistProduct(BaseMutation):
|
||||||
|
|
@ -371,8 +371,8 @@ class RemoveWishlistProduct(BaseMutation):
|
||||||
|
|
||||||
return RemoveWishlistProduct(wishlist=wishlist)
|
return RemoveWishlistProduct(wishlist=wishlist)
|
||||||
|
|
||||||
except Wishlist.DoesNotExist:
|
except Wishlist.DoesNotExist as dne:
|
||||||
raise Http404(_(f"wishlist {wishlist_uuid} not found"))
|
raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
|
||||||
|
|
||||||
|
|
||||||
class RemoveAllWishlistProducts(BaseMutation):
|
class RemoveAllWishlistProducts(BaseMutation):
|
||||||
|
|
@ -398,8 +398,8 @@ class RemoveAllWishlistProducts(BaseMutation):
|
||||||
|
|
||||||
return RemoveAllWishlistProducts(wishlist=wishlist)
|
return RemoveAllWishlistProducts(wishlist=wishlist)
|
||||||
|
|
||||||
except Wishlist.DoesNotExist:
|
except Wishlist.DoesNotExist as dne:
|
||||||
raise Http404(_(f"wishlist {wishlist_uuid} not found"))
|
raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
|
||||||
|
|
||||||
|
|
||||||
class BuyWishlist(BaseMutation):
|
class BuyWishlist(BaseMutation):
|
||||||
|
|
@ -441,8 +441,8 @@ class BuyWishlist(BaseMutation):
|
||||||
case _:
|
case _:
|
||||||
raise TypeError(_(f"wrong type came from order.buy() method: {type(instance)!s}"))
|
raise TypeError(_(f"wrong type came from order.buy() method: {type(instance)!s}"))
|
||||||
|
|
||||||
except Wishlist.DoesNotExist:
|
except Wishlist.DoesNotExist as dne:
|
||||||
raise Http404(_(f"wishlist {wishlist_uuid} not found"))
|
raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
|
||||||
|
|
||||||
|
|
||||||
class BuyProduct(BaseMutation):
|
class BuyProduct(BaseMutation):
|
||||||
|
|
@ -575,9 +575,9 @@ class DeleteAddress(BaseMutation):
|
||||||
|
|
||||||
raise PermissionDenied(permission_denied_message)
|
raise PermissionDenied(permission_denied_message)
|
||||||
|
|
||||||
except Address.DoesNotExist:
|
except Address.DoesNotExist as dne:
|
||||||
name = "Address"
|
name = "Address"
|
||||||
raise Http404(_(f"{name} does not exist: {uuid}"))
|
raise Http404(_(f"{name} does not exist: {uuid}")) from dne
|
||||||
|
|
||||||
|
|
||||||
class AutocompleteAddress(BaseMutation):
|
class AutocompleteAddress(BaseMutation):
|
||||||
|
|
|
||||||
|
|
@ -443,7 +443,7 @@ class PromoCodeType(DjangoObjectType):
|
||||||
description = _("promocodes")
|
description = _("promocodes")
|
||||||
|
|
||||||
def resolve_discount(self: PromoCode, _info) -> float:
|
def resolve_discount(self: PromoCode, _info) -> float:
|
||||||
return float(self.discount_percent) if self.discount_percent else float(self.discount_amount)
|
return float(self.discount_percent) if self.discount_percent else float(self.discount_amount) # type: ignore [arg-type]
|
||||||
|
|
||||||
def resolve_discount_type(self: PromoCode, _info) -> str:
|
def resolve_discount_type(self: PromoCode, _info) -> str:
|
||||||
return "percent" if self.discount_percent else "amount"
|
return "percent" if self.discount_percent else "amount"
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ def load_po_sanitized(path: str) -> polib.POFile:
|
||||||
with open(path, encoding="utf-8") as f:
|
with open(path, encoding="utf-8") as f:
|
||||||
text = f.read()
|
text = f.read()
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
raise CommandError(f"{path}: cannot read file ({e})")
|
raise CommandError(f"{path}: cannot read file ({e})") from e
|
||||||
# fix fuzzy flags and empty header entries
|
# fix fuzzy flags and empty header entries
|
||||||
text = re.sub(r"^#,(?!\s)", "#, ", text, flags=re.MULTILINE)
|
text = re.sub(r"^#,(?!\s)", "#, ", text, flags=re.MULTILINE)
|
||||||
parts = text.split("\n\n", 1)
|
parts = text.split("\n\n", 1)
|
||||||
|
|
@ -54,7 +54,7 @@ def load_po_sanitized(path: str) -> polib.POFile:
|
||||||
tmp.close()
|
tmp.close()
|
||||||
return polib.pofile(tmp.name)
|
return polib.pofile(tmp.name)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise CommandError(f"{path}: syntax error after sanitization ({e})")
|
raise CommandError(f"{path}: syntax error after sanitization ({e})") from e
|
||||||
finally:
|
finally:
|
||||||
with contextlib.suppress(OSError):
|
with contextlib.suppress(OSError):
|
||||||
os.unlink(tmp.name)
|
os.unlink(tmp.name)
|
||||||
|
|
@ -97,7 +97,8 @@ class Command(BaseCommand):
|
||||||
root_path: str = options.get("root_path") or "/app/"
|
root_path: str = options.get("root_path") or "/app/"
|
||||||
|
|
||||||
configs = list(apps.get_app_configs())
|
configs = list(apps.get_app_configs())
|
||||||
configs.append(RootDirectory())
|
# noinspection PyTypeChecker
|
||||||
|
configs.append(RootDirectory()) # type: ignore [arg-type]
|
||||||
|
|
||||||
for app_conf in configs:
|
for app_conf in configs:
|
||||||
if app_conf.label not in apps_to_scan:
|
if app_conf.label not in apps_to_scan:
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,8 @@ class Command(BaseCommand):
|
||||||
self.stdout.write(self.style.MIGRATE_HEADING(f"→ Translating into {target_lang}"))
|
self.stdout.write(self.style.MIGRATE_HEADING(f"→ Translating into {target_lang}"))
|
||||||
|
|
||||||
configs = list(apps.get_app_configs())
|
configs = list(apps.get_app_configs())
|
||||||
configs.append(RootDirectory())
|
# noinspection PyTypeChecker
|
||||||
|
configs.append(RootDirectory()) # type: ignore [arg-type]
|
||||||
|
|
||||||
for app_conf in configs:
|
for app_conf in configs:
|
||||||
if app_conf.label not in target_apps:
|
if app_conf.label not in target_apps:
|
||||||
|
|
@ -212,8 +213,8 @@ class Command(BaseCommand):
|
||||||
|
|
||||||
protected = []
|
protected = []
|
||||||
maps: list[list[str]] = []
|
maps: list[list[str]] = []
|
||||||
for e in to_trans:
|
for entry in to_trans:
|
||||||
txt = source_map[e.msgid]
|
txt = source_map[entry.msgid]
|
||||||
p_txt, p_map = placeholderize(txt)
|
p_txt, p_map = placeholderize(txt)
|
||||||
protected.append(p_txt)
|
protected.append(p_txt)
|
||||||
maps.append(p_map)
|
maps.append(p_map)
|
||||||
|
|
@ -227,14 +228,14 @@ class Command(BaseCommand):
|
||||||
resp.raise_for_status()
|
resp.raise_for_status()
|
||||||
result = resp.json()
|
result = resp.json()
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
raise CommandError(f"DeepL error: {exc} – {resp.text}")
|
raise CommandError(f"DeepL error: {exc} – {resp.text}") from exc
|
||||||
|
|
||||||
trans = result.get("translations", [])
|
trans = result.get("translations", [])
|
||||||
if len(trans) != len(to_trans):
|
if len(trans) != len(to_trans):
|
||||||
raise CommandError(f"Got {len(trans)} translations, expected {len(to_trans)}")
|
raise CommandError(f"Got {len(trans)} translations, expected {len(to_trans)}")
|
||||||
|
|
||||||
for e, obj, pmap in zip(to_trans, trans, maps, strict=True):
|
for entry, obj, pmap in zip(to_trans, trans, maps, strict=True):
|
||||||
e.msgstr = deplaceholderize(obj["text"], pmap)
|
entry.msgstr = deplaceholderize(obj["text"], pmap)
|
||||||
|
|
||||||
new_po.save(tgt_path)
|
new_po.save(tgt_path)
|
||||||
self.stdout.write(self.style.SUCCESS(f"Saved {tgt_path}"))
|
self.stdout.write(self.style.SUCCESS(f"Saved {tgt_path}"))
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ class Command(BaseCommand):
|
||||||
for product in Product.objects.filter(stocks__isnull=False):
|
for product in Product.objects.filter(stocks__isnull=False):
|
||||||
for stock in product.stocks.all():
|
for stock in product.stocks.all():
|
||||||
try:
|
try:
|
||||||
stock.price = AbstractVendor.round_price_marketologically(stock.price) # type: ignore
|
stock.price = AbstractVendor.round_price_marketologically(stock.price)
|
||||||
stock.save()
|
stock.save()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.stdout.write(self.style.WARNING(f"Couldn't fix price on {stock.uuid}"))
|
self.stdout.write(self.style.WARNING(f"Couldn't fix price on {stock.uuid}"))
|
||||||
|
|
|
||||||
|
|
@ -61,16 +61,16 @@ class Command(BaseCommand):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
module_path, model_name, field_name = target.rsplit(".", 2)
|
module_path, model_name, field_name = target.rsplit(".", 2)
|
||||||
except ValueError:
|
except ValueError as e:
|
||||||
raise CommandError(
|
raise CommandError(
|
||||||
"Invalid target format. Use app.module.Model.field, e.g. core.models.Product.description"
|
"Invalid target format. Use app.module.Model.field, e.g. core.models.Product.description"
|
||||||
)
|
) from e
|
||||||
|
|
||||||
try:
|
try:
|
||||||
module = importlib.import_module(module_path)
|
module = importlib.import_module(module_path)
|
||||||
model = getattr(module, model_name)
|
model = getattr(module, model_name)
|
||||||
except (ImportError, AttributeError) as e:
|
except (ImportError, AttributeError) as e:
|
||||||
raise CommandError(f"Could not import model '{model_name}' from '{module_path}': {e}")
|
raise CommandError(f"Could not import model '{model_name}' from '{module_path}': {e}") from e
|
||||||
|
|
||||||
dest_suffix = lang.replace("-", "_")
|
dest_suffix = lang.replace("-", "_")
|
||||||
dest_field = f"{field_name}_{dest_suffix}"
|
dest_field = f"{field_name}_{dest_suffix}"
|
||||||
|
|
|
||||||
|
|
@ -9,20 +9,20 @@ logger = logging.getLogger("evibes")
|
||||||
|
|
||||||
|
|
||||||
class AddressManager(models.Manager):
|
class AddressManager(models.Manager):
|
||||||
def create(self, raw_data: str, **kwargs): # type: ignore
|
def create(self, **kwargs):
|
||||||
if not raw_data:
|
if not kwargs.get("raw_data"):
|
||||||
raise ValueError("'raw_data' (address string) must be provided.")
|
raise ValueError("'raw_data' (address string) must be provided.")
|
||||||
|
|
||||||
params: dict[str, str | int] = {
|
params: dict[str, str | int] = { # type: ignore [annotation-unchecked]
|
||||||
"format": "json",
|
"format": "json",
|
||||||
"addressdetails": 1,
|
"addressdetails": 1,
|
||||||
"q": raw_data,
|
"q": kwargs.get("raw_data"),
|
||||||
}
|
}
|
||||||
resp = requests.get(config.NOMINATIM_URL.rstrip("/") + "/search", params=params)
|
resp = requests.get(config.NOMINATIM_URL.rstrip("/") + "/search", params=params)
|
||||||
resp.raise_for_status()
|
resp.raise_for_status()
|
||||||
results = resp.json()
|
results = resp.json()
|
||||||
if not results:
|
if not results:
|
||||||
raise ValueError(f"No geocoding result for address: {raw_data}")
|
raise ValueError(f"No geocoding result for address: {kwargs.get('raw_data')}")
|
||||||
data = results[0]
|
data = results[0]
|
||||||
|
|
||||||
addr = data.get("address", {})
|
addr = data.get("address", {})
|
||||||
|
|
@ -51,7 +51,7 @@ class AddressManager(models.Manager):
|
||||||
address_line_2 = ""
|
address_line_2 = ""
|
||||||
|
|
||||||
return super().get_or_create(
|
return super().get_or_create(
|
||||||
raw_data=raw_data,
|
raw_data=kwargs.get("raw_data"),
|
||||||
address_line=f"{address_line_1}, {address_line_2}",
|
address_line=f"{address_line_1}, {address_line_2}",
|
||||||
street=street,
|
street=street,
|
||||||
district=district,
|
district=district,
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -7,101 +7,205 @@ from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('core', '0001_initial'),
|
("core", "0001_initial"),
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='order',
|
model_name="order",
|
||||||
name='user',
|
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'),
|
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(
|
migrations.AddField(
|
||||||
model_name='orderproduct',
|
model_name="orderproduct",
|
||||||
name='order',
|
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'),
|
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(
|
migrations.AddField(
|
||||||
model_name='feedback',
|
model_name="feedback",
|
||||||
name='order_product',
|
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'),
|
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(
|
migrations.AddField(
|
||||||
model_name='product',
|
model_name="product",
|
||||||
name='brand',
|
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'),
|
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(
|
migrations.AddField(
|
||||||
model_name='product',
|
model_name="product",
|
||||||
name='category',
|
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'),
|
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(
|
migrations.AddField(
|
||||||
model_name='orderproduct',
|
model_name="orderproduct",
|
||||||
name='product',
|
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'),
|
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(
|
migrations.AddField(
|
||||||
model_name='attributevalue',
|
model_name="attributevalue",
|
||||||
name='product',
|
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'),
|
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(
|
migrations.AddField(
|
||||||
model_name='productimage',
|
model_name="productimage",
|
||||||
name='product',
|
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'),
|
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(
|
migrations.AddField(
|
||||||
model_name='product',
|
model_name="product",
|
||||||
name='tags',
|
name="tags",
|
||||||
field=models.ManyToManyField(blank=True, help_text='tags that help describe or group this product', to='core.producttag', verbose_name='product 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(
|
migrations.AddField(
|
||||||
model_name='promocode',
|
model_name="promocode",
|
||||||
name='user',
|
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'),
|
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(
|
migrations.AddField(
|
||||||
model_name='order',
|
model_name="order",
|
||||||
name='promo_code',
|
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'),
|
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(
|
migrations.AddField(
|
||||||
model_name='promotion',
|
model_name="promotion",
|
||||||
name='products',
|
name="products",
|
||||||
field=models.ManyToManyField(blank=True, help_text='select which products are included in this promotion', to='core.product', verbose_name='included 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(
|
migrations.AddField(
|
||||||
model_name='stock',
|
model_name="stock",
|
||||||
name='product',
|
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'),
|
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(
|
migrations.AddIndex(
|
||||||
model_name='vendor',
|
model_name="vendor",
|
||||||
index=django.contrib.postgres.indexes.GinIndex(fields=['authentication'], name='core_vendor_authent_80dc1f_gin'),
|
index=django.contrib.postgres.indexes.GinIndex(
|
||||||
|
fields=["authentication"], name="core_vendor_authent_80dc1f_gin"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='stock',
|
model_name="stock",
|
||||||
name='vendor',
|
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'),
|
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(
|
migrations.AddField(
|
||||||
model_name='wishlist',
|
model_name="wishlist",
|
||||||
name='products',
|
name="products",
|
||||||
field=models.ManyToManyField(blank=True, help_text='products that the user has marked as wanted', to='core.product', verbose_name='wishlisted 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(
|
migrations.AddField(
|
||||||
model_name='wishlist',
|
model_name="wishlist",
|
||||||
name='user',
|
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'),
|
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(
|
migrations.AddIndex(
|
||||||
model_name='orderproduct',
|
model_name="orderproduct",
|
||||||
index=django.contrib.postgres.indexes.GinIndex(fields=['notifications', 'attributes'], name='core_orderp_notific_cd27e9_gin'),
|
index=django.contrib.postgres.indexes.GinIndex(
|
||||||
|
fields=["notifications", "attributes"], name="core_orderp_notific_cd27e9_gin"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -4,105 +4,198 @@ from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('core', '0003_alter_attribute_name_alter_attribute_name_ar_ar_and_more'),
|
("core", "0003_alter_attribute_name_alter_attribute_name_ar_ar_and_more"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='product',
|
model_name="product",
|
||||||
name='name',
|
name="name",
|
||||||
field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, verbose_name='product name'),
|
field=models.CharField(
|
||||||
|
help_text="provide a clear identifying name for the product",
|
||||||
|
max_length=255,
|
||||||
|
verbose_name="product name",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='product',
|
model_name="product",
|
||||||
name='name_ar_AR',
|
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'),
|
field=models.CharField(
|
||||||
|
help_text="provide a clear identifying name for the product",
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="product name",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='product',
|
model_name="product",
|
||||||
name='name_cs_CZ',
|
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'),
|
field=models.CharField(
|
||||||
|
help_text="provide a clear identifying name for the product",
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="product name",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='product',
|
model_name="product",
|
||||||
name='name_da_DK',
|
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'),
|
field=models.CharField(
|
||||||
|
help_text="provide a clear identifying name for the product",
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="product name",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='product',
|
model_name="product",
|
||||||
name='name_de_DE',
|
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'),
|
field=models.CharField(
|
||||||
|
help_text="provide a clear identifying name for the product",
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="product name",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='product',
|
model_name="product",
|
||||||
name='name_en_GB',
|
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'),
|
field=models.CharField(
|
||||||
|
help_text="provide a clear identifying name for the product",
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="product name",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='product',
|
model_name="product",
|
||||||
name='name_en_US',
|
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'),
|
field=models.CharField(
|
||||||
|
help_text="provide a clear identifying name for the product",
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="product name",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='product',
|
model_name="product",
|
||||||
name='name_es_ES',
|
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'),
|
field=models.CharField(
|
||||||
|
help_text="provide a clear identifying name for the product",
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="product name",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='product',
|
model_name="product",
|
||||||
name='name_fr_FR',
|
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'),
|
field=models.CharField(
|
||||||
|
help_text="provide a clear identifying name for the product",
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="product name",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='product',
|
model_name="product",
|
||||||
name='name_hi_IN',
|
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'),
|
field=models.CharField(
|
||||||
|
help_text="provide a clear identifying name for the product",
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="product name",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='product',
|
model_name="product",
|
||||||
name='name_it_IT',
|
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'),
|
field=models.CharField(
|
||||||
|
help_text="provide a clear identifying name for the product",
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="product name",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='product',
|
model_name="product",
|
||||||
name='name_ja_JP',
|
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'),
|
field=models.CharField(
|
||||||
|
help_text="provide a clear identifying name for the product",
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="product name",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='product',
|
model_name="product",
|
||||||
name='name_kk_KZ',
|
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'),
|
field=models.CharField(
|
||||||
|
help_text="provide a clear identifying name for the product",
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="product name",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='product',
|
model_name="product",
|
||||||
name='name_nl_NL',
|
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'),
|
field=models.CharField(
|
||||||
|
help_text="provide a clear identifying name for the product",
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="product name",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='product',
|
model_name="product",
|
||||||
name='name_pl_PL',
|
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'),
|
field=models.CharField(
|
||||||
|
help_text="provide a clear identifying name for the product",
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="product name",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='product',
|
model_name="product",
|
||||||
name='name_pt_BR',
|
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'),
|
field=models.CharField(
|
||||||
|
help_text="provide a clear identifying name for the product",
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="product name",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='product',
|
model_name="product",
|
||||||
name='name_ro_RO',
|
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'),
|
field=models.CharField(
|
||||||
|
help_text="provide a clear identifying name for the product",
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="product name",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='product',
|
model_name="product",
|
||||||
name='name_ru_RU',
|
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'),
|
field=models.CharField(
|
||||||
|
help_text="provide a clear identifying name for the product",
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="product name",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='product',
|
model_name="product",
|
||||||
name='name_zh_hans',
|
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'),
|
field=models.CharField(
|
||||||
|
help_text="provide a clear identifying name for the product",
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="product name",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -4,19 +4,23 @@ from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('core', '0004_alter_product_name_alter_product_name_ar_ar_and_more'),
|
("core", "0004_alter_product_name_alter_product_name_ar_ar_and_more"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.RemoveField(
|
migrations.RemoveField(
|
||||||
model_name='brand',
|
model_name="brand",
|
||||||
name='category',
|
name="category",
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='brand',
|
model_name="brand",
|
||||||
name='categories',
|
name="categories",
|
||||||
field=models.ManyToManyField(blank=True, help_text='optional categories that this brand is associated with', to='core.category', verbose_name='associated categories'),
|
field=models.ManyToManyField(
|
||||||
|
blank=True,
|
||||||
|
help_text="optional categories that this brand is associated with",
|
||||||
|
to="core.category",
|
||||||
|
verbose_name="associated categories",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -4,15 +4,28 @@ from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('core', '0005_remove_brand_category_brand_categories'),
|
("core", "0005_remove_brand_category_brand_categories"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='order',
|
model_name="order",
|
||||||
name='status',
|
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'),
|
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",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -7,16 +7,20 @@ import core.validators
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('core', '0006_alter_order_status'),
|
("core", "0006_alter_order_status"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='category',
|
model_name="category",
|
||||||
name='image',
|
name="image",
|
||||||
field=models.ImageField(blank=True, help_text='upload an image representing this category', null=True,
|
field=models.ImageField(
|
||||||
upload_to='categories/',
|
blank=True,
|
||||||
|
help_text="upload an image representing this category",
|
||||||
|
null=True,
|
||||||
|
upload_to="categories/",
|
||||||
validators=[core.validators.validate_category_image_dimensions],
|
validators=[core.validators.validate_category_image_dimensions],
|
||||||
verbose_name='category image'),
|
verbose_name="category image",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -9,33 +9,57 @@ from django.db import migrations, models
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('core', '0007_alter_category_image'),
|
("core", "0007_alter_category_image"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='DigitalAssetDownload',
|
name="DigitalAssetDownload",
|
||||||
fields=[
|
fields=[
|
||||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
|
(
|
||||||
help_text='unique id is used to surely identify any database object',
|
"uuid",
|
||||||
primary_key=True, serialize=False, verbose_name='unique id')),
|
models.UUIDField(
|
||||||
('is_active', models.BooleanField(default=True,
|
default=uuid.uuid4,
|
||||||
|
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",
|
help_text="if set to false, this object can't be seen by users without needed permission",
|
||||||
verbose_name='is active')),
|
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,
|
"created",
|
||||||
help_text='when the object was last modified',
|
django_extensions.db.fields.CreationDateTimeField(
|
||||||
verbose_name='modified')),
|
auto_now_add=True,
|
||||||
('num_downloads', models.IntegerField(default=0)),
|
help_text="when the object first appeared on the database",
|
||||||
('order_product',
|
verbose_name="created",
|
||||||
models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='download',
|
),
|
||||||
to='core.orderproduct')),
|
),
|
||||||
|
(
|
||||||
|
"modified",
|
||||||
|
django_extensions.db.fields.ModificationDateTimeField(
|
||||||
|
auto_now=True, help_text="when the object was last modified", verbose_name="modified"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("num_downloads", models.IntegerField(default=0)),
|
||||||
|
(
|
||||||
|
"order_product",
|
||||||
|
models.OneToOneField(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE, related_name="download", to="core.orderproduct"
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'download',
|
"verbose_name": "download",
|
||||||
'verbose_name_plural': 'downloads',
|
"verbose_name_plural": "downloads",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -11,32 +11,57 @@ import core.utils
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('core', '0008_digitalassetdownload'),
|
("core", "0008_digitalassetdownload"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Documentary',
|
name="Documentary",
|
||||||
fields=[
|
fields=[
|
||||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
|
(
|
||||||
help_text='unique id is used to surely identify any database object',
|
"uuid",
|
||||||
primary_key=True, serialize=False, verbose_name='unique id')),
|
models.UUIDField(
|
||||||
('is_active', models.BooleanField(default=True,
|
default=uuid.uuid4,
|
||||||
|
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",
|
help_text="if set to false, this object can't be seen by users without needed permission",
|
||||||
verbose_name='is active')),
|
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,
|
"created",
|
||||||
help_text='when the object was last modified',
|
django_extensions.db.fields.CreationDateTimeField(
|
||||||
verbose_name='modified')),
|
auto_now_add=True,
|
||||||
('document', models.FileField(upload_to=core.utils.get_product_uuid_as_path)),
|
help_text="when the object first appeared on the database",
|
||||||
('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='documentaries',
|
verbose_name="created",
|
||||||
to='core.product')),
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"modified",
|
||||||
|
django_extensions.db.fields.ModificationDateTimeField(
|
||||||
|
auto_now=True, help_text="when the object was last modified", verbose_name="modified"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("document", models.FileField(upload_to=core.utils.get_product_uuid_as_path)),
|
||||||
|
(
|
||||||
|
"product",
|
||||||
|
models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE, related_name="documentaries", to="core.product"
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'documentary',
|
"verbose_name": "documentary",
|
||||||
'verbose_name_plural': 'documentaries',
|
"verbose_name_plural": "documentaries",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -4,15 +4,20 @@ from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('core', '0009_documentary'),
|
("core", "0009_documentary"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='product',
|
model_name="product",
|
||||||
name='partnumber',
|
name="partnumber",
|
||||||
field=models.CharField(default=None, help_text='part number for this product', null=True, unique=True, verbose_name='part number'),
|
field=models.CharField(
|
||||||
|
default=None,
|
||||||
|
help_text="part number for this product",
|
||||||
|
null=True,
|
||||||
|
unique=True,
|
||||||
|
verbose_name="part number",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -7,138 +7,222 @@ import core.validators
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('core', '0010_product_partnumber'),
|
("core", "0010_product_partnumber"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='brand',
|
model_name="brand",
|
||||||
name='big_logo',
|
name="big_logo",
|
||||||
field=models.ImageField(blank=True, help_text='upload a big logo representing this brand', null=True,
|
field=models.ImageField(
|
||||||
upload_to='brands/',
|
blank=True,
|
||||||
|
help_text="upload a big logo representing this brand",
|
||||||
|
null=True,
|
||||||
|
upload_to="brands/",
|
||||||
validators=[core.validators.validate_category_image_dimensions],
|
validators=[core.validators.validate_category_image_dimensions],
|
||||||
verbose_name='brand big image'),
|
verbose_name="brand big image",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='brand',
|
model_name="brand",
|
||||||
name='description',
|
name="description",
|
||||||
field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
|
field=models.TextField(
|
||||||
verbose_name='brand description'),
|
blank=True,
|
||||||
|
help_text="add a detailed description of the brand",
|
||||||
|
null=True,
|
||||||
|
verbose_name="brand description",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='brand',
|
model_name="brand",
|
||||||
name='description_ar_AR',
|
name="description_ar_AR",
|
||||||
field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
|
field=models.TextField(
|
||||||
verbose_name='brand description'),
|
blank=True,
|
||||||
|
help_text="add a detailed description of the brand",
|
||||||
|
null=True,
|
||||||
|
verbose_name="brand description",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='brand',
|
model_name="brand",
|
||||||
name='description_cs_CZ',
|
name="description_cs_CZ",
|
||||||
field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
|
field=models.TextField(
|
||||||
verbose_name='brand description'),
|
blank=True,
|
||||||
|
help_text="add a detailed description of the brand",
|
||||||
|
null=True,
|
||||||
|
verbose_name="brand description",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='brand',
|
model_name="brand",
|
||||||
name='description_da_DK',
|
name="description_da_DK",
|
||||||
field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
|
field=models.TextField(
|
||||||
verbose_name='brand description'),
|
blank=True,
|
||||||
|
help_text="add a detailed description of the brand",
|
||||||
|
null=True,
|
||||||
|
verbose_name="brand description",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='brand',
|
model_name="brand",
|
||||||
name='description_de_DE',
|
name="description_de_DE",
|
||||||
field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
|
field=models.TextField(
|
||||||
verbose_name='brand description'),
|
blank=True,
|
||||||
|
help_text="add a detailed description of the brand",
|
||||||
|
null=True,
|
||||||
|
verbose_name="brand description",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='brand',
|
model_name="brand",
|
||||||
name='description_en_GB',
|
name="description_en_GB",
|
||||||
field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
|
field=models.TextField(
|
||||||
verbose_name='brand description'),
|
blank=True,
|
||||||
|
help_text="add a detailed description of the brand",
|
||||||
|
null=True,
|
||||||
|
verbose_name="brand description",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='brand',
|
model_name="brand",
|
||||||
name='description_en_US',
|
name="description_en_US",
|
||||||
field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
|
field=models.TextField(
|
||||||
verbose_name='brand description'),
|
blank=True,
|
||||||
|
help_text="add a detailed description of the brand",
|
||||||
|
null=True,
|
||||||
|
verbose_name="brand description",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='brand',
|
model_name="brand",
|
||||||
name='description_es_ES',
|
name="description_es_ES",
|
||||||
field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
|
field=models.TextField(
|
||||||
verbose_name='brand description'),
|
blank=True,
|
||||||
|
help_text="add a detailed description of the brand",
|
||||||
|
null=True,
|
||||||
|
verbose_name="brand description",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='brand',
|
model_name="brand",
|
||||||
name='description_fr_FR',
|
name="description_fr_FR",
|
||||||
field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
|
field=models.TextField(
|
||||||
verbose_name='brand description'),
|
blank=True,
|
||||||
|
help_text="add a detailed description of the brand",
|
||||||
|
null=True,
|
||||||
|
verbose_name="brand description",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='brand',
|
model_name="brand",
|
||||||
name='description_hi_IN',
|
name="description_hi_IN",
|
||||||
field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
|
field=models.TextField(
|
||||||
verbose_name='brand description'),
|
blank=True,
|
||||||
|
help_text="add a detailed description of the brand",
|
||||||
|
null=True,
|
||||||
|
verbose_name="brand description",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='brand',
|
model_name="brand",
|
||||||
name='description_it_IT',
|
name="description_it_IT",
|
||||||
field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
|
field=models.TextField(
|
||||||
verbose_name='brand description'),
|
blank=True,
|
||||||
|
help_text="add a detailed description of the brand",
|
||||||
|
null=True,
|
||||||
|
verbose_name="brand description",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='brand',
|
model_name="brand",
|
||||||
name='description_ja_JP',
|
name="description_ja_JP",
|
||||||
field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
|
field=models.TextField(
|
||||||
verbose_name='brand description'),
|
blank=True,
|
||||||
|
help_text="add a detailed description of the brand",
|
||||||
|
null=True,
|
||||||
|
verbose_name="brand description",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='brand',
|
model_name="brand",
|
||||||
name='description_kk_KZ',
|
name="description_kk_KZ",
|
||||||
field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
|
field=models.TextField(
|
||||||
verbose_name='brand description'),
|
blank=True,
|
||||||
|
help_text="add a detailed description of the brand",
|
||||||
|
null=True,
|
||||||
|
verbose_name="brand description",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='brand',
|
model_name="brand",
|
||||||
name='description_nl_NL',
|
name="description_nl_NL",
|
||||||
field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
|
field=models.TextField(
|
||||||
verbose_name='brand description'),
|
blank=True,
|
||||||
|
help_text="add a detailed description of the brand",
|
||||||
|
null=True,
|
||||||
|
verbose_name="brand description",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='brand',
|
model_name="brand",
|
||||||
name='description_pl_PL',
|
name="description_pl_PL",
|
||||||
field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
|
field=models.TextField(
|
||||||
verbose_name='brand description'),
|
blank=True,
|
||||||
|
help_text="add a detailed description of the brand",
|
||||||
|
null=True,
|
||||||
|
verbose_name="brand description",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='brand',
|
model_name="brand",
|
||||||
name='description_pt_BR',
|
name="description_pt_BR",
|
||||||
field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
|
field=models.TextField(
|
||||||
verbose_name='brand description'),
|
blank=True,
|
||||||
|
help_text="add a detailed description of the brand",
|
||||||
|
null=True,
|
||||||
|
verbose_name="brand description",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='brand',
|
model_name="brand",
|
||||||
name='description_ro_RO',
|
name="description_ro_RO",
|
||||||
field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
|
field=models.TextField(
|
||||||
verbose_name='brand description'),
|
blank=True,
|
||||||
|
help_text="add a detailed description of the brand",
|
||||||
|
null=True,
|
||||||
|
verbose_name="brand description",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='brand',
|
model_name="brand",
|
||||||
name='description_ru_RU',
|
name="description_ru_RU",
|
||||||
field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
|
field=models.TextField(
|
||||||
verbose_name='brand description'),
|
blank=True,
|
||||||
|
help_text="add a detailed description of the brand",
|
||||||
|
null=True,
|
||||||
|
verbose_name="brand description",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='brand',
|
model_name="brand",
|
||||||
name='description_zh_hans',
|
name="description_zh_hans",
|
||||||
field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
|
field=models.TextField(
|
||||||
verbose_name='brand description'),
|
blank=True,
|
||||||
|
help_text="add a detailed description of the brand",
|
||||||
|
null=True,
|
||||||
|
verbose_name="brand description",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='brand',
|
model_name="brand",
|
||||||
name='small_logo',
|
name="small_logo",
|
||||||
field=models.ImageField(blank=True, help_text='upload a logo representing this brand', null=True,
|
field=models.ImageField(
|
||||||
upload_to='brands/',
|
blank=True,
|
||||||
|
help_text="upload a logo representing this brand",
|
||||||
|
null=True,
|
||||||
|
upload_to="brands/",
|
||||||
validators=[core.validators.validate_category_image_dimensions],
|
validators=[core.validators.validate_category_image_dimensions],
|
||||||
verbose_name='brand small image'),
|
verbose_name="brand small image",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -6,16 +6,23 @@ from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('core', '0011_brand_big_logo_brand_description_and_more'),
|
("core", "0011_brand_big_logo_brand_description_and_more"),
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='order',
|
model_name="order",
|
||||||
name='user',
|
name="user",
|
||||||
field=models.ForeignKey(blank=True, help_text='the user who placed the order', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='orders', to=settings.AUTH_USER_MODEL, verbose_name='user'),
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
help_text="the user who placed the order",
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="orders",
|
||||||
|
to=settings.AUTH_USER_MODEL,
|
||||||
|
verbose_name="user",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,21 @@ from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('core', '0012_alter_order_user'),
|
("core", "0012_alter_order_user"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='product',
|
model_name="product",
|
||||||
name='slug',
|
name="slug",
|
||||||
field=django_extensions.db.fields.AutoSlugField(allow_unicode=True, null=True, blank=True, editable=False, populate_from=('category.name', 'brand.name', 'name'), unique=True),
|
field=django_extensions.db.fields.AutoSlugField(
|
||||||
|
allow_unicode=True,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
editable=False,
|
||||||
|
populate_from=("category.name", "brand.name", "name"),
|
||||||
|
unique=True,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,21 @@ from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('core', '0013_product_slug'),
|
("core", "0013_product_slug"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='product',
|
model_name="product",
|
||||||
name='slug',
|
name="slug",
|
||||||
field=django_extensions.db.fields.AutoSlugField(allow_unicode=True, blank=True, editable=False, null=True, populate_from=('uuid', 'category.name', 'brand.name', 'name'), unique=True),
|
field=django_extensions.db.fields.AutoSlugField(
|
||||||
|
allow_unicode=True,
|
||||||
|
blank=True,
|
||||||
|
editable=False,
|
||||||
|
null=True,
|
||||||
|
populate_from=("uuid", "category.name", "brand.name", "name"),
|
||||||
|
unique=True,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,21 @@ from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('core', '0014_alter_product_slug'),
|
("core", "0014_alter_product_slug"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='product',
|
model_name="product",
|
||||||
name='slug',
|
name="slug",
|
||||||
field=django_extensions.db.fields.AutoSlugField(allow_unicode=True, blank=True, editable=False, null=True, populate_from=('category__name', 'name'), unique=True),
|
field=django_extensions.db.fields.AutoSlugField(
|
||||||
|
allow_unicode=True,
|
||||||
|
blank=True,
|
||||||
|
editable=False,
|
||||||
|
null=True,
|
||||||
|
populate_from=("category__name", "name"),
|
||||||
|
unique=True,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,21 @@ from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('core', '0015_alter_product_slug'),
|
("core", "0015_alter_product_slug"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='product',
|
model_name="product",
|
||||||
name='slug',
|
name="slug",
|
||||||
field=django_extensions.db.fields.AutoSlugField(allow_unicode=True, blank=True, editable=False, null=True, populate_from=('uuid', 'category__name', 'name'), unique=True),
|
field=django_extensions.db.fields.AutoSlugField(
|
||||||
|
allow_unicode=True,
|
||||||
|
blank=True,
|
||||||
|
editable=False,
|
||||||
|
null=True,
|
||||||
|
populate_from=("uuid", "category__name", "name"),
|
||||||
|
unique=True,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -7,15 +7,18 @@ import core.utils
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('core', '0016_alter_product_slug'),
|
("core", "0016_alter_product_slug"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='order',
|
model_name="order",
|
||||||
name='human_readable_id',
|
name="human_readable_id",
|
||||||
field=models.CharField(default=core.utils.generate_human_readable_id,
|
field=models.CharField(
|
||||||
help_text='a human-readable identifier for the order', max_length=8,
|
default=core.utils.generate_human_readable_id,
|
||||||
verbose_name='human readable id'),
|
help_text="a human-readable identifier for the order",
|
||||||
|
max_length=8,
|
||||||
|
verbose_name="human readable id",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,7 @@ def fix_duplicates(apps, schema_editor):
|
||||||
if schema_editor:
|
if schema_editor:
|
||||||
pass
|
pass
|
||||||
Order = apps.get_model("core", "Order")
|
Order = apps.get_model("core", "Order")
|
||||||
duplicates = (
|
duplicates = Order.objects.values("human_readable_id").annotate(count=Count("uuid")).filter(count__gt=1)
|
||||||
Order.objects.values("human_readable_id")
|
|
||||||
.annotate(count=Count("uuid"))
|
|
||||||
.filter(count__gt=1)
|
|
||||||
)
|
|
||||||
for duplicate in duplicates:
|
for duplicate in duplicates:
|
||||||
h_id = duplicate["human_readable_id"]
|
h_id = duplicate["human_readable_id"]
|
||||||
orders = Order.objects.filter(human_readable_id=h_id).order_by("uuid")
|
orders = Order.objects.filter(human_readable_id=h_id).order_by("uuid")
|
||||||
|
|
@ -20,6 +16,7 @@ def fix_duplicates(apps, schema_editor):
|
||||||
new_id = order.human_readable_id
|
new_id = order.human_readable_id
|
||||||
while Order.objects.filter(human_readable_id=new_id).exists():
|
while Order.objects.filter(human_readable_id=new_id).exists():
|
||||||
from core.utils import generate_human_readable_id
|
from core.utils import generate_human_readable_id
|
||||||
|
|
||||||
new_id = generate_human_readable_id()
|
new_id = generate_human_readable_id()
|
||||||
order.human_readable_id = new_id
|
order.human_readable_id = new_id
|
||||||
order.save()
|
order.save()
|
||||||
|
|
@ -35,16 +32,20 @@ def reverse_func(apps, schema_editor):
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('core', '0017_order_human_readable_id'),
|
("core", "0017_order_human_readable_id"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.RunPython(fix_duplicates, reverse_func),
|
migrations.RunPython(fix_duplicates, reverse_func),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='order',
|
model_name="order",
|
||||||
name='human_readable_id',
|
name="human_readable_id",
|
||||||
field=models.CharField(default=core.utils.generate_human_readable_id,
|
field=models.CharField(
|
||||||
help_text='a human-readable identifier for the order', max_length=8, unique=True,
|
default=core.utils.generate_human_readable_id,
|
||||||
verbose_name='human readable id'),
|
help_text="a human-readable identifier for the order",
|
||||||
|
max_length=8,
|
||||||
|
unique=True,
|
||||||
|
verbose_name="human readable id",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -11,46 +11,86 @@ from django.db import migrations, models
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('core', '0018_alter_order_human_readable_id'),
|
("core", "0018_alter_order_human_readable_id"),
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Address',
|
name="Address",
|
||||||
fields=[
|
fields=[
|
||||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
|
(
|
||||||
help_text='unique id is used to surely identify any database object',
|
"uuid",
|
||||||
primary_key=True, serialize=False, verbose_name='unique id')),
|
models.UUIDField(
|
||||||
('is_active', models.BooleanField(default=True,
|
default=uuid.uuid4,
|
||||||
|
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",
|
help_text="if set to false, this object can't be seen by users without needed permission",
|
||||||
verbose_name='is active')),
|
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,
|
"created",
|
||||||
help_text='when the object was last modified',
|
django_extensions.db.fields.CreationDateTimeField(
|
||||||
verbose_name='modified')),
|
auto_now_add=True,
|
||||||
('street', models.CharField(max_length=255, null=True, verbose_name='street')),
|
help_text="when the object first appeared on the database",
|
||||||
('district', models.CharField(max_length=255, null=True, verbose_name='district')),
|
verbose_name="created",
|
||||||
('city', models.CharField(max_length=100, null=True, verbose_name='city')),
|
),
|
||||||
('region', models.CharField(max_length=100, null=True, verbose_name='region')),
|
),
|
||||||
('postal_code', models.CharField(max_length=20, null=True, verbose_name='postal code')),
|
(
|
||||||
('country', models.CharField(max_length=40, null=True, verbose_name='country')),
|
"modified",
|
||||||
('location', django.contrib.gis.db.models.fields.PointField(blank=True, geography=True,
|
django_extensions.db.fields.ModificationDateTimeField(
|
||||||
help_text='geolocation point: (longitude, latitude)',
|
auto_now=True, help_text="when the object was last modified", verbose_name="modified"
|
||||||
null=True, srid=4326)),
|
),
|
||||||
('raw_data', models.JSONField(blank=True, help_text='full JSON response from geocoder for this address',
|
),
|
||||||
null=True)),
|
("street", models.CharField(max_length=255, null=True, verbose_name="street")),
|
||||||
('api_response',
|
("district", models.CharField(max_length=255, null=True, verbose_name="district")),
|
||||||
models.JSONField(blank=True, help_text='stored JSON response from the geocoding service', null=True)),
|
("city", models.CharField(max_length=100, null=True, verbose_name="city")),
|
||||||
('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE,
|
("region", models.CharField(max_length=100, null=True, verbose_name="region")),
|
||||||
to=settings.AUTH_USER_MODEL)),
|
("postal_code", models.CharField(max_length=20, null=True, verbose_name="postal code")),
|
||||||
|
("country", models.CharField(max_length=40, null=True, verbose_name="country")),
|
||||||
|
(
|
||||||
|
"location",
|
||||||
|
django.contrib.gis.db.models.fields.PointField(
|
||||||
|
blank=True,
|
||||||
|
geography=True,
|
||||||
|
help_text="geolocation point: (longitude, latitude)",
|
||||||
|
null=True,
|
||||||
|
srid=4326,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"raw_data",
|
||||||
|
models.JSONField(
|
||||||
|
blank=True, help_text="full JSON response from geocoder for this address", null=True
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"api_response",
|
||||||
|
models.JSONField(
|
||||||
|
blank=True, help_text="stored JSON response from the geocoding service", null=True
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"user",
|
||||||
|
models.ForeignKey(
|
||||||
|
blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'address',
|
"verbose_name": "address",
|
||||||
'verbose_name_plural': 'addresses',
|
"verbose_name_plural": "addresses",
|
||||||
'indexes': [models.Index(fields=['location'], name='core_addres_locatio_eb6b39_idx')],
|
"indexes": [models.Index(fields=["location"], name="core_addres_locatio_eb6b39_idx")],
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ from django.db import migrations, models
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('core', '0019_address'),
|
("core", "0019_address"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
|
@ -17,29 +17,30 @@ class Migration(migrations.Migration):
|
||||||
),
|
),
|
||||||
reverse_sql=migrations.RunSQL.noop,
|
reverse_sql=migrations.RunSQL.noop,
|
||||||
),
|
),
|
||||||
|
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='order',
|
model_name="order",
|
||||||
name='billing_address',
|
name="billing_address",
|
||||||
field=models.ForeignKey(
|
field=models.ForeignKey(
|
||||||
blank=True, null=True,
|
blank=True,
|
||||||
|
null=True,
|
||||||
on_delete=models.deletion.CASCADE,
|
on_delete=models.deletion.CASCADE,
|
||||||
related_name='billing_address_order',
|
related_name="billing_address_order",
|
||||||
to='core.address',
|
to="core.address",
|
||||||
verbose_name='billing address',
|
verbose_name="billing address",
|
||||||
help_text='the billing address used for this order',
|
help_text="the billing address used for this order",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='order',
|
model_name="order",
|
||||||
name='shipping_address',
|
name="shipping_address",
|
||||||
field=models.ForeignKey(
|
field=models.ForeignKey(
|
||||||
blank=True, null=True,
|
blank=True,
|
||||||
|
null=True,
|
||||||
on_delete=models.deletion.CASCADE,
|
on_delete=models.deletion.CASCADE,
|
||||||
related_name='shipping_address_order',
|
related_name="shipping_address_order",
|
||||||
to='core.address',
|
to="core.address",
|
||||||
verbose_name='shipping address',
|
verbose_name="shipping address",
|
||||||
help_text='the shipping address used for this order',
|
help_text="the shipping address used for this order",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -7,7 +7,7 @@ from django.db import migrations
|
||||||
def populate_slugs(apps, schema_editor):
|
def populate_slugs(apps, schema_editor):
|
||||||
if schema_editor:
|
if schema_editor:
|
||||||
pass
|
pass
|
||||||
Category = apps.get_model('core', 'Category')
|
Category = apps.get_model("core", "Category")
|
||||||
for category in Category.objects.all():
|
for category in Category.objects.all():
|
||||||
try:
|
try:
|
||||||
if not category.slug:
|
if not category.slug:
|
||||||
|
|
@ -18,15 +18,16 @@ def populate_slugs(apps, schema_editor):
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('core', '0021_rename_name_ar_ar_attribute_name_ar_ar_and_more'),
|
("core", "0021_rename_name_ar_ar_attribute_name_ar_ar_and_more"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='category',
|
model_name="category",
|
||||||
name='slug',
|
name="slug",
|
||||||
field=django_extensions.db.fields.AutoSlugField(allow_unicode=True, blank=True, editable=False, null=True,
|
field=django_extensions.db.fields.AutoSlugField(
|
||||||
populate_from=('uuid', 'name'), unique=True),
|
allow_unicode=True, blank=True, editable=False, null=True, populate_from=("uuid", "name"), unique=True
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.RunPython(populate_slugs, reverse_code=migrations.RunPython.noop),
|
migrations.RunPython(populate_slugs, reverse_code=migrations.RunPython.noop),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,15 @@ from django.db import migrations, models
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('core', '0022_category_slug'),
|
("core", "0022_category_slug"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='address',
|
model_name="address",
|
||||||
name='address_line',
|
name="address_line",
|
||||||
field=models.TextField(blank=True, help_text='address line for the customer', null=True,
|
field=models.TextField(
|
||||||
verbose_name='address line'),
|
blank=True, help_text="address line for the customer", null=True, verbose_name="address line"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -9,95 +9,256 @@ from django.db import migrations, models
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('core', '0023_address_address_line'),
|
("core", "0023_address_address_line"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='CategoryTag',
|
name="CategoryTag",
|
||||||
fields=[
|
fields=[
|
||||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
|
(
|
||||||
help_text='unique id is used to surely identify any database object',
|
"uuid",
|
||||||
primary_key=True, serialize=False, verbose_name='unique id')),
|
models.UUIDField(
|
||||||
('is_active', models.BooleanField(default=True,
|
default=uuid.uuid4,
|
||||||
|
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",
|
help_text="if set to false, this object can't be seen by users without needed permission",
|
||||||
verbose_name='is active')),
|
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,
|
"created",
|
||||||
help_text='when the object was last modified',
|
django_extensions.db.fields.CreationDateTimeField(
|
||||||
verbose_name='modified')),
|
auto_now_add=True,
|
||||||
('tag_name', models.CharField(help_text='internal tag identifier for the product tag', max_length=255,
|
help_text="when the object first appeared on the database",
|
||||||
verbose_name='tag name')),
|
verbose_name="created",
|
||||||
('name',
|
),
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, unique=True,
|
),
|
||||||
verbose_name='tag display name')),
|
(
|
||||||
('name_en_gb',
|
"modified",
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
django_extensions.db.fields.ModificationDateTimeField(
|
||||||
unique=True, verbose_name='tag display name')),
|
auto_now=True, help_text="when the object was last modified", verbose_name="modified"
|
||||||
('name_ar_ar',
|
),
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
),
|
||||||
unique=True, verbose_name='tag display name')),
|
(
|
||||||
('name_cs_cz',
|
"tag_name",
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
models.CharField(
|
||||||
unique=True, verbose_name='tag display name')),
|
help_text="internal tag identifier for the product tag", max_length=255, verbose_name="tag name"
|
||||||
('name_da_dk',
|
),
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
),
|
||||||
unique=True, verbose_name='tag display name')),
|
(
|
||||||
('name_de_de',
|
"name",
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
models.CharField(
|
||||||
unique=True, verbose_name='tag display name')),
|
help_text="user-friendly name for the product tag",
|
||||||
('name_en_us',
|
max_length=255,
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
unique=True,
|
||||||
unique=True, verbose_name='tag display name')),
|
verbose_name="tag display name",
|
||||||
('name_es_es',
|
),
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
),
|
||||||
unique=True, verbose_name='tag display name')),
|
(
|
||||||
('name_fr_fr',
|
"name_en_gb",
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
models.CharField(
|
||||||
unique=True, verbose_name='tag display name')),
|
help_text="user-friendly name for the product tag",
|
||||||
('name_hi_in',
|
max_length=255,
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
null=True,
|
||||||
unique=True, verbose_name='tag display name')),
|
unique=True,
|
||||||
('name_it_it',
|
verbose_name="tag display name",
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
),
|
||||||
unique=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,
|
"name_ar_ar",
|
||||||
unique=True, verbose_name='tag display name')),
|
models.CharField(
|
||||||
('name_kk_kz',
|
help_text="user-friendly name for the product tag",
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
max_length=255,
|
||||||
unique=True, verbose_name='tag display name')),
|
null=True,
|
||||||
('name_nl_nl',
|
unique=True,
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
verbose_name="tag display name",
|
||||||
unique=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,
|
(
|
||||||
unique=True, verbose_name='tag display name')),
|
"name_cs_cz",
|
||||||
('name_pt_br',
|
models.CharField(
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
help_text="user-friendly name for the product tag",
|
||||||
unique=True, verbose_name='tag display name')),
|
max_length=255,
|
||||||
('name_ro_ro',
|
null=True,
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
unique=True,
|
||||||
unique=True, verbose_name='tag display name')),
|
verbose_name="tag display name",
|
||||||
('name_ru_ru',
|
),
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
),
|
||||||
unique=True, verbose_name='tag display name')),
|
(
|
||||||
('name_zh_hans',
|
"name_da_dk",
|
||||||
models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
|
models.CharField(
|
||||||
unique=True, verbose_name='tag display name')),
|
help_text="user-friendly name for the product tag",
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
unique=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,
|
||||||
|
unique=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,
|
||||||
|
unique=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,
|
||||||
|
unique=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,
|
||||||
|
unique=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,
|
||||||
|
unique=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,
|
||||||
|
unique=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,
|
||||||
|
unique=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,
|
||||||
|
unique=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,
|
||||||
|
unique=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,
|
||||||
|
unique=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,
|
||||||
|
unique=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,
|
||||||
|
unique=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,
|
||||||
|
unique=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,
|
||||||
|
unique=True,
|
||||||
|
verbose_name="tag display name",
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'category tag',
|
"verbose_name": "category tag",
|
||||||
'verbose_name_plural': 'category tags',
|
"verbose_name_plural": "category tags",
|
||||||
},
|
},
|
||||||
bases=(django_prometheus.models.ExportModelOperationsMixin('category_tag'), models.Model),
|
bases=(django_prometheus.models.ExportModelOperationsMixin("category_tag"), models.Model),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='category',
|
model_name="category",
|
||||||
name='tags',
|
name="tags",
|
||||||
field=models.ManyToManyField(blank=True, help_text='tags that help describe or group this category',
|
field=models.ManyToManyField(
|
||||||
to='core.categorytag', verbose_name='category tags'),
|
blank=True,
|
||||||
|
help_text="tags that help describe or group this category",
|
||||||
|
to="core.categorytag",
|
||||||
|
verbose_name="category tags",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -6,15 +6,19 @@ from django.db import migrations, models
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('core', '0024_categorytag_category_tags'),
|
("core", "0024_categorytag_category_tags"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='product',
|
model_name="product",
|
||||||
name='category',
|
name="category",
|
||||||
field=models.ForeignKey(help_text='category this product belongs to',
|
field=models.ForeignKey(
|
||||||
on_delete=django.db.models.deletion.CASCADE, related_name='products',
|
help_text="category this product belongs to",
|
||||||
to='core.category', verbose_name='category'),
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="products",
|
||||||
|
to="core.category",
|
||||||
|
verbose_name="category",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("core", "0025_alter_product_category"),
|
("core", "0025_alter_product_category"),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("core", "0026_brand_slug_alter_category_slug_alter_product_slug"),
|
("core", "0026_brand_slug_alter_category_slug_alter_product_slug"),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("core", "0027_brand_priority_alter_brand_slug"),
|
("core", "0027_brand_priority_alter_brand_slug"),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("core", "0028_alter_category_slug_alter_product_slug"),
|
("core", "0028_alter_category_slug_alter_product_slug"),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("core", "0029_alter_category_slug"),
|
("core", "0029_alter_category_slug"),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("core", "0030_alter_category_slug"),
|
("core", "0030_alter_category_slug"),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("core", "0031_alter_product_slug"),
|
("core", "0031_alter_product_slug"),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import core.utils.db
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("core", "0032_alter_brand_slug_alter_category_slug_and_more"),
|
("core", "0032_alter_brand_slug_alter_category_slug_and_more"),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("core", "0033_alter_category_slug"),
|
("core", "0033_alter_category_slug"),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("core", "0034_category_priority_alter_brand_priority"),
|
("core", "0034_category_priority_alter_brand_priority"),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
506
core/models.py
506
core/models.py
File diff suppressed because it is too large
Load diff
|
|
@ -1,5 +1,6 @@
|
||||||
import logging
|
import logging
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
|
from typing import Collection, Any
|
||||||
|
|
||||||
from django.contrib.auth.models import AnonymousUser
|
from django.contrib.auth.models import AnonymousUser
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
|
|
@ -113,7 +114,7 @@ class CategoryDetailSerializer(ModelSerializer):
|
||||||
|
|
||||||
return filterable_results
|
return filterable_results
|
||||||
|
|
||||||
def get_children(self, obj) -> list:
|
def get_children(self, obj) -> Collection[Any]:
|
||||||
request = self.context.get("request")
|
request = self.context.get("request")
|
||||||
if request is not None and request.user.has_perm("view_category"):
|
if request is not None and request.user.has_perm("view_category"):
|
||||||
children = obj.children.all()
|
children = obj.children.all()
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,8 @@ from core.serializers.utility import AddressSerializer
|
||||||
|
|
||||||
|
|
||||||
class AttributeGroupSimpleSerializer(ModelSerializer):
|
class AttributeGroupSimpleSerializer(ModelSerializer):
|
||||||
parent: PrimaryKeyRelatedField = PrimaryKeyRelatedField(read_only=True) # type: ignore
|
parent = PrimaryKeyRelatedField(read_only=True)
|
||||||
children: PrimaryKeyRelatedField = PrimaryKeyRelatedField(many=True, read_only=True) # type: ignore
|
children = PrimaryKeyRelatedField(many=True, read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = AttributeGroup
|
model = AttributeGroup
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ class DoFeedbackSerializer(Serializer):
|
||||||
|
|
||||||
class CacheOperatorSerializer(Serializer):
|
class CacheOperatorSerializer(Serializer):
|
||||||
key = CharField(required=True)
|
key = CharField(required=True)
|
||||||
data = JSONField(required=False) # type: ignore
|
data = JSONField(required=False)
|
||||||
timeout = IntegerField(required=False)
|
timeout = IntegerField(required=False)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
{% load tz static i18n filters conditions %}
|
{% load tz static i18n filters conditions %}
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,12 @@
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from django.db.models import Model
|
|
||||||
from django.db.models.constants import LOOKUP_SEP
|
from django.db.models.constants import LOOKUP_SEP
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
from django_extensions.db.fields import AutoSlugField
|
from django_extensions.db.fields import AutoSlugField
|
||||||
from slugify import slugify
|
from slugify import slugify
|
||||||
|
|
||||||
logger = logging.getLogger("evibes")
|
logger = logging.getLogger("evibes")
|
||||||
|
|
||||||
|
|
||||||
def list_to_queryset(model: Model, data: list):
|
|
||||||
if not isinstance(model, Model):
|
|
||||||
raise ValueError(_(f"{model} must be model"))
|
|
||||||
if not isinstance(data, list):
|
|
||||||
raise ValueError(_(f"{data} must be list object"))
|
|
||||||
|
|
||||||
pk_list = [obj.pk for obj in data]
|
|
||||||
return model.objects.filter(pk__in=pk_list)
|
|
||||||
|
|
||||||
|
|
||||||
def unicode_slugify_function(content):
|
def unicode_slugify_function(content):
|
||||||
return slugify(
|
return slugify(
|
||||||
text=str(content),
|
text=str(content),
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,10 @@ def send_order_created_email(order_pk: str) -> tuple[bool, str]:
|
||||||
except Order.DoesNotExist:
|
except Order.DoesNotExist:
|
||||||
return False, f"Order not found with the given pk: {order_pk}"
|
return False, f"Order not found with the given pk: {order_pk}"
|
||||||
|
|
||||||
activate(order.user.language) # type: ignore
|
if not order.user:
|
||||||
|
return False, f"Order's user not found with the given pk: {order_pk}"
|
||||||
|
|
||||||
|
activate(order.user.language)
|
||||||
|
|
||||||
set_email_settings()
|
set_email_settings()
|
||||||
connection = mail.get_connection()
|
connection = mail.get_connection()
|
||||||
|
|
@ -64,7 +67,7 @@ def send_order_created_email(order_pk: str) -> tuple[bool, str]:
|
||||||
"total_price": order.total_price,
|
"total_price": order.total_price,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
to=[order.user.email], # type: ignore
|
to=[order.user.email],
|
||||||
from_email=f"{config.PROJECT_NAME} <{config.EMAIL_FROM}>",
|
from_email=f"{config.PROJECT_NAME} <{config.EMAIL_FROM}>",
|
||||||
connection=connection,
|
connection=connection,
|
||||||
)
|
)
|
||||||
|
|
@ -80,7 +83,7 @@ def send_order_finished_email(order_pk: str) -> tuple[bool, str]:
|
||||||
if len(ops) <= 0:
|
if len(ops) <= 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
activate(order.user.language) # type: ignore
|
activate(order.user.language)
|
||||||
|
|
||||||
set_email_settings()
|
set_email_settings()
|
||||||
connection = mail.get_connection()
|
connection = mail.get_connection()
|
||||||
|
|
@ -91,16 +94,16 @@ def send_order_finished_email(order_pk: str) -> tuple[bool, str]:
|
||||||
template_name="digital_order_delivered_email.html",
|
template_name="digital_order_delivered_email.html",
|
||||||
context={
|
context={
|
||||||
"order_uuid": order.human_readable_id,
|
"order_uuid": order.human_readable_id,
|
||||||
"user_first_name": order.user.first_name, # type: ignore
|
"user_first_name": order.user.first_name,
|
||||||
"order_products": ops,
|
"order_products": ops,
|
||||||
"project_name": config.PROJECT_NAME,
|
"project_name": config.PROJECT_NAME,
|
||||||
"contact_email": config.EMAIL_FROM,
|
"contact_email": config.EMAIL_FROM,
|
||||||
"total_price": round(sum(op.buy_price for op in ops), 2),
|
"total_price": round(sum(op.buy_price for op in ops), 2),
|
||||||
"display_system_attributes": order.user.has_perm("core.view_order"), # type: ignore
|
"display_system_attributes": order.user.has_perm("core.view_order"),
|
||||||
"today": datetime.today(),
|
"today": datetime.today(),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
to=[order.user.email], # type: ignore
|
to=[order.user.email],
|
||||||
from_email=f"{config.PROJECT_NAME} <{config.EMAIL_FROM}>",
|
from_email=f"{config.PROJECT_NAME} <{config.EMAIL_FROM}>",
|
||||||
connection=connection,
|
connection=connection,
|
||||||
)
|
)
|
||||||
|
|
@ -110,7 +113,7 @@ def send_order_finished_email(order_pk: str) -> tuple[bool, str]:
|
||||||
def send_thank_you_email(ops: list[OrderProduct]):
|
def send_thank_you_email(ops: list[OrderProduct]):
|
||||||
if ops:
|
if ops:
|
||||||
pass
|
pass
|
||||||
activate(order.user.language) # type: ignore
|
activate(order.user.language)
|
||||||
|
|
||||||
set_email_settings()
|
set_email_settings()
|
||||||
|
|
||||||
|
|
@ -121,6 +124,9 @@ def send_order_finished_email(order_pk: str) -> tuple[bool, str]:
|
||||||
except Order.DoesNotExist:
|
except Order.DoesNotExist:
|
||||||
return False, f"Order not found with the given pk: {order_pk}"
|
return False, f"Order not found with the given pk: {order_pk}"
|
||||||
|
|
||||||
|
if not order.user:
|
||||||
|
return False, f"Order's user not found with the given pk: {order_pk}"
|
||||||
|
|
||||||
digital_ops = []
|
digital_ops = []
|
||||||
|
|
||||||
for digital_op in order.order_products.filter(
|
for digital_op in order.order_products.filter(
|
||||||
|
|
|
||||||
16
core/vendors/__init__.py
vendored
16
core/vendors/__init__.py
vendored
|
|
@ -145,7 +145,7 @@ class AbstractVendor:
|
||||||
return value, "string"
|
return value, "string"
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def auto_resolver_helper(model: Brand | Category, resolving_name: str) -> Brand | Category | None:
|
def auto_resolver_helper(model: type[Brand] | type[Category], resolving_name: str) -> Brand | Category | None:
|
||||||
queryset = model.objects.filter(name=resolving_name)
|
queryset = model.objects.filter(name=resolving_name)
|
||||||
if not queryset.exists():
|
if not queryset.exists():
|
||||||
if len(resolving_name) > 255:
|
if len(resolving_name) > 255:
|
||||||
|
|
@ -178,7 +178,7 @@ class AbstractVendor:
|
||||||
except Category.DoesNotExist:
|
except Category.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
return self.auto_resolver_helper(Category, category_name) # type: ignore
|
return self.auto_resolver_helper(Category, category_name)
|
||||||
|
|
||||||
def auto_resolve_brand(self, brand_name: str):
|
def auto_resolve_brand(self, brand_name: str):
|
||||||
if brand_name:
|
if brand_name:
|
||||||
|
|
@ -196,7 +196,7 @@ class AbstractVendor:
|
||||||
except Brand.DoesNotExist:
|
except Brand.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
return self.auto_resolver_helper(Brand, brand_name) # type: ignore
|
return self.auto_resolver_helper(Brand, brand_name)
|
||||||
|
|
||||||
def resolve_price(
|
def resolve_price(
|
||||||
self,
|
self,
|
||||||
|
|
@ -213,7 +213,7 @@ class AbstractVendor:
|
||||||
price = float(original_price)
|
price = float(original_price)
|
||||||
|
|
||||||
if category and category.markup_percent:
|
if category and category.markup_percent:
|
||||||
price *= 1 + float(category.markup_percent) / 100.0 # type: ignore
|
price *= 1 + float(category.markup_percent) / 100.0
|
||||||
elif vendor and vendor.markup_percent:
|
elif vendor and vendor.markup_percent:
|
||||||
price *= 1 + vendor.markup_percent / 100.0
|
price *= 1 + vendor.markup_percent / 100.0
|
||||||
|
|
||||||
|
|
@ -268,8 +268,8 @@ class AbstractVendor:
|
||||||
if vendor.is_active:
|
if vendor.is_active:
|
||||||
return vendor
|
return vendor
|
||||||
raise VendorError(f"Vendor {self.vendor_name!r} is inactive...")
|
raise VendorError(f"Vendor {self.vendor_name!r} is inactive...")
|
||||||
except Vendor.DoesNotExist:
|
except Vendor.DoesNotExist as dne:
|
||||||
raise Exception(f"No matching vendor found with name {self.vendor_name!r}...")
|
raise Exception(f"No matching vendor found with name {self.vendor_name!r}...") from dne
|
||||||
|
|
||||||
def get_products(self):
|
def get_products(self):
|
||||||
pass
|
pass
|
||||||
|
|
@ -288,6 +288,7 @@ class AbstractVendor:
|
||||||
def prepare_for_stock_update(self, method: str = "deactivate") -> None:
|
def prepare_for_stock_update(self, method: str = "deactivate") -> None:
|
||||||
products = self.get_products_queryset()
|
products = self.get_products_queryset()
|
||||||
|
|
||||||
|
# noinspection PyUnreachableCode
|
||||||
match method:
|
match method:
|
||||||
case "deactivate":
|
case "deactivate":
|
||||||
products.update(is_active=False)
|
products.update(is_active=False)
|
||||||
|
|
@ -301,6 +302,7 @@ class AbstractVendor:
|
||||||
def delete_inactives(self, inactivation_method: str = "deactivate"):
|
def delete_inactives(self, inactivation_method: str = "deactivate"):
|
||||||
products = self.get_products_queryset()
|
products = self.get_products_queryset()
|
||||||
|
|
||||||
|
# noinspection PyUnreachableCode
|
||||||
match inactivation_method:
|
match inactivation_method:
|
||||||
case "deactivate":
|
case "deactivate":
|
||||||
products.filter(is_active=False).delete()
|
products.filter(is_active=False).delete()
|
||||||
|
|
@ -339,7 +341,7 @@ class AbstractVendor:
|
||||||
defaults={"is_active": True},
|
defaults={"is_active": True},
|
||||||
)
|
)
|
||||||
except Attribute.MultipleObjectsReturned:
|
except Attribute.MultipleObjectsReturned:
|
||||||
attribute = Attribute.objects.filter(name=key, group=attr_group).order_by("uuid").first() # type: ignore
|
attribute = Attribute.objects.filter(name=key, group=attr_group).order_by("uuid").first() # type: ignore [assignment]
|
||||||
attribute.is_active = True
|
attribute.is_active = True
|
||||||
attribute.value_type = attr_value_type
|
attribute.value_type = attr_value_type
|
||||||
attribute.save()
|
attribute.save()
|
||||||
|
|
|
||||||
|
|
@ -102,9 +102,6 @@ class CustomGraphQLView(FileUploadGraphQLView):
|
||||||
This class serves as a customization extension of FileUploadGraphQLView that allows modification
|
This class serves as a customization extension of FileUploadGraphQLView that allows modification
|
||||||
or enhancement of specific behaviors, particularly the context handling for GraphQL requests.
|
or enhancement of specific behaviors, particularly the context handling for GraphQL requests.
|
||||||
|
|
||||||
Attributes
|
|
||||||
----------
|
|
||||||
None
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def get_context(self, request):
|
def get_context(self, request):
|
||||||
|
|
@ -520,8 +517,8 @@ def favicon_view(request, *args, **kwargs):
|
||||||
try:
|
try:
|
||||||
favicon_path = os.path.join(settings.BASE_DIR, "static/favicon.png")
|
favicon_path = os.path.join(settings.BASE_DIR, "static/favicon.png")
|
||||||
return FileResponse(open(favicon_path, "rb"), content_type="image/x-icon")
|
return FileResponse(open(favicon_path, "rb"), content_type="image/x-icon")
|
||||||
except FileNotFoundError:
|
except FileNotFoundError as fnfe:
|
||||||
raise Http404(_("favicon not found"))
|
raise Http404(_("favicon not found")) from fnfe
|
||||||
|
|
||||||
|
|
||||||
def index(request, *args, **kwargs):
|
def index(request, *args, **kwargs):
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import logging
|
||||||
import uuid
|
import uuid
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
from django.db.models import Q, QuerySet
|
from django.db.models import Q
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
|
|
@ -378,7 +378,7 @@ class ProductViewSet(EvibesViewSet):
|
||||||
lookup_val = kwargs.get(self.lookup_field)
|
lookup_val = kwargs.get(self.lookup_field)
|
||||||
try:
|
try:
|
||||||
product = Product.objects.get(uuid=lookup_val)
|
product = Product.objects.get(uuid=lookup_val)
|
||||||
feedbacks: QuerySet[Feedback] = ( # type: ignore
|
feedbacks = (
|
||||||
Feedback.objects.filter(order_product__product=product)
|
Feedback.objects.filter(order_product__product=product)
|
||||||
if request.user.has_perm("core.view_feedback")
|
if request.user.has_perm("core.view_feedback")
|
||||||
else Feedback.objects.filter(order_product__product=product, is_active=True)
|
else Feedback.objects.filter(order_product__product=product, is_active=True)
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ app.conf.update(
|
||||||
)
|
)
|
||||||
|
|
||||||
app.conf.task_routes = {
|
app.conf.task_routes = {
|
||||||
'core.tasks.update_products_task': {'queue': 'stock_updater'},
|
"core.tasks.update_products_task": {"queue": "stock_updater"},
|
||||||
}
|
}
|
||||||
|
|
||||||
app.config_from_object("django.conf:settings", namespace="CELERY")
|
app.config_from_object("django.conf:settings", namespace="CELERY")
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,9 @@ class CustomPagination(PageNumberPagination):
|
||||||
{
|
{
|
||||||
"links": {"forward": self.get_next_link(), "backward": self.get_previous_link()},
|
"links": {"forward": self.get_next_link(), "backward": self.get_previous_link()},
|
||||||
"counts": {
|
"counts": {
|
||||||
"total_pages": None or self.page.paginator.num_pages, # type: ignore
|
"total_pages": None or self.page.paginator.num_pages, # type: ignore [union-attr]
|
||||||
"page_size": None or self.page_size, # type: ignore
|
"page_size": None or self.page_size,
|
||||||
"total_items": None or self.page.paginator.count, # type: ignore
|
"total_items": None or self.page.paginator.count, # type: ignore [union-attr]
|
||||||
},
|
},
|
||||||
"data": data,
|
"data": data,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import logging
|
import logging
|
||||||
from os import getenv
|
from os import getenv, name
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
EVIBES_VERSION = "2.9.0"
|
EVIBES_VERSION = "2.9.0"
|
||||||
|
|
@ -9,7 +9,7 @@ BASE_DIR = Path(__file__).resolve().parent.parent.parent
|
||||||
SECRET_KEY = getenv("SECRET_KEY", "SUPER_SECRET_KEY")
|
SECRET_KEY = getenv("SECRET_KEY", "SUPER_SECRET_KEY")
|
||||||
DEBUG = bool(int(getenv("DEBUG", "1")))
|
DEBUG = bool(int(getenv("DEBUG", "1")))
|
||||||
|
|
||||||
ALLOWED_HOSTS = {
|
ALLOWED_HOSTS: set = {
|
||||||
"app",
|
"app",
|
||||||
"worker",
|
"worker",
|
||||||
"beat",
|
"beat",
|
||||||
|
|
@ -27,9 +27,9 @@ else:
|
||||||
for entry in getenv("ALLOWED_HOSTS", "").split(" "):
|
for entry in getenv("ALLOWED_HOSTS", "").split(" "):
|
||||||
ALLOWED_HOSTS.add(entry)
|
ALLOWED_HOSTS.add(entry)
|
||||||
|
|
||||||
ALLOWED_HOSTS = tuple(ALLOWED_HOSTS) # type: ignore
|
ALLOWED_HOSTS: tuple = tuple(ALLOWED_HOSTS)
|
||||||
|
|
||||||
CSRF_TRUSTED_ORIGINS = {
|
CSRF_TRUSTED_ORIGINS: set = {
|
||||||
"http://127.0.0.1",
|
"http://127.0.0.1",
|
||||||
"http://api.localhost",
|
"http://api.localhost",
|
||||||
"http://b2b.localhost",
|
"http://b2b.localhost",
|
||||||
|
|
@ -38,12 +38,12 @@ CSRF_TRUSTED_ORIGINS = {
|
||||||
for entry in getenv("CSRF_TRUSTED_ORIGINS", "").split(" "):
|
for entry in getenv("CSRF_TRUSTED_ORIGINS", "").split(" "):
|
||||||
CSRF_TRUSTED_ORIGINS.add(entry)
|
CSRF_TRUSTED_ORIGINS.add(entry)
|
||||||
|
|
||||||
CSRF_TRUSTED_ORIGINS = tuple(CSRF_TRUSTED_ORIGINS) # type: ignore
|
CSRF_TRUSTED_ORIGINS: tuple = tuple(CSRF_TRUSTED_ORIGINS)
|
||||||
|
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
CORS_ALLOW_ALL_ORIGINS = True
|
CORS_ALLOW_ALL_ORIGINS = True
|
||||||
else:
|
else:
|
||||||
CORS_ALLOWED_ORIGINS = {
|
CORS_ALLOWED_ORIGINS: set = {
|
||||||
"http://127.0.0.1",
|
"http://127.0.0.1",
|
||||||
"http://api.localhost",
|
"http://api.localhost",
|
||||||
"http://b2b.localhost",
|
"http://b2b.localhost",
|
||||||
|
|
@ -51,7 +51,7 @@ else:
|
||||||
for entry in getenv("CORS_ALLOWED_ORIGINS", "").split(" "):
|
for entry in getenv("CORS_ALLOWED_ORIGINS", "").split(" "):
|
||||||
CORS_ALLOWED_ORIGINS.add(entry)
|
CORS_ALLOWED_ORIGINS.add(entry)
|
||||||
|
|
||||||
CORS_ALLOWED_ORIGINS = tuple(CORS_ALLOWED_ORIGINS) # type: ignore
|
CORS_ALLOWED_ORIGINS: tuple = tuple(CORS_ALLOWED_ORIGINS)
|
||||||
|
|
||||||
CORS_ALLOW_METHODS = (
|
CORS_ALLOW_METHODS = (
|
||||||
"DELETE",
|
"DELETE",
|
||||||
|
|
@ -342,3 +342,7 @@ STORAGES: dict[str, dict[str, str | int | bool | None]] = {
|
||||||
"BACKEND": "django.core.files.storage.FileSystemStorage",
|
"BACKEND": "django.core.files.storage.FileSystemStorage",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if name == "nt":
|
||||||
|
GDAL_LIBRARY_PATH = r"C:\OSGeo4W\bin\gdal311.dll"
|
||||||
|
GEOS_LIBRARY_PATH = r"C:\OSGeo4W\bin\geos_c.dll"
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
from evibes.settings.base import * # noqa: F403
|
from evibes.settings.base import getenv
|
||||||
|
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
"default": {
|
"default": {
|
||||||
"ENGINE": "django_prometheus.db.backends.postgis",
|
"ENGINE": "django_prometheus.db.backends.postgis",
|
||||||
"NAME": getenv("POSTGRES_DB"), # noqa: F405
|
"NAME": getenv("POSTGRES_DB"),
|
||||||
"USER": getenv("POSTGRES_USER"), # noqa: F405
|
"USER": getenv("POSTGRES_USER"),
|
||||||
"PASSWORD": getenv("POSTGRES_PASSWORD"), # noqa: F405
|
"PASSWORD": getenv("POSTGRES_PASSWORD"),
|
||||||
"HOST": "database",
|
"HOST": "database",
|
||||||
"PORT": 5432,
|
"PORT": 5432,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
from evibes.settings import CONSTANCE_CONFIG
|
from evibes.settings import CONSTANCE_CONFIG
|
||||||
|
|
||||||
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
|
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
|
||||||
EMAIL_HOST = CONSTANCE_CONFIG.get("EMAIL_HOST")[0] # type: ignore
|
EMAIL_HOST = CONSTANCE_CONFIG.get("EMAIL_HOST")[0]
|
||||||
EMAIL_PORT = CONSTANCE_CONFIG.get("EMAIL_PORT")[0] # type: ignore
|
EMAIL_PORT = CONSTANCE_CONFIG.get("EMAIL_PORT")[0]
|
||||||
EMAIL_USE_TLS = CONSTANCE_CONFIG.get("EMAIL_USE_TLS")[0] # type: ignore
|
EMAIL_USE_TLS = CONSTANCE_CONFIG.get("EMAIL_USE_TLS")[0]
|
||||||
EMAIL_USE_SSL = CONSTANCE_CONFIG.get("EMAIL_USE_SSL")[0] # type: ignore
|
EMAIL_USE_SSL = CONSTANCE_CONFIG.get("EMAIL_USE_SSL")[0]
|
||||||
EMAIL_HOST_USER = CONSTANCE_CONFIG.get("EMAIL_HOST_USER")[0] # type: ignore
|
EMAIL_HOST_USER = CONSTANCE_CONFIG.get("EMAIL_HOST_USER")[0]
|
||||||
EMAIL_HOST_PASSWORD = CONSTANCE_CONFIG.get("EMAIL_HOST_PASSWORD")[0] # type: ignore
|
EMAIL_HOST_PASSWORD = CONSTANCE_CONFIG.get("EMAIL_HOST_PASSWORD")[0]
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,9 @@ from evibes.settings.base import EVIBES_VERSION
|
||||||
from evibes.settings.constance import CONSTANCE_CONFIG
|
from evibes.settings.constance import CONSTANCE_CONFIG
|
||||||
|
|
||||||
JAZZMIN_SETTINGS = {
|
JAZZMIN_SETTINGS = {
|
||||||
"site_title": f"{CONSTANCE_CONFIG.get('PROJECT_NAME')[0]} Admin", # type: ignore
|
"site_title": f"{CONSTANCE_CONFIG.get('PROJECT_NAME')[0]} Admin", # type: ignore [index]
|
||||||
"site_header": str(CONSTANCE_CONFIG.get("PROJECT_NAME")[0]), # type: ignore
|
"site_header": str(CONSTANCE_CONFIG.get("PROJECT_NAME")[0]), # type: ignore [index]
|
||||||
"site_brand": str(CONSTANCE_CONFIG.get("PROJECT_NAME")[0]), # type: ignore
|
"site_brand": str(CONSTANCE_CONFIG.get("PROJECT_NAME")[0]), # type: ignore [index]
|
||||||
"site_logo": "logo.png",
|
"site_logo": "logo.png",
|
||||||
"login_logo": "logo.png",
|
"login_logo": "logo.png",
|
||||||
"login_logo_dark": "logo.png",
|
"login_logo_dark": "logo.png",
|
||||||
|
|
@ -18,21 +18,21 @@ JAZZMIN_SETTINGS = {
|
||||||
"user_avatar": "avatar",
|
"user_avatar": "avatar",
|
||||||
"topmenu_links": [
|
"topmenu_links": [
|
||||||
{"name": _("Home"), "url": "admin:index"},
|
{"name": _("Home"), "url": "admin:index"},
|
||||||
{"name": _("Storefront"), "url": f"https://{CONSTANCE_CONFIG.get('BASE_DOMAIN')[0]}", "new_window": True},
|
{"name": _("Storefront"), "url": f"https://{CONSTANCE_CONFIG.get('BASE_DOMAIN')[0]}", "new_window": True}, # type: ignore [index]
|
||||||
{"name": "GitLab", "url": "https://gitlab.com/wiseless/evibes", "new_window": True},
|
{"name": "GitLab", "url": "https://gitlab.com/wiseless/evibes", "new_window": True},
|
||||||
{
|
{
|
||||||
"name": _("GraphQL Docs"),
|
"name": _("GraphQL Docs"),
|
||||||
"url": f"https://api.{CONSTANCE_CONFIG.get('BASE_DOMAIN')[0]}/graphql", # type: ignore
|
"url": f"https://api.{CONSTANCE_CONFIG.get('BASE_DOMAIN')[0]}/graphql", # type: ignore [index]
|
||||||
"new_window": True,
|
"new_window": True,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": _("Platform REST Docs"),
|
"name": _("Platform REST Docs"),
|
||||||
"url": f"https://api.{CONSTANCE_CONFIG.get('BASE_DOMAIN')[0]}/docs/swagger", # type: ignore
|
"url": f"https://api.{CONSTANCE_CONFIG.get('BASE_DOMAIN')[0]}/docs/swagger", # type: ignore [index]
|
||||||
"new_window": True,
|
"new_window": True,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": _("B2B REST Docs"),
|
"name": _("B2B REST Docs"),
|
||||||
"url": f"https://b2b.{CONSTANCE_CONFIG.get('BASE_DOMAIN')[0]}/docs/swagger", # type: ignore
|
"url": f"https://b2b.{CONSTANCE_CONFIG.get('BASE_DOMAIN')[0]}/docs/swagger", # type: ignore [index]
|
||||||
"new_window": True,
|
"new_window": True,
|
||||||
},
|
},
|
||||||
{"name": _("Support"), "url": "https://t.me/fureunoir", "new_window": True},
|
{"name": _("Support"), "url": "https://t.me/fureunoir", "new_window": True},
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,11 @@ class SkipVariableDoesNotExistFilter(logging.Filter): # noqa: F405
|
||||||
if record.exc_info:
|
if record.exc_info:
|
||||||
exc_type, exc_instance, _ = record.exc_info
|
exc_type, exc_instance, _ = record.exc_info
|
||||||
try:
|
try:
|
||||||
if exc_type.__name__ == "VariableDoesNotExist": # type: ignore
|
if exc_type is not None:
|
||||||
|
if exc_type.__name__ == "VariableDoesNotExist":
|
||||||
return False
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return True
|
return True
|
||||||
return "VariableDoesNotExist" not in record.getMessage()
|
return "VariableDoesNotExist" not in record.getMessage()
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ class TransactionType(DjangoObjectType):
|
||||||
process = GenericScalar()
|
process = GenericScalar()
|
||||||
|
|
||||||
def resolve_process(self: Transaction, info) -> dict:
|
def resolve_process(self: Transaction, info) -> dict:
|
||||||
|
if self.balance is not None:
|
||||||
if info.context.user == self.balance.user:
|
if info.context.user == self.balance.user:
|
||||||
return self.process
|
return self.process
|
||||||
return {}
|
return {}
|
||||||
|
|
|
||||||
|
|
@ -9,55 +9,96 @@ from django.db import migrations, models
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = []
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Balance',
|
name="Balance",
|
||||||
fields=[
|
fields=[
|
||||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
|
(
|
||||||
help_text='unique id is used to surely identify any database object',
|
"uuid",
|
||||||
primary_key=True, serialize=False, verbose_name='unique id')),
|
models.UUIDField(
|
||||||
('is_active', models.BooleanField(default=True,
|
default=uuid.uuid4,
|
||||||
|
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",
|
help_text="if set to false, this object can't be seen by users without needed permission",
|
||||||
verbose_name='is active')),
|
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,
|
"created",
|
||||||
help_text='when the object was last modified',
|
django_extensions.db.fields.CreationDateTimeField(
|
||||||
verbose_name='modified')),
|
auto_now_add=True,
|
||||||
('amount', models.FloatField(default=0)),
|
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"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("amount", models.FloatField(default=0)),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'balance',
|
"verbose_name": "balance",
|
||||||
'verbose_name_plural': 'balances',
|
"verbose_name_plural": "balances",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Transaction',
|
name="Transaction",
|
||||||
fields=[
|
fields=[
|
||||||
('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
|
(
|
||||||
help_text='unique id is used to surely identify any database object',
|
"uuid",
|
||||||
primary_key=True, serialize=False, verbose_name='unique id')),
|
models.UUIDField(
|
||||||
('is_active', models.BooleanField(default=True,
|
default=uuid.uuid4,
|
||||||
|
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",
|
help_text="if set to false, this object can't be seen by users without needed permission",
|
||||||
verbose_name='is active')),
|
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,
|
"created",
|
||||||
help_text='when the object was last modified',
|
django_extensions.db.fields.CreationDateTimeField(
|
||||||
verbose_name='modified')),
|
auto_now_add=True,
|
||||||
('amount', models.FloatField()),
|
help_text="when the object first appeared on the database",
|
||||||
('currency', models.CharField(max_length=3)),
|
verbose_name="created",
|
||||||
('payment_method', models.CharField(max_length=20)),
|
),
|
||||||
('process', models.JSONField(default=dict, verbose_name='processing details')),
|
),
|
||||||
|
(
|
||||||
|
"modified",
|
||||||
|
django_extensions.db.fields.ModificationDateTimeField(
|
||||||
|
auto_now=True, help_text="when the object was last modified", verbose_name="modified"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("amount", models.FloatField()),
|
||||||
|
("currency", models.CharField(max_length=3)),
|
||||||
|
("payment_method", models.CharField(max_length=20)),
|
||||||
|
("process", models.JSONField(default=dict, verbose_name="processing details")),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'transaction',
|
"verbose_name": "transaction",
|
||||||
'verbose_name_plural': 'transactions',
|
"verbose_name_plural": "transactions",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -10,32 +10,42 @@ class Migration(migrations.Migration):
|
||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('core', '0002_initial'),
|
("core", "0002_initial"),
|
||||||
('payments', '0001_initial'),
|
("payments", "0001_initial"),
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='balance',
|
model_name="balance",
|
||||||
name='user',
|
name="user",
|
||||||
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='payments_balance',
|
field=models.OneToOneField(
|
||||||
to=settings.AUTH_USER_MODEL, blank=True, null=True),
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="payments_balance",
|
||||||
|
to=settings.AUTH_USER_MODEL,
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='transaction',
|
model_name="transaction",
|
||||||
name='balance',
|
name="balance",
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='payments.balance'),
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="payments.balance"),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='transaction',
|
model_name="transaction",
|
||||||
name='order',
|
name="order",
|
||||||
field=models.ForeignKey(blank=True, help_text='order to process after paid', null=True,
|
field=models.ForeignKey(
|
||||||
on_delete=django.db.models.deletion.CASCADE, related_name='payments_transactions',
|
blank=True,
|
||||||
to='core.order'),
|
help_text="order to process after paid",
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="payments_transactions",
|
||||||
|
to="core.order",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AddIndex(
|
migrations.AddIndex(
|
||||||
model_name='transaction',
|
model_name="transaction",
|
||||||
index=django.contrib.postgres.indexes.GinIndex(fields=['process'], name='payments_tr_process_d5b008_gin'),
|
index=django.contrib.postgres.indexes.GinIndex(fields=["process"], name="payments_tr_process_d5b008_gin"),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,20 @@ from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('payments', '0002_initial'),
|
("payments", "0002_initial"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='transaction',
|
model_name="transaction",
|
||||||
name='balance',
|
name="balance",
|
||||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='transactions', to='payments.balance'),
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="transactions",
|
||||||
|
to="payments.balance",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -4,15 +4,14 @@ from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('payments', '0003_alter_transaction_balance'),
|
("payments", "0003_alter_transaction_balance"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='transaction',
|
model_name="transaction",
|
||||||
name='payment_method',
|
name="payment_method",
|
||||||
field=models.CharField(blank=True, max_length=20, null=True),
|
field=models.CharField(blank=True, max_length=20, null=True),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,11 @@ from core.abstract import NiceModel
|
||||||
|
|
||||||
|
|
||||||
class Transaction(NiceModel):
|
class Transaction(NiceModel):
|
||||||
amount: float = FloatField(null=False, blank=False) # type: ignore
|
amount = FloatField(null=False, blank=False)
|
||||||
balance: "Balance" = ForeignKey(
|
balance = ForeignKey("payments.Balance", on_delete=CASCADE, blank=True, null=True, related_name="transactions")
|
||||||
"payments.Balance", on_delete=CASCADE, blank=True, null=True, related_name="transactions"
|
currency = CharField(max_length=3, null=False, blank=False)
|
||||||
) # type: ignore
|
payment_method = CharField(max_length=20, null=True, blank=True)
|
||||||
currency: str = CharField(max_length=3, null=False, blank=False) # type: ignore
|
order = ForeignKey(
|
||||||
payment_method: str = CharField(max_length=20, null=True, blank=True) # type: ignore
|
|
||||||
order = ForeignKey( # type: ignore
|
|
||||||
"core.Order",
|
"core.Order",
|
||||||
on_delete=CASCADE,
|
on_delete=CASCADE,
|
||||||
blank=True,
|
blank=True,
|
||||||
|
|
@ -21,7 +19,7 @@ class Transaction(NiceModel):
|
||||||
help_text=_("order to process after paid"),
|
help_text=_("order to process after paid"),
|
||||||
related_name="payments_transactions",
|
related_name="payments_transactions",
|
||||||
)
|
)
|
||||||
process: dict = JSONField(verbose_name=_("processing details"), default=dict) # type: ignore
|
process = JSONField(verbose_name=_("processing details"), default=dict)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.balance.user.email} | {self.amount}"
|
return f"{self.balance.user.email} | {self.amount}"
|
||||||
|
|
@ -48,8 +46,8 @@ class Transaction(NiceModel):
|
||||||
|
|
||||||
|
|
||||||
class Balance(NiceModel):
|
class Balance(NiceModel):
|
||||||
amount: float = FloatField(null=False, blank=False, default=0) # type: ignore
|
amount = FloatField(null=False, blank=False, default=0)
|
||||||
user = OneToOneField( # type: ignore
|
user = OneToOneField(
|
||||||
to="vibes_auth.User", on_delete=CASCADE, blank=True, null=True, related_name="payments_balance"
|
to="vibes_auth.User", on_delete=CASCADE, blank=True, null=True, related_name="payments_balance"
|
||||||
)
|
)
|
||||||
transactions: QuerySet["Transaction"]
|
transactions: QuerySet["Transaction"]
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,10 @@ class TransactionProcessSerializer(ModelSerializer):
|
||||||
order_uuid = SerializerMethodField(read_only=True, required=False)
|
order_uuid = SerializerMethodField(read_only=True, required=False)
|
||||||
|
|
||||||
def get_order_hr_id(self, obj: Transaction) -> str | None:
|
def get_order_hr_id(self, obj: Transaction) -> str | None:
|
||||||
return obj.order.human_readable_id if obj.order else None # type: ignore
|
return obj.order.human_readable_id if obj.order else None
|
||||||
|
|
||||||
def get_order_uuid(self, obj: Transaction) -> str | None:
|
def get_order_uuid(self, obj: Transaction) -> str | None:
|
||||||
return str(obj.order.uuid) if obj.order else None # type: ignore
|
return str(obj.order.uuid) if obj.order else None
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Transaction
|
model = Transaction
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ def process_transaction_changes(instance, created, **_kwargs):
|
||||||
case _:
|
case _:
|
||||||
gateway = AbstractGateway()
|
gateway = AbstractGateway()
|
||||||
gateway.process_transaction(instance)
|
gateway.process_transaction(instance)
|
||||||
except Exception as e: # noqa:
|
except Exception as e:
|
||||||
instance.process = {"status": "NOGATEWAY", "error": str(e)}
|
instance.process = {"status": "NOGATEWAY", "error": str(e)}
|
||||||
if not created:
|
if not created:
|
||||||
status = instance.process.get("status", "").lower()
|
status = instance.process.get("status", "").lower()
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
{% load tz static i18n filters conditions %}
|
{% load tz static i18n filters conditions %}
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
|
|
@ -61,12 +60,6 @@
|
||||||
color: #888;
|
color: #888;
|
||||||
}
|
}
|
||||||
|
|
||||||
.order-table {
|
|
||||||
width: 100%;
|
|
||||||
margin-top: 20px;
|
|
||||||
border-collapse: collapse;
|
|
||||||
}
|
|
||||||
|
|
||||||
.order-table th, .order-table td {
|
.order-table th, .order-table td {
|
||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,10 @@ def balance_deposit_email(transaction_pk: str) -> tuple[bool, str]:
|
||||||
except Transaction.DoesNotExist:
|
except Transaction.DoesNotExist:
|
||||||
return False, f"Transaction not found with the given pk: {transaction_pk}"
|
return False, f"Transaction not found with the given pk: {transaction_pk}"
|
||||||
|
|
||||||
activate(transaction.balance.user.language) # type: ignore
|
if not transaction.balance or not transaction.balance.user:
|
||||||
|
return False, f"Balance not found for the given transaction pk: {transaction_pk}"
|
||||||
|
|
||||||
|
activate(transaction.balance.user.language)
|
||||||
|
|
||||||
set_email_settings()
|
set_email_settings()
|
||||||
connection = mail.get_connection()
|
connection = mail.get_connection()
|
||||||
|
|
@ -31,13 +34,13 @@ def balance_deposit_email(transaction_pk: str) -> tuple[bool, str]:
|
||||||
context={
|
context={
|
||||||
"amount": transaction.amount,
|
"amount": transaction.amount,
|
||||||
"balance": transaction.balance.amount,
|
"balance": transaction.balance.amount,
|
||||||
"user_first_name": transaction.balance.user.first_name, # type: ignore
|
"user_first_name": transaction.balance.user.first_name,
|
||||||
"project_name": config.PROJECT_NAME,
|
"project_name": config.PROJECT_NAME,
|
||||||
"contact_email": config.EMAIL_FROM,
|
"contact_email": config.EMAIL_FROM,
|
||||||
"today": datetime.today(),
|
"today": datetime.today(),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
to=[transaction.balance.user.email], # type: ignore
|
to=[transaction.balance.user.email],
|
||||||
from_email=f"{config.PROJECT_NAME} <{config.EMAIL_FROM}>",
|
from_email=f"{config.PROJECT_NAME} <{config.EMAIL_FROM}>",
|
||||||
connection=connection,
|
connection=connection,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -103,18 +103,21 @@ testing = ["pytest", "pytest-django", "coverage"]
|
||||||
linting = ["black", "isort", "flake8", "bandit"]
|
linting = ["black", "isort", "flake8", "bandit"]
|
||||||
|
|
||||||
[tool.mypy]
|
[tool.mypy]
|
||||||
disable_error_code = ["import-untyped", "misc"]
|
disable_error_code = ["no-redef", "import-untyped"]
|
||||||
exclude = ["*/migrations/*", "./evibes/settings/drf.py"]
|
exclude = ["*/migrations/*"]
|
||||||
|
plugins = ["mypy_django_plugin.main", "mypy_drf_plugin.main"]
|
||||||
|
|
||||||
|
[tool.django-stubs]
|
||||||
|
django_settings_module = "evibes.settings"
|
||||||
|
|
||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
line-length = 120
|
line-length = 120
|
||||||
target-version = "py312"
|
target-version = "py312"
|
||||||
exclude = ["migrations", "media", "static", "storefront"]
|
exclude = ["media", "static", "storefront"]
|
||||||
|
|
||||||
[tool.ruff.lint]
|
[tool.ruff.lint]
|
||||||
select = ["E", "W", "F", "B", "I", "RUF", "UP", "N", "A", "COM", "C4", "DJ001", "RSE", "SIM", "ISC", "TID252", "PGH004"]
|
select = ["E4", "E7", "E9", "F", "B", "Q"]
|
||||||
ignore = ["B904", "RUF001", "RUF002", "RUF003", "RUF005", "RUF012", "A003", "A002", "COM812", "S603"]
|
ignore = ["RUF012", "A002", "A003"]
|
||||||
per-file-ignores = { "__init__.py" = ["E402", "F401"] }
|
|
||||||
|
|
||||||
[tool.ruff.format]
|
[tool.ruff.format]
|
||||||
quote-style = "double"
|
quote-style = "double"
|
||||||
|
|
|
||||||
|
|
@ -102,9 +102,9 @@ class UpdateUser(BaseMutation):
|
||||||
try:
|
try:
|
||||||
user = User.objects.get(uuid=uuid)
|
user = User.objects.get(uuid=uuid)
|
||||||
|
|
||||||
except User.DoesNotExist:
|
except User.DoesNotExist as dne:
|
||||||
name = "User"
|
name = "User"
|
||||||
raise Http404(_(f"{name} does not exist: {uuid}"))
|
raise Http404(_(f"{name} does not exist: {uuid}")) from dne
|
||||||
|
|
||||||
if not (info.context.user.has_perm("vibes_auth.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)
|
||||||
|
|
@ -176,8 +176,8 @@ class DeleteUser(BaseMutation):
|
||||||
else:
|
else:
|
||||||
raise BadRequest("uuid or email must be specified")
|
raise BadRequest("uuid or email must be specified")
|
||||||
return DeleteUser(success=True)
|
return DeleteUser(success=True)
|
||||||
except User.DoesNotExist:
|
except User.DoesNotExist as dne:
|
||||||
raise Http404(f"User with the given uuid: {uuid} or email: {email} does not exist.")
|
raise Http404(f"User with the given uuid: {uuid} or email: {email} does not exist.") from dne
|
||||||
raise PermissionDenied(permission_denied_message)
|
raise PermissionDenied(permission_denied_message)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -201,7 +201,7 @@ class ObtainJSONWebToken(BaseMutation):
|
||||||
access_token=serializer.validated_data["access"],
|
access_token=serializer.validated_data["access"],
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise PermissionDenied(f"invalid credentials provided: {e!s}")
|
raise PermissionDenied(f"invalid credentials provided: {e!s}") from e
|
||||||
|
|
||||||
|
|
||||||
class RefreshJSONWebToken(BaseMutation):
|
class RefreshJSONWebToken(BaseMutation):
|
||||||
|
|
@ -222,7 +222,7 @@ class RefreshJSONWebToken(BaseMutation):
|
||||||
user=User.objects.get(uuid=serializer.validated_data["user"]["uuid"]),
|
user=User.objects.get(uuid=serializer.validated_data["user"]["uuid"]),
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise PermissionDenied(f"invalid refresh token provided: {e!s}")
|
raise PermissionDenied(f"invalid refresh token provided: {e!s}") from e
|
||||||
|
|
||||||
|
|
||||||
class VerifyJSONWebToken(BaseMutation):
|
class VerifyJSONWebToken(BaseMutation):
|
||||||
|
|
@ -270,7 +270,7 @@ class ActivateUser(BaseMutation):
|
||||||
user.save()
|
user.save()
|
||||||
|
|
||||||
except (TypeError, ValueError, OverflowError, User.DoesNotExist) as e:
|
except (TypeError, ValueError, OverflowError, User.DoesNotExist) as e:
|
||||||
raise BadRequest(_(f"something went wrong: {e!s}"))
|
raise BadRequest(_(f"something went wrong: {e!s}")) from e
|
||||||
|
|
||||||
return ActivateUser(success=True)
|
return ActivateUser(success=True)
|
||||||
|
|
||||||
|
|
@ -322,7 +322,7 @@ class ConfirmResetPassword(BaseMutation):
|
||||||
return ConfirmResetPassword(success=True)
|
return ConfirmResetPassword(success=True)
|
||||||
|
|
||||||
except (TypeError, ValueError, OverflowError, ValidationError, User.DoesNotExist) as e:
|
except (TypeError, ValueError, OverflowError, ValidationError, User.DoesNotExist) as e:
|
||||||
raise BadRequest(_(f"something went wrong: {e!s}"))
|
raise BadRequest(_(f"something went wrong: {e!s}")) from e
|
||||||
|
|
||||||
|
|
||||||
class UploadAvatar(BaseMutation):
|
class UploadAvatar(BaseMutation):
|
||||||
|
|
@ -339,6 +339,6 @@ class UploadAvatar(BaseMutation):
|
||||||
info.context.user.avatar = avatar
|
info.context.user.avatar = avatar
|
||||||
info.context.user.save()
|
info.context.user.save()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise BadRequest(str(e))
|
raise BadRequest(str(e)) from e
|
||||||
|
|
||||||
return UploadAvatar(user=info.context.user)
|
return UploadAvatar(user=info.context.user)
|
||||||
|
|
|
||||||
|
|
@ -16,87 +16,179 @@ class Migration(migrations.Migration):
|
||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('auth', '0012_alter_user_first_name_max_length'),
|
("auth", "0012_alter_user_first_name_max_length"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Group',
|
name="Group",
|
||||||
fields=[
|
fields=[],
|
||||||
],
|
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'group',
|
"verbose_name": "group",
|
||||||
'verbose_name_plural': 'groups',
|
"verbose_name_plural": "groups",
|
||||||
'proxy': True,
|
"proxy": True,
|
||||||
'indexes': [],
|
"indexes": [],
|
||||||
'constraints': [],
|
"constraints": [],
|
||||||
},
|
},
|
||||||
bases=('auth.group',),
|
bases=("auth.group",),
|
||||||
managers=[
|
managers=[
|
||||||
('objects', django.contrib.auth.models.GroupManager()),
|
("objects", django.contrib.auth.models.GroupManager()),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='User',
|
name="User",
|
||||||
fields=[
|
fields=[
|
||||||
('password', models.CharField(max_length=128, verbose_name='password')),
|
("password", models.CharField(max_length=128, verbose_name="password")),
|
||||||
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
|
("last_login", models.DateTimeField(blank=True, null=True, verbose_name="last login")),
|
||||||
('is_superuser', models.BooleanField(default=False,
|
(
|
||||||
help_text='Designates that this user has all permissions without explicitly assigning them.',
|
"is_superuser",
|
||||||
verbose_name='superuser status')),
|
models.BooleanField(
|
||||||
('is_staff', models.BooleanField(default=False,
|
default=False,
|
||||||
help_text='Designates whether the user can log into this admin site.',
|
help_text="Designates that this user has all permissions without explicitly assigning them.",
|
||||||
verbose_name='staff status')),
|
verbose_name="superuser status",
|
||||||
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
|
),
|
||||||
('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_staff",
|
||||||
('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True,
|
models.BooleanField(
|
||||||
help_text='when the object first appeared on the database',
|
default=False,
|
||||||
verbose_name='created')),
|
help_text="Designates whether the user can log into this admin site.",
|
||||||
('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True,
|
verbose_name="staff status",
|
||||||
help_text='when the object was last modified',
|
),
|
||||||
verbose_name='modified')),
|
),
|
||||||
('email',
|
("date_joined", models.DateTimeField(default=django.utils.timezone.now, verbose_name="date joined")),
|
||||||
models.EmailField(help_text='user email address', max_length=254, unique=True, verbose_name='email')),
|
(
|
||||||
('phone_number',
|
"uuid",
|
||||||
models.CharField(blank=True, help_text='user phone number', max_length=20, null=True, unique=True,
|
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",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"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"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"email",
|
||||||
|
models.EmailField(
|
||||||
|
help_text="user email address", max_length=254, unique=True, verbose_name="email"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"phone_number",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
help_text="user phone number",
|
||||||
|
max_length=20,
|
||||||
|
null=True,
|
||||||
|
unique=True,
|
||||||
validators=[vibes_auth.validators.validate_phone_number],
|
validators=[vibes_auth.validators.validate_phone_number],
|
||||||
verbose_name='phone_number')),
|
verbose_name="phone_number",
|
||||||
('first_name', models.CharField(blank=True, max_length=150, null=True, verbose_name='first_name')),
|
),
|
||||||
('last_name', models.CharField(blank=True, max_length=150, null=True, verbose_name='last_name')),
|
),
|
||||||
('avatar', models.ImageField(blank=True, help_text='user profile image', null=True,
|
("first_name", models.CharField(blank=True, max_length=150, null=True, verbose_name="first_name")),
|
||||||
upload_to=vibes_auth.models.User.get_uuid_as_path, verbose_name='avatar')),
|
("last_name", models.CharField(blank=True, max_length=150, null=True, verbose_name="last_name")),
|
||||||
('is_verified',
|
(
|
||||||
models.BooleanField(default=False, help_text='user verification status', verbose_name='is verified')),
|
"avatar",
|
||||||
('is_active', models.BooleanField(default=False, help_text='unselect this instead of deleting accounts',
|
models.ImageField(
|
||||||
verbose_name='is_active')),
|
blank=True,
|
||||||
('is_subscribed', models.BooleanField(default=False, help_text="user's newsletter subscription status",
|
help_text="user profile image",
|
||||||
verbose_name='is_subscribed')),
|
null=True,
|
||||||
('activation_token', models.UUIDField(default=uuid.uuid4, verbose_name='activation token')),
|
upload_to=vibes_auth.models.User.get_uuid_as_path,
|
||||||
('language', models.CharField(
|
verbose_name="avatar",
|
||||||
choices=[('en-GB', 'English (British)'), ('ar-AR', 'العربية'), ('cs-CZ', 'Česky'),
|
),
|
||||||
('da-DK', 'Dansk'), ('de-DE', 'Deutsch'), ('en-US', 'English (American)'),
|
),
|
||||||
('es-ES', 'Español'), ('fr-FR', 'Français'), ('hi-IN', 'हिंदी'), ('it-IT', 'Italiano'),
|
(
|
||||||
('ja-JP', '日本語'), ('kk-KZ', 'Қазақ'), ('nl-NL', 'Nederlands'), ('pl-PL', 'Polska'),
|
"is_verified",
|
||||||
('pt-BR', 'Português'), ('ro-RO', 'Română'), ('ru-RU', 'Русский'),
|
models.BooleanField(
|
||||||
('zh-hans', '简体中文')], default='en-GB', max_length=7)),
|
default=False, help_text="user verification status", verbose_name="is verified"
|
||||||
('attributes', models.JSONField(blank=True, default=dict, null=True, verbose_name='attributes')),
|
),
|
||||||
('groups', models.ManyToManyField(blank=True,
|
),
|
||||||
help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.',
|
(
|
||||||
related_name='user_set', related_query_name='user', to='auth.group',
|
"is_active",
|
||||||
verbose_name='groups')),
|
models.BooleanField(
|
||||||
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.',
|
default=False, help_text="unselect this instead of deleting accounts", verbose_name="is_active"
|
||||||
related_name='user_set', related_query_name='user',
|
),
|
||||||
to='auth.permission', verbose_name='user permissions')),
|
),
|
||||||
|
(
|
||||||
|
"is_subscribed",
|
||||||
|
models.BooleanField(
|
||||||
|
default=False, help_text="user's newsletter subscription status", verbose_name="is_subscribed"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("activation_token", models.UUIDField(default=uuid.uuid4, verbose_name="activation token")),
|
||||||
|
(
|
||||||
|
"language",
|
||||||
|
models.CharField(
|
||||||
|
choices=[
|
||||||
|
("en-GB", "English (British)"),
|
||||||
|
("ar-AR", "العربية"),
|
||||||
|
("cs-CZ", "Česky"),
|
||||||
|
("da-DK", "Dansk"),
|
||||||
|
("de-DE", "Deutsch"),
|
||||||
|
("en-US", "English (American)"),
|
||||||
|
("es-ES", "Español"),
|
||||||
|
("fr-FR", "Français"),
|
||||||
|
("hi-IN", "हिंदी"),
|
||||||
|
("it-IT", "Italiano"),
|
||||||
|
("ja-JP", "日本語"),
|
||||||
|
("kk-KZ", "Қазақ"),
|
||||||
|
("nl-NL", "Nederlands"),
|
||||||
|
("pl-PL", "Polska"),
|
||||||
|
("pt-BR", "Português"),
|
||||||
|
("ro-RO", "Română"),
|
||||||
|
("ru-RU", "Русский"),
|
||||||
|
("zh-hans", "简体中文"),
|
||||||
|
],
|
||||||
|
default="en-GB",
|
||||||
|
max_length=7,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("attributes", models.JSONField(blank=True, default=dict, null=True, verbose_name="attributes")),
|
||||||
|
(
|
||||||
|
"groups",
|
||||||
|
models.ManyToManyField(
|
||||||
|
blank=True,
|
||||||
|
help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.",
|
||||||
|
related_name="user_set",
|
||||||
|
related_query_name="user",
|
||||||
|
to="auth.group",
|
||||||
|
verbose_name="groups",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"user_permissions",
|
||||||
|
models.ManyToManyField(
|
||||||
|
blank=True,
|
||||||
|
help_text="Specific permissions for this user.",
|
||||||
|
related_name="user_set",
|
||||||
|
related_query_name="user",
|
||||||
|
to="auth.permission",
|
||||||
|
verbose_name="user permissions",
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'user',
|
"verbose_name": "user",
|
||||||
'verbose_name_plural': 'users',
|
"verbose_name_plural": "users",
|
||||||
'swappable': 'AUTH_USER_MODEL',
|
"swappable": "AUTH_USER_MODEL",
|
||||||
},
|
},
|
||||||
managers=[
|
managers=[
|
||||||
('objects', vibes_auth.managers.UserManager()),
|
("objects", vibes_auth.managers.UserManager()),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -4,37 +4,34 @@ from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('token_blacklist', '0012_alter_outstandingtoken_user'),
|
("token_blacklist", "0012_alter_outstandingtoken_user"),
|
||||||
('vibes_auth', '0001_initial'),
|
("vibes_auth", "0001_initial"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='BlacklistedToken',
|
name="BlacklistedToken",
|
||||||
fields=[
|
fields=[],
|
||||||
],
|
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'blacklisted token',
|
"verbose_name": "blacklisted token",
|
||||||
'verbose_name_plural': 'blacklisted tokens',
|
"verbose_name_plural": "blacklisted tokens",
|
||||||
'proxy': True,
|
"proxy": True,
|
||||||
'indexes': [],
|
"indexes": [],
|
||||||
'constraints': [],
|
"constraints": [],
|
||||||
},
|
},
|
||||||
bases=('token_blacklist.blacklistedtoken',),
|
bases=("token_blacklist.blacklistedtoken",),
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='OutstandingToken',
|
name="OutstandingToken",
|
||||||
fields=[
|
fields=[],
|
||||||
],
|
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'outstanding token',
|
"verbose_name": "outstanding token",
|
||||||
'verbose_name_plural': 'outstanding tokens',
|
"verbose_name_plural": "outstanding tokens",
|
||||||
'proxy': True,
|
"proxy": True,
|
||||||
'indexes': [],
|
"indexes": [],
|
||||||
'constraints': [],
|
"constraints": [],
|
||||||
},
|
},
|
||||||
bases=('token_blacklist.outstandingtoken',),
|
bases=("token_blacklist.outstandingtoken",),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -5,54 +5,53 @@ from django.db.models.functions import Lower
|
||||||
def forwards(apps, schema_editor):
|
def forwards(apps, schema_editor):
|
||||||
if schema_editor:
|
if schema_editor:
|
||||||
pass
|
pass
|
||||||
User = apps.get_model('vibes_auth', 'User')
|
User = apps.get_model("vibes_auth", "User")
|
||||||
User.objects.all().update(language=Lower('language'))
|
User.objects.all().update(language=Lower("language"))
|
||||||
|
|
||||||
|
|
||||||
def backwards(apps, schema_editor):
|
def backwards(apps, schema_editor):
|
||||||
if schema_editor:
|
if schema_editor:
|
||||||
pass
|
pass
|
||||||
User = apps.get_model('vibes_auth', 'User')
|
User = apps.get_model("vibes_auth", "User")
|
||||||
for u in User.objects.all():
|
for u in User.objects.all():
|
||||||
parts = u.language.split('-', 1)
|
parts = u.language.split("-", 1)
|
||||||
if len(parts) == 2:
|
if len(parts) == 2:
|
||||||
u.language = f"{parts[0].lower()}-{parts[1].upper()}"
|
u.language = f"{parts[0].lower()}-{parts[1].upper()}"
|
||||||
u.save(update_fields=['language'])
|
u.save(update_fields=["language"])
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('vibes_auth', '0002_blacklistedtoken_outstandingtoken'),
|
("vibes_auth", "0002_blacklistedtoken_outstandingtoken"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.RunPython(forwards, backwards),
|
migrations.RunPython(forwards, backwards),
|
||||||
|
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='user',
|
model_name="user",
|
||||||
name='language',
|
name="language",
|
||||||
field=models.CharField(
|
field=models.CharField(
|
||||||
choices=[
|
choices=[
|
||||||
('en-gb', 'English (British)'),
|
("en-gb", "English (British)"),
|
||||||
('ar-ar', 'العربية'),
|
("ar-ar", "العربية"),
|
||||||
('cs-cz', 'Česky'),
|
("cs-cz", "Česky"),
|
||||||
('da-dk', 'Dansk'),
|
("da-dk", "Dansk"),
|
||||||
('de-de', 'Deutsch'),
|
("de-de", "Deutsch"),
|
||||||
('en-us', 'English (American)'),
|
("en-us", "English (American)"),
|
||||||
('es-es', 'Español'),
|
("es-es", "Español"),
|
||||||
('fr-fr', 'Français'),
|
("fr-fr", "Français"),
|
||||||
('hi-in', 'हिंदी'),
|
("hi-in", "हिंदी"),
|
||||||
('it-it', 'Italiano'),
|
("it-it", "Italiano"),
|
||||||
('ja-jp', '日本語'),
|
("ja-jp", "日本語"),
|
||||||
('kk-kz', 'Қазақ'),
|
("kk-kz", "Қазақ"),
|
||||||
('nl-nl', 'Nederlands'),
|
("nl-nl", "Nederlands"),
|
||||||
('pl-pl', 'Polska'),
|
("pl-pl", "Polska"),
|
||||||
('pt-br', 'Português'),
|
("pt-br", "Português"),
|
||||||
('ro-ro', 'Română'),
|
("ro-ro", "Română"),
|
||||||
('ru-ru', 'Русский'),
|
("ru-ru", "Русский"),
|
||||||
('zh-hans', '简体中文'),
|
("zh-hans", "简体中文"),
|
||||||
],
|
],
|
||||||
default='en-gb',
|
default="en-gb",
|
||||||
max_length=7,
|
max_length=7,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import uuid
|
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
from django.contrib.auth.models import AbstractUser
|
from django.contrib.auth.models import AbstractUser
|
||||||
|
|
@ -21,6 +20,7 @@ from rest_framework_simplejwt.token_blacklist.models import (
|
||||||
OutstandingToken as BaseOutstandingToken,
|
OutstandingToken as BaseOutstandingToken,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from blog.models import Post
|
||||||
from core.abstract import NiceModel
|
from core.abstract import NiceModel
|
||||||
from core.models import Order, Wishlist
|
from core.models import Order, Wishlist
|
||||||
from evibes.settings import LANGUAGE_CODE, LANGUAGES
|
from evibes.settings import LANGUAGE_CODE, LANGUAGES
|
||||||
|
|
@ -83,8 +83,8 @@ class User(AbstractUser, NiceModel):
|
||||||
def get_uuid_as_path(self, *args):
|
def get_uuid_as_path(self, *args):
|
||||||
return str(self.uuid) + "/" + args[0]
|
return str(self.uuid) + "/" + args[0]
|
||||||
|
|
||||||
email: str = EmailField(_("email"), unique=True, help_text=_("user email address")) # type: ignore
|
email = EmailField(_("email"), unique=True, help_text=_("user email address"))
|
||||||
phone_number: str = CharField( # type: ignore
|
phone_number = CharField(
|
||||||
_("phone_number"),
|
_("phone_number"),
|
||||||
max_length=20,
|
max_length=20,
|
||||||
unique=True,
|
unique=True,
|
||||||
|
|
@ -95,9 +95,10 @@ class User(AbstractUser, NiceModel):
|
||||||
validate_phone_number,
|
validate_phone_number,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
username = None
|
username: None = None # type: ignore [assignment]
|
||||||
first_name: str = CharField(_("first_name"), max_length=150, blank=True, null=True) # type: ignore
|
posts: "Post"
|
||||||
last_name: str = CharField(_("last_name"), max_length=150, blank=True, null=True) # type: ignore
|
first_name = CharField(_("first_name"), max_length=150, blank=True, null=True) # type: ignore [assignment]
|
||||||
|
last_name = CharField(_("last_name"), max_length=150, blank=True, null=True) # type: ignore [assignment]
|
||||||
avatar = ImageField(
|
avatar = ImageField(
|
||||||
null=True,
|
null=True,
|
||||||
verbose_name=_("avatar"),
|
verbose_name=_("avatar"),
|
||||||
|
|
@ -106,28 +107,28 @@ class User(AbstractUser, NiceModel):
|
||||||
help_text=_("user profile image"),
|
help_text=_("user profile image"),
|
||||||
)
|
)
|
||||||
|
|
||||||
is_verified: bool = BooleanField( # type: ignore
|
is_verified = BooleanField(
|
||||||
default=False,
|
default=False,
|
||||||
verbose_name=_("is verified"),
|
verbose_name=_("is verified"),
|
||||||
help_text=_("user verification status"),
|
help_text=_("user verification status"),
|
||||||
)
|
)
|
||||||
is_active: bool = BooleanField( # type: ignore
|
is_active = BooleanField(
|
||||||
_("is_active"),
|
_("is_active"),
|
||||||
default=False,
|
default=False,
|
||||||
help_text=_("unselect this instead of deleting accounts"),
|
help_text=_("unselect this instead of deleting accounts"),
|
||||||
)
|
)
|
||||||
is_subscribed: bool = BooleanField( # type: ignore
|
is_subscribed = BooleanField(
|
||||||
verbose_name=_("is_subscribed"), help_text=_("user's newsletter subscription status"), default=False
|
verbose_name=_("is_subscribed"), help_text=_("user's newsletter subscription status"), default=False
|
||||||
)
|
)
|
||||||
|
|
||||||
activation_token: uuid = UUIDField(default=uuid4, verbose_name=_("activation token")) # type: ignore
|
activation_token = UUIDField(default=uuid4, verbose_name=_("activation token"))
|
||||||
language: str = CharField(choices=LANGUAGES, default=LANGUAGE_CODE, null=False, blank=False, max_length=7) # type: ignore
|
language = CharField(choices=LANGUAGES, default=LANGUAGE_CODE, null=False, blank=False, max_length=7)
|
||||||
attributes: dict = JSONField(verbose_name=_("attributes"), default=dict, blank=True, null=True) # type: ignore
|
attributes = JSONField(verbose_name=_("attributes"), default=dict, blank=True, null=True)
|
||||||
|
|
||||||
USERNAME_FIELD = "email"
|
USERNAME_FIELD = "email"
|
||||||
REQUIRED_FIELDS = []
|
REQUIRED_FIELDS = []
|
||||||
# noinspection PyClassVar
|
# noinspection PyClassVar
|
||||||
objects = UserManager() # type: ignore
|
objects = UserManager() # type: ignore [misc, assignment]
|
||||||
|
|
||||||
payments_balance: "Balance"
|
payments_balance: "Balance"
|
||||||
user_related_wishlist: "Wishlist"
|
user_related_wishlist: "Wishlist"
|
||||||
|
|
@ -190,11 +191,6 @@ class OutstandingToken(BaseOutstandingToken):
|
||||||
It does not add additional fields or logic to the base model but allows for
|
It does not add additional fields or logic to the base model but allows for
|
||||||
overloading or extending its default functionality as required.
|
overloading or extending its default functionality as required.
|
||||||
|
|
||||||
Attributes:
|
|
||||||
Meta (class): Contains metadata for the model, including options such as
|
|
||||||
whether the model is a proxy, the human-readable name for the model, and
|
|
||||||
the plural form of that name.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
@ -214,8 +210,6 @@ class BlacklistedToken(BaseBlacklistedToken):
|
||||||
meta options for the model, affecting its database and administrative
|
meta options for the model, affecting its database and administrative
|
||||||
representation.
|
representation.
|
||||||
|
|
||||||
Attributes:
|
|
||||||
None
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ class TokenObtainSerializer(Serializer):
|
||||||
def __init__(self, *args, **kwargs) -> None:
|
def __init__(self, *args, **kwargs) -> None:
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
self.user = None
|
self.user: User | None = None
|
||||||
self.fields[self.username_field] = CharField(write_only=True)
|
self.fields[self.username_field] = CharField(write_only=True)
|
||||||
self.fields["password"] = PasswordField()
|
self.fields["password"] = PasswordField()
|
||||||
|
|
||||||
|
|
@ -124,19 +124,22 @@ class TokenObtainSerializer(Serializer):
|
||||||
with suppress(KeyError):
|
with suppress(KeyError):
|
||||||
authenticate_kwargs["request"] = self.context["request"]
|
authenticate_kwargs["request"] = self.context["request"]
|
||||||
|
|
||||||
self.user = authenticate(**authenticate_kwargs) # type: ignore
|
self.user: User | None = authenticate(**authenticate_kwargs)
|
||||||
|
|
||||||
if not api_settings.USER_AUTHENTICATION_RULE(self.user):
|
if not api_settings.USER_AUTHENTICATION_RULE(self.user):
|
||||||
raise AuthenticationFailed(
|
raise AuthenticationFailed(
|
||||||
self.error_messages["no_active_account"],
|
self.error_messages["no_active_account"],
|
||||||
_("no active account"), # type: ignore
|
str(_("no active account")),
|
||||||
)
|
)
|
||||||
|
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_token(cls, user: AuthUser) -> Token:
|
def get_token(cls, user: AuthUser) -> Token:
|
||||||
return cls.token_class.for_user(user) # type: ignore
|
if cls.token_class is not None:
|
||||||
|
return cls.token_class.for_user(user)
|
||||||
|
else:
|
||||||
|
raise RuntimeError(_("must set token_class attribute on class."))
|
||||||
|
|
||||||
|
|
||||||
class TokenObtainPairSerializer(TokenObtainSerializer):
|
class TokenObtainPairSerializer(TokenObtainSerializer):
|
||||||
|
|
@ -147,15 +150,19 @@ class TokenObtainPairSerializer(TokenObtainSerializer):
|
||||||
|
|
||||||
logger.debug("Data validated")
|
logger.debug("Data validated")
|
||||||
|
|
||||||
refresh = self.get_token(self.user) # type: ignore
|
if self.user is None:
|
||||||
|
raise ValidationError(_("no active account"))
|
||||||
|
|
||||||
|
refresh = self.get_token(self.user)
|
||||||
data["refresh"] = str(refresh)
|
data["refresh"] = str(refresh)
|
||||||
data["access"] = str(refresh.access_token) # type: ignore
|
# noinspection PyUnresolvedReferences
|
||||||
|
data["access"] = str(refresh.access_token) # type: ignore [attr-defined]
|
||||||
data["user"] = UserSerializer(self.user).data
|
data["user"] = UserSerializer(self.user).data
|
||||||
|
|
||||||
logger.debug("Data formed")
|
logger.debug("Data formed")
|
||||||
|
|
||||||
if api_settings.UPDATE_LAST_LOGIN:
|
if api_settings.UPDATE_LAST_LOGIN:
|
||||||
update_last_login(self.user, self.user) # type: ignore
|
update_last_login(self.user, self.user)
|
||||||
logger.debug("Updated last login")
|
logger.debug("Updated last login")
|
||||||
|
|
||||||
logger.debug("Returning data")
|
logger.debug("Returning data")
|
||||||
|
|
@ -183,7 +190,8 @@ class TokenRefreshSerializer(Serializer):
|
||||||
|
|
||||||
data["refresh"] = str(refresh)
|
data["refresh"] = str(refresh)
|
||||||
user = User.objects.get(uuid=refresh.payload["user_uuid"])
|
user = User.objects.get(uuid=refresh.payload["user_uuid"])
|
||||||
data["user"] = UserSerializer(user).data # type: ignore
|
# noinspection PyTypeChecker
|
||||||
|
data["user"] = UserSerializer(user).data
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
@ -204,18 +212,19 @@ class TokenVerifySerializer(Serializer):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
payload = UntypedToken(attrs["token"]).payload
|
payload = UntypedToken(attrs["token"]).payload
|
||||||
except TokenError:
|
except TokenError as te:
|
||||||
raise ValidationError(_("invalid token"))
|
raise ValidationError(_("invalid token")) from te
|
||||||
|
|
||||||
try:
|
try:
|
||||||
user_uuid = payload["user_uuid"]
|
user_uuid = payload["user_uuid"]
|
||||||
user = User.objects.get(uuid=user_uuid)
|
user = User.objects.get(uuid=user_uuid)
|
||||||
except KeyError:
|
except KeyError as ke:
|
||||||
raise ValidationError(_("no user uuid claim present in token"))
|
raise ValidationError(_("no user uuid claim present in token")) from ke
|
||||||
except User.DoesNotExist:
|
except User.DoesNotExist as dne:
|
||||||
raise ValidationError(_("user does not exist"))
|
raise ValidationError(_("user does not exist")) from dne
|
||||||
|
|
||||||
attrs["user"] = UserSerializer(user).data # type: ignore
|
# noinspection PyTypeChecker
|
||||||
|
attrs["user"] = UserSerializer(user).data
|
||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ def send_verification_email_task(user_pk: str) -> tuple[bool, str]:
|
||||||
return False, f"Something went wrong while sending an email: {e!s}"
|
return False, f"Something went wrong while sending an email: {e!s}"
|
||||||
|
|
||||||
else:
|
else:
|
||||||
return True, user.uuid
|
return True, str(user.uuid)
|
||||||
|
|
||||||
|
|
||||||
@shared_task(queue="default")
|
@shared_task(queue="default")
|
||||||
|
|
@ -95,4 +95,4 @@ def send_reset_password_email_task(user_pk: str) -> tuple[bool, str]:
|
||||||
return False, f"Something went wrong while sending an email: {e!s}"
|
return False, f"Something went wrong while sending an email: {e!s}"
|
||||||
|
|
||||||
else:
|
else:
|
||||||
return True, user.uuid
|
return True, str(user.uuid)
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,8 @@ class TokenObtainPairView(TokenViewBase):
|
||||||
subject to rate limiting depending on the global DEBUG setting.
|
subject to rate limiting depending on the global DEBUG setting.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
serializer_class = TokenObtainPairSerializer # type: ignore
|
serializer_class = TokenObtainPairSerializer
|
||||||
_serializer_class = TokenObtainPairSerializer # type: ignore
|
_serializer_class = TokenObtainPairSerializer
|
||||||
|
|
||||||
@method_decorator(ratelimit(key="ip", rate="10/h" if not DEBUG else "888/h"))
|
@method_decorator(ratelimit(key="ip", rate="10/h" if not DEBUG else "888/h"))
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
|
|
@ -82,8 +82,8 @@ class TokenRefreshView(TokenViewBase):
|
||||||
whether the application is in DEBUG mode or not.
|
whether the application is in DEBUG mode or not.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
serializer_class = TokenRefreshSerializer # type: ignore
|
serializer_class = TokenRefreshSerializer
|
||||||
_serializer_class = TokenRefreshSerializer # type: ignore
|
_serializer_class = TokenRefreshSerializer
|
||||||
|
|
||||||
@method_decorator(ratelimit(key="ip", rate="10/h" if not DEBUG else "888/h"))
|
@method_decorator(ratelimit(key="ip", rate="10/h" if not DEBUG else "888/h"))
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
|
|
@ -104,8 +104,8 @@ class TokenVerifyView(TokenViewBase):
|
||||||
error response.
|
error response.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
serializer_class = TokenVerifySerializer # type: ignore
|
serializer_class = TokenVerifySerializer
|
||||||
_serializer_class = TokenVerifySerializer # type: ignore
|
_serializer_class = TokenVerifySerializer
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue