video player and model and video guide routing and stuff
This commit is contained in:
@@ -9,7 +9,7 @@ from django.contrib.postgres.fields import ArrayField
|
|||||||
from django.contrib.auth.models import Group
|
from django.contrib.auth.models import Group
|
||||||
from unfold.forms import AdminPasswordChangeForm
|
from unfold.forms import AdminPasswordChangeForm
|
||||||
from unfold.forms import AdminPasswordChangeForm, UserChangeForm, UserCreationForm
|
from unfold.forms import AdminPasswordChangeForm, UserChangeForm, UserCreationForm
|
||||||
|
from utils.admin import ModelAdmin
|
||||||
class UserAddressInLine(TabularInline):
|
class UserAddressInLine(TabularInline):
|
||||||
model = UserAddressModel
|
model = UserAddressModel
|
||||||
extra = 0
|
extra = 0
|
||||||
@@ -36,6 +36,7 @@ class UserAdmin(BaseUserAdmin, ModelAdmin, ImportExportModelAdmin):
|
|||||||
fieldsets = (
|
fieldsets = (
|
||||||
('اطلاعات شخصی', {'fields': ('first_name', 'last_name', 'profile_photo', 'password', 'gender', 'birth_date'),}),
|
('اطلاعات شخصی', {'fields': ('first_name', 'last_name', 'profile_photo', 'password', 'gender', 'birth_date'),}),
|
||||||
('اطلاعات ارتباطی', {'fields': ('phone', 'email'),}),
|
('اطلاعات ارتباطی', {'fields': ('phone', 'email'),}),
|
||||||
|
('دسترسی های وبسایت', {'fields': ('is_superuser', 'video_uploader'),}),
|
||||||
)
|
)
|
||||||
empty_value_display = 'ثبت نشده'
|
empty_value_display = 'ثبت نشده'
|
||||||
add_fieldsets = (
|
add_fieldsets = (
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.1.2 on 2025-02-14 22:08
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('account', '0010_useraddressmodel_is_main'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='user',
|
||||||
|
name='video_uploader',
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.1.2 on 2025-02-14 23:12
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('account', '0011_user_video_uploader'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='user',
|
||||||
|
name='video_uploader',
|
||||||
|
field=models.BooleanField(default=False, help_text='اپلود کننده ی ویدیویی اموزشی پنل ادمین', verbose_name='اپلودر اموزش'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -50,6 +50,7 @@ class User(AbstractBaseUser, PermissionsMixin):
|
|||||||
date_joined = models.DateTimeField(auto_now_add=True, verbose_name='تاریخ ثبتنام')
|
date_joined = models.DateTimeField(auto_now_add=True, verbose_name='تاریخ ثبتنام')
|
||||||
otp_hash = models.CharField(max_length=64, null=True, blank=True, verbose_name='کد یک بار مصرف')
|
otp_hash = models.CharField(max_length=64, null=True, blank=True, verbose_name='کد یک بار مصرف')
|
||||||
otp_expiry = models.DateTimeField(null=True, blank=True, verbose_name='تاریخ تمام شدن کد یک بار مصرف')
|
otp_expiry = models.DateTimeField(null=True, blank=True, verbose_name='تاریخ تمام شدن کد یک بار مصرف')
|
||||||
|
video_uploader = models.BooleanField(default=False, help_text='اپلود کننده ی ویدیویی اموزشی پنل ادمین', verbose_name='اپلودر اموزش')
|
||||||
objects = UserManager()
|
objects = UserManager()
|
||||||
|
|
||||||
USERNAME_FIELD = 'phone'
|
USERNAME_FIELD = 'phone'
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from .models import *
|
from .models import *
|
||||||
from unfold.admin import ModelAdmin
|
|
||||||
|
|
||||||
from import_export.admin import ImportExportModelAdmin
|
from import_export.admin import ImportExportModelAdmin
|
||||||
from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm
|
from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm
|
||||||
from unfold.contrib.forms.widgets import ArrayWidget, WysiwygWidget
|
from unfold.contrib.forms.widgets import ArrayWidget, WysiwygWidget
|
||||||
from django.contrib.postgres.fields import ArrayField
|
from django.contrib.postgres.fields import ArrayField
|
||||||
|
from utils.admin import ModelAdmin
|
||||||
|
|
||||||
@admin.register(BlogModel)
|
@admin.register(BlogModel)
|
||||||
class BlogModelAdmin(ModelAdmin, ImportExportModelAdmin):
|
class BlogModelAdmin(ModelAdmin, ImportExportModelAdmin):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from .models import *
|
from .models import *
|
||||||
from unfold.admin import ModelAdmin
|
|
||||||
|
|
||||||
from import_export.admin import ImportExportModelAdmin
|
from import_export.admin import ImportExportModelAdmin
|
||||||
from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm
|
from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm
|
||||||
from unfold.contrib.forms.widgets import ArrayWidget, WysiwygWidget
|
from unfold.contrib.forms.widgets import ArrayWidget, WysiwygWidget
|
||||||
from django.contrib.postgres.fields import ArrayField
|
from django.contrib.postgres.fields import ArrayField
|
||||||
|
from utils.admin import ModelAdmin
|
||||||
|
|
||||||
@admin.register(ProductChatModel)
|
@admin.register(ProductChatModel)
|
||||||
class ProductChatAdmin(ModelAdmin, ImportExportModelAdmin):
|
class ProductChatAdmin(ModelAdmin, ImportExportModelAdmin):
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ UNFOLD = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
"BORDER_RADIUS": "8px",
|
"BORDER_RADIUS": "20px",
|
||||||
"SHOW_HISTORY": True,
|
"SHOW_HISTORY": True,
|
||||||
"SHOW_VIEW_ON_SITE": True,
|
"SHOW_VIEW_ON_SITE": True,
|
||||||
"ENVIRONMENT": "core.settings.environment_callback",
|
"ENVIRONMENT": "core.settings.environment_callback",
|
||||||
@@ -93,6 +93,12 @@ UNFOLD = {
|
|||||||
"icon": "dashboard",
|
"icon": "dashboard",
|
||||||
"link": reverse_lazy("admin:index"),
|
"link": reverse_lazy("admin:index"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"title": _("آموزش استفاده از پنل"),
|
||||||
|
"icon": "school",
|
||||||
|
"link": reverse_lazy("admin:home_learnvideomodel_changelist"),
|
||||||
|
"badge": "utils.admin.new_learn_video_count",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"title": _("سفارشات"),
|
"title": _("سفارشات"),
|
||||||
"icon": "shopping_cart",
|
"icon": "shopping_cart",
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
@@ -26,6 +26,7 @@ urlpatterns = [
|
|||||||
path('tickets/', include('ticket.urls')),
|
path('tickets/', include('ticket.urls')),
|
||||||
path('blogs/', include('blog.urls')),
|
path('blogs/', include('blog.urls')),
|
||||||
path('order/', include('order.urls')),
|
path('order/', include('order.urls')),
|
||||||
|
path('home/', include('home.urls')),
|
||||||
path('', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
|
path('', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
+33
-4
@@ -1,14 +1,15 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from .models import *
|
from .models import *
|
||||||
from unfold.admin import ModelAdmin
|
from unfold.admin import ModelAdmin as UnfoldModelAdmin
|
||||||
|
|
||||||
from import_export.admin import ImportExportModelAdmin
|
from import_export.admin import ImportExportModelAdmin
|
||||||
from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm
|
from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm
|
||||||
from unfold.contrib.forms.widgets import ArrayWidget, WysiwygWidget
|
from unfold.contrib.forms.widgets import ArrayWidget, WysiwygWidget
|
||||||
from django.contrib.postgres.fields import ArrayField
|
from django.contrib.postgres.fields import ArrayField
|
||||||
|
from unfold.decorators import action, display
|
||||||
|
from django.utils.html import format_html
|
||||||
|
from unfold.decorators import display
|
||||||
|
from utils.admin import ModelAdmin
|
||||||
@admin.register(ShowCaseSlider)
|
@admin.register(ShowCaseSlider)
|
||||||
class ShowCaseSliderAdmin(ModelAdmin, ImportExportModelAdmin):
|
class ShowCaseSliderAdmin(ModelAdmin, ImportExportModelAdmin):
|
||||||
import_form_class = ImportForm
|
import_form_class = ImportForm
|
||||||
@@ -24,6 +25,34 @@ class ShowCaseSliderAdmin(ModelAdmin, ImportExportModelAdmin):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@admin.register(LearnVideoModel)
|
||||||
|
class LearnVideoAdmin(UnfoldModelAdmin):
|
||||||
|
list_display = ['title', 'section', 'display_viewd']
|
||||||
|
search_fields = ['title', 'section']
|
||||||
|
compressed_fields = False
|
||||||
|
list_filter = ['section']
|
||||||
|
warn_unsaved_form = True
|
||||||
|
change_form_template = 'video_change_form_after.html'
|
||||||
|
formfield_overrides = {
|
||||||
|
ArrayField: {
|
||||||
|
"widget": ArrayWidget,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@display(description='دیده شده')
|
||||||
|
def display_viewd(self, instance):
|
||||||
|
if instance.viewd:
|
||||||
|
svg = f'<a href="/home/video/view/{instance.id}"><svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 24 24"><path fill="green" d="M12 16q1.875 0 3.188-1.312T16.5 11.5t-1.312-3.187T12 7T8.813 8.313T7.5 11.5t1.313 3.188T12 16m0-1.8q-1.125 0-1.912-.788T9.3 11.5t.788-1.912T12 8.8t1.913.788t.787 1.912t-.787 1.913T12 14.2m0 4.8q-3.65 0-6.65-2.037T1 11.5q1.35-3.425 4.35-5.462T12 4t6.65 2.038T23 11.5q-1.35 3.425-4.35 5.463T12 19m0-2q2.825 0 5.188-1.487T20.8 11.5q-1.25-2.525-3.613-4.012T12 6T6.813 7.488T3.2 11.5q1.25 2.525 3.613 4.013T12 17"/></svg></a>'
|
||||||
|
else:
|
||||||
|
svg = f'<a href="/home/video/view/{instance.id}"><svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 24 24"><path fill="#c30009" d="m19.1 21.9l-3.5-3.45q-.875.275-1.775.413T12 19q-3.35 0-6.125-1.8t-4.35-4.75q-.125-.225-.187-.462t-.063-.488t.063-.488t.187-.462q.55-.975 1.175-1.9T4.15 7L2.075 4.9Q1.8 4.625 1.8 4.213t.3-.713q.275-.275.7-.275t.7.275l17 17q.275.275.288.688t-.288.712q-.275.275-.7.275t-.7-.275M12 16q.275 0 .525-.025t.5-.1l-5.4-5.4q-.075.25-.1.5T7.5 11.5q0 1.875 1.313 3.188T12 16m0-12q3.35 0 6.138 1.813t4.362 4.762q.125.2.188.438t.062.487t-.05.488t-.175.437q-.475.925-1.062 1.75t-1.313 1.55q-.35.35-.825.325t-.825-.375l-2-2q-.175-.175-.225-.413t.025-.487q.1-.325.15-.625t.05-.65q0-1.875-1.312-3.187T12 7q-.35 0-.65.05t-.625.15q-.25.075-.5.025T9.8 7l-.825-.825q-.475-.475-.312-1.1t.787-.8q.625-.125 1.263-.2T12 4m1.975 5.65q.275.325.462.713t.238.812q.025.2-.15.275t-.325-.075l-2.05-2.05Q12 9.175 12.088 9t.287-.175q.475.05.875.263t.725.562"/></svg></a>'
|
||||||
|
|
||||||
|
return format_html(
|
||||||
|
svg
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(SliderModel)
|
@admin.register(SliderModel)
|
||||||
class SliderAdmin(ModelAdmin, ImportExportModelAdmin):
|
class SliderAdmin(ModelAdmin, ImportExportModelAdmin):
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# Generated by Django 5.1.2 on 2025-02-14 21:23
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('home', '0005_alter_showcaseslider_description_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='LearnVideoModel',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('title', models.CharField(max_length=50)),
|
||||||
|
('video', models.FileField(upload_to='learning_video/')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'ویدیوی اموزشی',
|
||||||
|
'verbose_name_plural': 'ویدیوی های اموزشی',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
+29
@@ -0,0 +1,29 @@
|
|||||||
|
# Generated by Django 5.1.2 on 2025-02-14 21:28
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('home', '0006_learnvideomodel'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='learnvideomodel',
|
||||||
|
name='section',
|
||||||
|
field=models.CharField(default='', max_length=40, verbose_name='بخش مربوطه'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='learnvideomodel',
|
||||||
|
name='title',
|
||||||
|
field=models.CharField(max_length=100, verbose_name='عنوان ویدیو'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='learnvideomodel',
|
||||||
|
name='video',
|
||||||
|
field=models.FileField(upload_to='learning_video/', verbose_name='ویدیو'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# Generated by Django 5.1.2 on 2025-02-14 23:12
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('contenttypes', '0002_remove_content_type_name'),
|
||||||
|
('home', '0007_learnvideomodel_section_alter_learnvideomodel_title_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='learnvideomodel',
|
||||||
|
name='content_type',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype', verbose_name='Related Model'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# Generated by Django 5.1.2 on 2025-02-14 23:28
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('contenttypes', '0002_remove_content_type_name'),
|
||||||
|
('home', '0008_learnvideomodel_content_type'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='learnvideomodel',
|
||||||
|
name='content_type',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype', unique=True, verbose_name='مدل مرتبط'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.1.2 on 2025-02-15 00:37
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('home', '0009_alter_learnvideomodel_content_type'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='learnvideomodel',
|
||||||
|
name='viewd',
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# Generated by Django 5.1.2 on 2025-02-15 07:48
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('home', '0010_learnvideomodel_viewd'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='learnvideomodel',
|
||||||
|
name='icon',
|
||||||
|
field=models.CharField(default='', max_length=30, verbose_name='ایکون'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='learnvideomodel',
|
||||||
|
name='viewd',
|
||||||
|
field=models.BooleanField(default=False, verbose_name='تماشا شده'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# Generated by Django 5.1.2 on 2025-02-16 17:45
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('contenttypes', '0002_remove_content_type_name'),
|
||||||
|
('home', '0011_learnvideomodel_icon_alter_learnvideomodel_viewd'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='learnvideomodel',
|
||||||
|
name='content_type',
|
||||||
|
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype', verbose_name='مدل مرتبط'),
|
||||||
|
),
|
||||||
|
]
|
||||||
+36
-2
@@ -1,6 +1,6 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from product.models import ProductModel
|
from product.models import ProductModel
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
class SliderModel(models.Model):
|
class SliderModel(models.Model):
|
||||||
link = models.URLField(verbose_name='لینک')
|
link = models.URLField(verbose_name='لینک')
|
||||||
@@ -45,4 +45,38 @@ class ShowCaseSlider(models.Model):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = 'مدل نمایش کیس'
|
verbose_name = 'مدل نمایش کیس'
|
||||||
verbose_name_plural = 'مدل نمایش کیس ها'
|
verbose_name_plural = 'مدل نمایش کیس ها'
|
||||||
|
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
class LearnVideoModel(models.Model):
|
||||||
|
title = models.CharField(max_length=100, verbose_name='عنوان ویدیو')
|
||||||
|
section = models.CharField(max_length=40, verbose_name='بخش مربوطه')
|
||||||
|
video = models.FileField(upload_to='learning_video/', verbose_name='ویدیو')
|
||||||
|
content_type = models.OneToOneField(
|
||||||
|
ContentType,
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
verbose_name='مدل مرتبط', blank=True, null=True, unique=True
|
||||||
|
)
|
||||||
|
icon = models.CharField(max_length=30, verbose_name='ایکون')
|
||||||
|
viewd = models.BooleanField(default=False, verbose_name='تماشا شده')
|
||||||
|
@property
|
||||||
|
def section_url(self):
|
||||||
|
if not self.content_type:
|
||||||
|
return None
|
||||||
|
|
||||||
|
app_label = self.content_type.app_label
|
||||||
|
model_name = self.content_type.model
|
||||||
|
|
||||||
|
try:
|
||||||
|
return reverse(f'admin:{app_label}_{model_name}_changelist')
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.title
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = 'ویدیوی اموزشی'
|
||||||
|
verbose_name_plural = 'ویدیوی های اموزشی'
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
from django.urls import path
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('video/view/<int:pk>', views.ChangeViewVideo.as_view(), name='product-chat-view'),
|
||||||
|
]
|
||||||
+10
-1
@@ -1,10 +1,19 @@
|
|||||||
from django.shortcuts import render
|
from django.shortcuts import render, get_object_or_404, redirect
|
||||||
from rest_framework.views import APIView, Response
|
from rest_framework.views import APIView, Response
|
||||||
from product.models import ProductModel, SubCategoryModel, DollorModel
|
from product.models import ProductModel, SubCategoryModel, DollorModel
|
||||||
from product.serializers import SubCategorySerializer, DynamicProductSerializer
|
from product.serializers import SubCategorySerializer, DynamicProductSerializer
|
||||||
from .serializers import *
|
from .serializers import *
|
||||||
from .models import *
|
from .models import *
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
|
from django.views import View
|
||||||
|
|
||||||
|
|
||||||
|
class ChangeViewVideo(View):
|
||||||
|
def get(self, request, pk):
|
||||||
|
videomodel = get_object_or_404(LearnVideoModel, pk=pk)
|
||||||
|
videomodel.viewd = not videomodel.viewd
|
||||||
|
videomodel.save()
|
||||||
|
return redirect('admin:home_learnvideomodel_changelist')
|
||||||
|
|
||||||
|
|
||||||
class HomeView(APIView):
|
class HomeView(APIView):
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from .models import *
|
from .models import *
|
||||||
from unfold.admin import ModelAdmin, TabularInline, StackedInline
|
from unfold.admin import TabularInline, StackedInline
|
||||||
|
|
||||||
from import_export.admin import ImportExportModelAdmin
|
from import_export.admin import ImportExportModelAdmin
|
||||||
from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm
|
from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm
|
||||||
from unfold.contrib.forms.widgets import ArrayWidget, WysiwygWidget
|
from unfold.contrib.forms.widgets import ArrayWidget, WysiwygWidget
|
||||||
from django.contrib.postgres.fields import ArrayField
|
from django.contrib.postgres.fields import ArrayField
|
||||||
|
from utils.admin import ModelAdmin
|
||||||
|
|
||||||
class OrderItemModelInline(StackedInline):
|
class OrderItemModelInline(StackedInline):
|
||||||
model = OrderItemModel
|
model = OrderItemModel
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# Generated by Django 5.1.2 on 2025-02-14 21:23
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('order', '0004_alter_orderitemmodel_product'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='orderitemmodel',
|
||||||
|
options={'verbose_name': 'ایتم سبد خرید', 'verbose_name_plural': 'ایتم های سبد خرید'},
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -1,15 +1,14 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin, messages
|
||||||
from .models import *
|
from .models import *
|
||||||
from unfold.admin import ModelAdmin, TabularInline, StackedInline
|
from unfold.admin import TabularInline, StackedInline
|
||||||
|
from home.models import LearnVideoModel
|
||||||
from import_export.admin import ImportExportModelAdmin
|
from import_export.admin import ImportExportModelAdmin
|
||||||
from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm
|
from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm
|
||||||
from unfold.contrib.forms.widgets import ArrayWidget, WysiwygWidget
|
from unfold.contrib.forms.widgets import ArrayWidget, WysiwygWidget
|
||||||
from django.contrib.postgres.fields import ArrayField
|
from django.contrib.postgres.fields import ArrayField
|
||||||
from unfold.widgets import (
|
from unfold.widgets import UnfoldAdminColorInputWidget
|
||||||
UnfoldAdminColorInputWidget,
|
|
||||||
)
|
|
||||||
from unfold.decorators import action, display
|
from unfold.decorators import action, display
|
||||||
|
from utils.admin import ModelAdmin
|
||||||
|
|
||||||
@admin.register(ProductVariant)
|
@admin.register(ProductVariant)
|
||||||
class ProductVariantAdmin(ModelAdmin, ImportExportModelAdmin):
|
class ProductVariantAdmin(ModelAdmin, ImportExportModelAdmin):
|
||||||
|
|||||||
@@ -0,0 +1,166 @@
|
|||||||
|
{% extends "admin/base_site.html" %}
|
||||||
|
{% load unfold %}
|
||||||
|
{% load i18n admin_urls static admin_modify %}
|
||||||
|
|
||||||
|
{% block extrahead %}{{ block.super }}
|
||||||
|
<script src="{% url 'admin:jsi18n' %}"></script>
|
||||||
|
{{ media }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block bodyclass %}{{ block.super }} app-{{ opts.app_label }} model-{{ opts.model_name }} change-form{% endblock %}
|
||||||
|
|
||||||
|
{% if not is_popup %}
|
||||||
|
{% block breadcrumbs %}
|
||||||
|
<div class="px-4 lg:px-8">
|
||||||
|
<div class="container mb-6 mx-auto -my-3 lg:mb-12">
|
||||||
|
<ul class="flex flex-wrap">
|
||||||
|
{% url 'admin:index' as link %}
|
||||||
|
{% trans 'Home' as name %}
|
||||||
|
{% include 'unfold/helpers/breadcrumb_item.html' with link=link name=name %}
|
||||||
|
|
||||||
|
{% url 'admin:app_list' app_label=opts.app_label as link %}
|
||||||
|
{% include 'unfold/helpers/breadcrumb_item.html' with link=link name=opts.app_config.verbose_name %}
|
||||||
|
|
||||||
|
{% if has_view_permission %}
|
||||||
|
{% url opts|admin_urlname:'changelist' as link %}
|
||||||
|
{% include 'unfold/helpers/breadcrumb_item.html' with link=link name=opts.verbose_name_plural|capfirst %}
|
||||||
|
{% else %}
|
||||||
|
{% include 'unfold/helpers/breadcrumb_item.html' with link='' name=opts.verbose_name_plural|capfirst %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if add %}
|
||||||
|
{% blocktranslate trimmed with name=opts.verbose_name asvar breadcrumb_name %}
|
||||||
|
Add {{ name }}
|
||||||
|
{% endblocktranslate %}
|
||||||
|
|
||||||
|
{% include 'unfold/helpers/breadcrumb_item.html' with link='' name=breadcrumb_name %}
|
||||||
|
{% else %}
|
||||||
|
{% include 'unfold/helpers/breadcrumb_item.html' with link='' name=original|truncatewords:'18' %}
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% block nav-global %}{% spaceless %}
|
||||||
|
{% if change and not is_popup %}
|
||||||
|
{% block object-tools-items %}
|
||||||
|
{% change_form_object_tools %}
|
||||||
|
{% endblock %}
|
||||||
|
{% endif %}
|
||||||
|
{% endspaceless %}{% endblock %}
|
||||||
|
|
||||||
|
{% block nav-global-side %}
|
||||||
|
{% if has_add_permission %}
|
||||||
|
{% include "unfold/helpers/add_link.html" %}
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div id="content-main" class="flex flex-col gap-4">
|
||||||
|
{% block form_before %}{% endblock %}
|
||||||
|
<div dir='rtl' class="bg-base-50 border border-base-200 border-dashed flex flex-col gap-4 p-4 rounded dark:bg-white/[.02] dark:border-base-700 lg:flex-row lg:justify-between w-full shrink-0 lg:items-center" style="justify-content: space-between;">
|
||||||
|
<div class="flex flex-col lg:flex-row lg:items-center">
|
||||||
|
<h2 class="font-semibold text-font-important-light text-base dark:text-font-important-dark flex items-center">
|
||||||
|
<span class="material-symbols-outlined md-18 mr-3 w-4.5 align-middle">{{original.icon}}</span>
|
||||||
|
<span class="align-middle" style="margin-right: 8px;">اموزش بخش {{original.content_type}}</span>
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex lg:flex-row lg:items-center">
|
||||||
|
{% component "unfold/components/flex.html" with class="flex-col gap-4 lg:flex-row" %}
|
||||||
|
{% component "unfold/components/button.html" with href=original.section_url %}
|
||||||
|
نمایش بخش مربوطه
|
||||||
|
{% endcomponent %}
|
||||||
|
{% endcomponent %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% if adminform.model_admin.change_form_outer_before_template %}
|
||||||
|
{% include adminform.model_admin.change_form_outer_before_template %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="border border-base-200 border-dashed mb-4 p-3 rounded dark:border-base-700 gap-1.5">
|
||||||
|
{% if original and original.video %}
|
||||||
|
<h3 style="display: flex; justify-content: center; align-items: center; width: 100%; padding: 5px 0;">
|
||||||
|
|
||||||
|
<a href="{{original.section_url}}" style="color: rgb(var(--color-primary-500)); margin-right: 5px;">
|
||||||
|
{{original.content_type}}
|
||||||
|
</a>
|
||||||
|
آموزش بخش
|
||||||
|
</h3>
|
||||||
|
<div style="display: flex;justify-content: center;align-items: center;width: 100%;padding: 25px 0px;">
|
||||||
|
<video controls style="border-radius: var(--border-radius,6px);width: 100%;max-width: 800px;">
|
||||||
|
<source src="{{ original.video.url }}" type="video/mp4">
|
||||||
|
</video>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<p>no video available.</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% if request.user.video_uploader %}
|
||||||
|
<form {% if has_file_field %}enctype="multipart/form-data" {% endif %}{% if form_url %}action="{{ form_url }}" {% endif %}method="post" id="{{ opts.model_name }}_form" {% if adminform.model_admin.warn_unsaved_form %}class="warn-unsaved-form"{% endif %} novalidate>
|
||||||
|
{% csrf_token %}
|
||||||
|
|
||||||
|
{% if adminform.model_admin.change_form_before_template %}
|
||||||
|
{% include adminform.model_admin.change_form_before_template %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% block form_top %}{% endblock %}
|
||||||
|
|
||||||
|
<div>
|
||||||
|
{% if is_popup %}
|
||||||
|
<input type="hidden" name="{{ is_popup_var }}" value="1">
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if to_field %}
|
||||||
|
<input type="hidden" name="{{ to_field_var }}" value="{{ to_field }}">
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% include "unfold/helpers/messages/errornote.html" with errors=errors %}
|
||||||
|
{% include "unfold/helpers/messages/error.html" with errors=adminform.form.non_field_errors %}
|
||||||
|
|
||||||
|
{% block field_sets %}
|
||||||
|
{% for fieldset in adminform %}
|
||||||
|
{% if "tab" not in fieldset.classes %}
|
||||||
|
{% include 'admin/includes/fieldset.html' %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% include "unfold/helpers/fieldsets_tabs.html" %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block after_field_sets %}{% endblock %}
|
||||||
|
|
||||||
|
{% block inline_field_sets %}
|
||||||
|
{% for inline_admin_formset in inline_admin_formsets %}
|
||||||
|
{% include inline_admin_formset.opts.template %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block after_related_objects %}{% endblock %}
|
||||||
|
|
||||||
|
{% if adminform.model_admin.change_form_after_template %}
|
||||||
|
{% include adminform.model_admin.change_form_after_template %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% block submit_buttons_bottom %}{% submit_row %}{% endblock %}
|
||||||
|
|
||||||
|
{% block admin_change_form_document_ready %}
|
||||||
|
<script id="django-admin-form-add-constants" src="{% static 'admin/js/change_form.js' %}"{% if adminform and add %} data-model-name="{{ opts.model_name }}"{% endif %} async></script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% prepopulated_fields_js %}
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
{% if adminform.model_admin.change_form_outer_after_template %}
|
||||||
|
{% include adminform.model_admin.change_form_outer_after_template %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% block form_after %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from .models import *
|
from .models import *
|
||||||
from unfold.admin import ModelAdmin, TabularInline
|
from unfold.admin import TabularInline
|
||||||
|
|
||||||
from import_export.admin import ImportExportModelAdmin
|
from import_export.admin import ImportExportModelAdmin
|
||||||
from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm
|
from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm
|
||||||
@@ -10,7 +10,7 @@ from unfold.contrib.filters.admin import (
|
|||||||
ChoicesDropdownFilter,
|
ChoicesDropdownFilter,
|
||||||
MultipleChoicesDropdownFilter,
|
MultipleChoicesDropdownFilter,
|
||||||
)
|
)
|
||||||
|
from utils.admin import ModelAdmin
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.1.2 on 2025-02-14 21:23
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('ticket', '0007_alter_ticket_ticket_category'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='ticket',
|
||||||
|
name='ticket_category',
|
||||||
|
field=models.CharField(choices=[('finance_and_accounting', 'مالی و حسابداری'), ('user_profile', 'پروفایل کاربری'), ('order_tracking', 'پیگیری سفارش'), ('authentication', 'احراز هویت'), ('product', 'محصول'), ('bug_and_error_reporting', 'اعلام باگ و خطا در وبسایت'), ('other', 'سایر')], max_length=30, verbose_name='دسته بندی تیکت'),
|
||||||
|
),
|
||||||
|
]
|
||||||
+30
-2
@@ -1,7 +1,7 @@
|
|||||||
from order.models import OrderModel
|
from order.models import OrderModel
|
||||||
from product.models import DollorModel, CommentModel
|
from product.models import DollorModel, CommentModel
|
||||||
from ticket.models import Ticket
|
from ticket.models import Ticket
|
||||||
|
from home.models import LearnVideoModel
|
||||||
|
|
||||||
def admin_pending_count(request):
|
def admin_pending_count(request):
|
||||||
pending_count = OrderModel.objects.filter(status='ADMIN_PENDING').count()
|
pending_count = OrderModel.objects.filter(status='ADMIN_PENDING').count()
|
||||||
@@ -15,4 +15,32 @@ def comment_count(request):
|
|||||||
return CommentModel.objects.filter(review_status='not_reviwed').count()
|
return CommentModel.objects.filter(review_status='not_reviwed').count()
|
||||||
|
|
||||||
def new_ticket_count(request):
|
def new_ticket_count(request):
|
||||||
return Ticket.objects.filter(status__in=['open', 'in_progress']).count()
|
return Ticket.objects.filter(status__in=['open', 'in_progress']).count()
|
||||||
|
|
||||||
|
def new_learn_video_count(request):
|
||||||
|
return LearnVideoModel.objects.filter(viewd=False).count()
|
||||||
|
|
||||||
|
|
||||||
|
from django.contrib import admin, messages
|
||||||
|
from unfold.admin import ModelAdmin
|
||||||
|
from home.models import LearnVideoModel
|
||||||
|
from import_export.admin import ImportExportModelAdmin
|
||||||
|
from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm
|
||||||
|
from unfold.decorators import action, display
|
||||||
|
from django.shortcuts import redirect
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
|
||||||
|
|
||||||
|
class ModelAdmin(ModelAdmin):
|
||||||
|
actions_list = ['redirect_to_learn']
|
||||||
|
@action(description=f"چگونگی استفاده این بخش")
|
||||||
|
def redirect_to_learn(self, request):
|
||||||
|
content_type = ContentType.objects.get_for_model(self.model)
|
||||||
|
try:
|
||||||
|
learn_video = LearnVideoModel.objects.get(
|
||||||
|
content_type=content_type,
|
||||||
|
)
|
||||||
|
return redirect(f'/admin/home/learnvideomodel/{learn_video.id}/change/')
|
||||||
|
except Exception as e:
|
||||||
|
messages.error(request, f"برای بخش {content_type} ویدیویی اپلود نشده است")
|
||||||
|
return redirect(f'/admin/home/learnvideomodel/')
|
||||||
Reference in New Issue
Block a user