From 81df30c806b464a9a01f72a72b07779098e97995 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Sun, 16 Feb 2025 21:42:29 +0330 Subject: [PATCH] video player and model and video guide routing and stuff --- backend/account/admin.py | 3 +- .../migrations/0011_user_video_uploader.py | 18 ++ .../0012_alter_user_video_uploader.py | 18 ++ backend/account/models.py | 1 + backend/blog/admin.py | 3 +- backend/chat/admin.py | 4 +- backend/core/settings/unfold_conf.py | 8 +- backend/core/static/visibility.png | Bin 0 -> 1545 bytes backend/core/static/visibility_off.png | Bin 0 -> 1584 bytes backend/core/urls.py | 1 + backend/home/admin.py | 37 +++- .../home/migrations/0006_learnvideomodel.py | 25 +++ ...on_alter_learnvideomodel_title_and_more.py | 29 +++ .../0008_learnvideomodel_content_type.py | 20 +++ ...0009_alter_learnvideomodel_content_type.py | 20 +++ .../migrations/0010_learnvideomodel_viewd.py | 18 ++ ...omodel_icon_alter_learnvideomodel_viewd.py | 24 +++ ...0012_alter_learnvideomodel_content_type.py | 20 +++ backend/home/models.py | 38 +++- backend/home/urls.py | 6 + backend/home/views.py | 11 +- backend/order/admin.py | 4 +- .../0005_alter_orderitemmodel_options.py | 17 ++ backend/product/admin.py | 11 +- .../templates/video_change_form_after.html | 166 ++++++++++++++++++ backend/ticket/admin.py | 4 +- .../0008_alter_ticket_ticket_category.py | 18 ++ backend/utils/admin.py | 32 +++- 28 files changed, 531 insertions(+), 25 deletions(-) create mode 100644 backend/account/migrations/0011_user_video_uploader.py create mode 100644 backend/account/migrations/0012_alter_user_video_uploader.py create mode 100644 backend/core/static/visibility.png create mode 100644 backend/core/static/visibility_off.png create mode 100644 backend/home/migrations/0006_learnvideomodel.py create mode 100644 backend/home/migrations/0007_learnvideomodel_section_alter_learnvideomodel_title_and_more.py create mode 100644 backend/home/migrations/0008_learnvideomodel_content_type.py create mode 100644 backend/home/migrations/0009_alter_learnvideomodel_content_type.py create mode 100644 backend/home/migrations/0010_learnvideomodel_viewd.py create mode 100644 backend/home/migrations/0011_learnvideomodel_icon_alter_learnvideomodel_viewd.py create mode 100644 backend/home/migrations/0012_alter_learnvideomodel_content_type.py create mode 100644 backend/home/urls.py create mode 100644 backend/order/migrations/0005_alter_orderitemmodel_options.py create mode 100644 backend/templates/video_change_form_after.html create mode 100644 backend/ticket/migrations/0008_alter_ticket_ticket_category.py diff --git a/backend/account/admin.py b/backend/account/admin.py index e293140..53c231d 100644 --- a/backend/account/admin.py +++ b/backend/account/admin.py @@ -9,7 +9,7 @@ from django.contrib.postgres.fields import ArrayField from django.contrib.auth.models import Group from unfold.forms import AdminPasswordChangeForm from unfold.forms import AdminPasswordChangeForm, UserChangeForm, UserCreationForm - +from utils.admin import ModelAdmin class UserAddressInLine(TabularInline): model = UserAddressModel extra = 0 @@ -36,6 +36,7 @@ class UserAdmin(BaseUserAdmin, ModelAdmin, ImportExportModelAdmin): fieldsets = ( ('اطلاعات شخصی', {'fields': ('first_name', 'last_name', 'profile_photo', 'password', 'gender', 'birth_date'),}), ('اطلاعات ارتباطی', {'fields': ('phone', 'email'),}), + ('دسترسی های وبسایت', {'fields': ('is_superuser', 'video_uploader'),}), ) empty_value_display = 'ثبت نشده' add_fieldsets = ( diff --git a/backend/account/migrations/0011_user_video_uploader.py b/backend/account/migrations/0011_user_video_uploader.py new file mode 100644 index 0000000..d8249f3 --- /dev/null +++ b/backend/account/migrations/0011_user_video_uploader.py @@ -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), + ), + ] diff --git a/backend/account/migrations/0012_alter_user_video_uploader.py b/backend/account/migrations/0012_alter_user_video_uploader.py new file mode 100644 index 0000000..425e808 --- /dev/null +++ b/backend/account/migrations/0012_alter_user_video_uploader.py @@ -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='اپلودر اموزش'), + ), + ] diff --git a/backend/account/models.py b/backend/account/models.py index fc097df..0e5323b 100644 --- a/backend/account/models.py +++ b/backend/account/models.py @@ -50,6 +50,7 @@ class User(AbstractBaseUser, PermissionsMixin): date_joined = models.DateTimeField(auto_now_add=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='تاریخ تمام شدن کد یک بار مصرف') + video_uploader = models.BooleanField(default=False, help_text='اپلود کننده ی ویدیویی اموزشی پنل ادمین', verbose_name='اپلودر اموزش') objects = UserManager() USERNAME_FIELD = 'phone' diff --git a/backend/blog/admin.py b/backend/blog/admin.py index fd74838..ea7b973 100644 --- a/backend/blog/admin.py +++ b/backend/blog/admin.py @@ -1,12 +1,11 @@ from django.contrib import admin from .models import * -from unfold.admin import ModelAdmin from import_export.admin import ImportExportModelAdmin from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm from unfold.contrib.forms.widgets import ArrayWidget, WysiwygWidget from django.contrib.postgres.fields import ArrayField - +from utils.admin import ModelAdmin @admin.register(BlogModel) class BlogModelAdmin(ModelAdmin, ImportExportModelAdmin): diff --git a/backend/chat/admin.py b/backend/chat/admin.py index 8d83c8f..5532e04 100644 --- a/backend/chat/admin.py +++ b/backend/chat/admin.py @@ -1,12 +1,12 @@ from django.contrib import admin from .models import * -from unfold.admin import ModelAdmin + from import_export.admin import ImportExportModelAdmin from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm from unfold.contrib.forms.widgets import ArrayWidget, WysiwygWidget from django.contrib.postgres.fields import ArrayField - +from utils.admin import ModelAdmin @admin.register(ProductChatModel) class ProductChatAdmin(ModelAdmin, ImportExportModelAdmin): diff --git a/backend/core/settings/unfold_conf.py b/backend/core/settings/unfold_conf.py index 3829318..934d808 100644 --- a/backend/core/settings/unfold_conf.py +++ b/backend/core/settings/unfold_conf.py @@ -30,7 +30,7 @@ UNFOLD = { }, - "BORDER_RADIUS": "8px", + "BORDER_RADIUS": "20px", "SHOW_HISTORY": True, "SHOW_VIEW_ON_SITE": True, "ENVIRONMENT": "core.settings.environment_callback", @@ -93,6 +93,12 @@ UNFOLD = { "icon": "dashboard", "link": reverse_lazy("admin:index"), }, + { + "title": _("آموزش استفاده از پنل"), + "icon": "school", + "link": reverse_lazy("admin:home_learnvideomodel_changelist"), + "badge": "utils.admin.new_learn_video_count", + }, { "title": _("سفارشات"), "icon": "shopping_cart", diff --git a/backend/core/static/visibility.png b/backend/core/static/visibility.png new file mode 100644 index 0000000000000000000000000000000000000000..3a7a90782270b20fecd1122ee93fca941c8d6357 GIT binary patch literal 1545 zcmbu<`#aMM00!{y*2c_nzu#&_$V%l%#B$q~9hX>c<)|g68s*Yd)1kg0*N`prpL-@J{F#=cdhNIKi zR`Q#bJ6my9_vS6_+Lb$NHR+&*Z5mf|nDMDPq1gf@ z0@A0amX;|6rjf5(+LTjf0%C=qC9=+61{c5W1WK{v>Wp?o+TCEtuZ0U}r%CG<7ks}$ zg>p$hvODQBWOFb`slfa>m7>5e@uIFDRg&5b^ z(7CGFvDbAi>kO5ZvEPvafY<3W$ek}zEe*^CXMD{ozWDv19!oR;%2ww}S2S&UuV&#{ z0wGi=npq8M&MCOFq8!fW7SbAREjXxrKzETFNPREOX!ly9&344enaFz8)db6-b&6qt z-}i~N`#T;jye~saD;brQSEkJ@Mzs-PfXeYMHa3>rtzRl$?C{BFYaNIpLq9q~|bV1*^>I;ajyd$(gle5;TT{@6^sm8LV((=%_>cyU=kQ}@V z2yruw?wrs_DN!{MrvPq8wx>lCU7;&AuH+yu!JhuUZKEHv>1F~wXMo2)K=tuHnAe8I zh4s@&apvy>fhyAFhBH&a1S9#euvY3VI)Cb+l3066p^Kl*e)IvqfJvtaVJ0d@_Pi!SyJSBguGl z)L{LPA;|+E(1hfgdqWo7RJi)*-n|Q&$zCFg3!0>j zVXxr;^W3v*M@g`zTi-y9ZX__`%f$VC3KnB8$7C48^A$&eJe&o5?y01e)Px+IPrcY? z0H|A~*o@?VT`(Uu08UW&-}EdC2;+5CbC)}YSp|Vac-{ky;=!qsw^yBRy&Pp6`MCl#oQYYu_m7R?r-yYgDtZ7GuEFoc7fV^wFpQT z^*M7`r=c*!OXkLo_Jw#;lbbAUUBFh}Kmvbwuz^is;4v2~j9d?sC9Jt?4 zQ9^@#Xnv&cB)My?+R7@@XR7autZ!g3)W)Cjk*wRCm{1My{L&j*W3AjNDerk|xBHFv z;^V(zCL+Q-VLHH{@$IwNq@mQk)$H#~XKFM?+%upA%EJVX-T@*ly$pj~o>#29HTiI- zT{;?Y51#gTI2Lm#1%v70FhB>6Lxei#ab8muWuovUDk91g-Ib{)Yi=BB6h~!)kFNRo z6_<6K9yXegwLpsnJk3^g-yimwqV@+eks8mEUAbH8xongsF^xk2R$;M(w9*^Zu;lS*RwF!UUY8pL!JjSoAJU(7JS(7ofxjrt=n2JvvN{;AwetloNv38XB poGD03P(VRoXw^$cjsKsU`&G(z(V{S)o^E|RK)`unnJ%P+e*n0W$#4Jw literal 0 HcmV?d00001 diff --git a/backend/core/static/visibility_off.png b/backend/core/static/visibility_off.png new file mode 100644 index 0000000000000000000000000000000000000000..229a8437e42445593e180ba5dad473ad8d4acfde GIT binary patch literal 1584 zcmV-02G9A4P)Px)>PbXFRCr$PoLiF9Fc3wZl`*UYs+f=21+a_xfGSuC!^*<6%Sve!TYYc09vRa4 zOk_*Cr(aTRotF4aRp2zW_vm~H0F#X%00e-^3QX=kJRkr}R$y}X;Q;|)vI3L44-W_c zlNFfUJ?sIWADyyqBOq*vU%HY4VEw%2q7T{hFWj-`3_OLAfO$)g&xpph8$7r1EyN?A)RW zZB0!Dh*We_y#uL&xQx05XqHU!G(Q09hyF35 zVIW`tcL-q!2nxWRLg>2vLIaopA(fA-MW*OpRxjC_A*~lu2@T~gAZv69OC|uFA*{Qu zB6h11F~QkNY8Mcu$N-@Fo(t+#9U%kvwAo5v@emV?mJrMykOX+I5M=yL5HG)fK7aHW zf?PWkz}lhX|AcItBJBqy3%=wAxxe(ogf9mOcV2J-V5~p46b3@JRRQfwW&P0NSV8>$ z`E1tFe4$nRBoGM!-VWIb2^J7+f97yx0^k*Y0t7nr8N9&+fd(nMVeqoGF= zf7Z4IGJbUIWi}@uR6|kK13;^VTx}u*%@e5c=O9|><9aY_i`h`J$p?;FPm7#@gdr-ZQ=rP34HwNtyO7Q}hF=-xF3#C^8kjlZbr&5N7PhXzSTI}5W-3mby$(je4^}*iQ zuK^Po0IZ2wGb}FvWKIwO%~GVJ5rfsdgY|^o0JQsW^SKIjdm%`xo9VsvJuwka zYYCxe4j>ZoRo*!V5z2*-CxMv8x#9t!@Yf?Q2!{i%w+=Id+y`rW87(^QJbTZ6?DNz|?Lz8Yf zP!j+H1bVGtcshA11g+jb8k`xx20`5~Dmu1!gDeKk?{ghaoOn}5sRHS+W2%DoCgQMC z69^eYad^m^<7(tIlwQw=9zbx3Z%V>@ARHwm4FZWX%y`J0(ERK?R|v|*AQM)pV{;Ha zA+$U_vKat&olvpl6^8tdJlSR?A_}vefaZX#jJ+HLbqni+n*vaZnIBzT z99b+)OY6;#tdV1j)2Dj!)@%qj4FI)nZ@ZZg0>DOZ7K8whxz7v;0icLqqag%#YS`Wo0sydx=m{YJ005*33W0q-C;)%}q?z_FA1l7xGXM|( zY7i{q2LMw1?Ej26?@?RD4**60xhHtU4*(7TtuBom&`L?;eFA_{xK@`1fL2Nx?-Kxw i!nL|A0JKulc%Ofo$IPA8{hg2i0000' + else: + svg = f'' + + return format_html( + svg + ) + + + @admin.register(SliderModel) class SliderAdmin(ModelAdmin, ImportExportModelAdmin): diff --git a/backend/home/migrations/0006_learnvideomodel.py b/backend/home/migrations/0006_learnvideomodel.py new file mode 100644 index 0000000..9353a52 --- /dev/null +++ b/backend/home/migrations/0006_learnvideomodel.py @@ -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': 'ویدیوی های اموزشی', + }, + ), + ] diff --git a/backend/home/migrations/0007_learnvideomodel_section_alter_learnvideomodel_title_and_more.py b/backend/home/migrations/0007_learnvideomodel_section_alter_learnvideomodel_title_and_more.py new file mode 100644 index 0000000..b7b3d98 --- /dev/null +++ b/backend/home/migrations/0007_learnvideomodel_section_alter_learnvideomodel_title_and_more.py @@ -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='ویدیو'), + ), + ] diff --git a/backend/home/migrations/0008_learnvideomodel_content_type.py b/backend/home/migrations/0008_learnvideomodel_content_type.py new file mode 100644 index 0000000..ab5b2f3 --- /dev/null +++ b/backend/home/migrations/0008_learnvideomodel_content_type.py @@ -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'), + ), + ] diff --git a/backend/home/migrations/0009_alter_learnvideomodel_content_type.py b/backend/home/migrations/0009_alter_learnvideomodel_content_type.py new file mode 100644 index 0000000..7f1327e --- /dev/null +++ b/backend/home/migrations/0009_alter_learnvideomodel_content_type.py @@ -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='مدل مرتبط'), + ), + ] diff --git a/backend/home/migrations/0010_learnvideomodel_viewd.py b/backend/home/migrations/0010_learnvideomodel_viewd.py new file mode 100644 index 0000000..5b4b232 --- /dev/null +++ b/backend/home/migrations/0010_learnvideomodel_viewd.py @@ -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), + ), + ] diff --git a/backend/home/migrations/0011_learnvideomodel_icon_alter_learnvideomodel_viewd.py b/backend/home/migrations/0011_learnvideomodel_icon_alter_learnvideomodel_viewd.py new file mode 100644 index 0000000..adf3697 --- /dev/null +++ b/backend/home/migrations/0011_learnvideomodel_icon_alter_learnvideomodel_viewd.py @@ -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='تماشا شده'), + ), + ] diff --git a/backend/home/migrations/0012_alter_learnvideomodel_content_type.py b/backend/home/migrations/0012_alter_learnvideomodel_content_type.py new file mode 100644 index 0000000..47c18fc --- /dev/null +++ b/backend/home/migrations/0012_alter_learnvideomodel_content_type.py @@ -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='مدل مرتبط'), + ), + ] diff --git a/backend/home/models.py b/backend/home/models.py index d0d9a1e..857e0e0 100644 --- a/backend/home/models.py +++ b/backend/home/models.py @@ -1,6 +1,6 @@ from django.db import models from product.models import ProductModel - +from django.urls import reverse class SliderModel(models.Model): link = models.URLField(verbose_name='لینک') @@ -45,4 +45,38 @@ class ShowCaseSlider(models.Model): class Meta: verbose_name = 'مدل نمایش کیس' - verbose_name_plural = 'مدل نمایش کیس ها' \ No newline at end of file + 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 = 'ویدیوی های اموزشی' \ No newline at end of file diff --git a/backend/home/urls.py b/backend/home/urls.py new file mode 100644 index 0000000..a406202 --- /dev/null +++ b/backend/home/urls.py @@ -0,0 +1,6 @@ +from django.urls import path +from . import views + +urlpatterns = [ + path('video/view/', views.ChangeViewVideo.as_view(), name='product-chat-view'), +] \ No newline at end of file diff --git a/backend/home/views.py b/backend/home/views.py index 181d7ab..003a09a 100644 --- a/backend/home/views.py +++ b/backend/home/views.py @@ -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 product.models import ProductModel, SubCategoryModel, DollorModel from product.serializers import SubCategorySerializer, DynamicProductSerializer from .serializers import * from .models import * 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): diff --git a/backend/order/admin.py b/backend/order/admin.py index 813088f..bce84b0 100644 --- a/backend/order/admin.py +++ b/backend/order/admin.py @@ -1,12 +1,12 @@ from django.contrib import admin from .models import * -from unfold.admin import ModelAdmin, TabularInline, StackedInline +from unfold.admin import TabularInline, StackedInline from import_export.admin import ImportExportModelAdmin from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm from unfold.contrib.forms.widgets import ArrayWidget, WysiwygWidget from django.contrib.postgres.fields import ArrayField - +from utils.admin import ModelAdmin class OrderItemModelInline(StackedInline): model = OrderItemModel diff --git a/backend/order/migrations/0005_alter_orderitemmodel_options.py b/backend/order/migrations/0005_alter_orderitemmodel_options.py new file mode 100644 index 0000000..308bddd --- /dev/null +++ b/backend/order/migrations/0005_alter_orderitemmodel_options.py @@ -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': 'ایتم های سبد خرید'}, + ), + ] diff --git a/backend/product/admin.py b/backend/product/admin.py index 5ea98c7..3cfe104 100644 --- a/backend/product/admin.py +++ b/backend/product/admin.py @@ -1,15 +1,14 @@ -from django.contrib import admin +from django.contrib import admin, messages 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 unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm from unfold.contrib.forms.widgets import ArrayWidget, WysiwygWidget from django.contrib.postgres.fields import ArrayField -from unfold.widgets import ( - UnfoldAdminColorInputWidget, -) +from unfold.widgets import UnfoldAdminColorInputWidget from unfold.decorators import action, display +from utils.admin import ModelAdmin @admin.register(ProductVariant) class ProductVariantAdmin(ModelAdmin, ImportExportModelAdmin): diff --git a/backend/templates/video_change_form_after.html b/backend/templates/video_change_form_after.html new file mode 100644 index 0000000..54b4059 --- /dev/null +++ b/backend/templates/video_change_form_after.html @@ -0,0 +1,166 @@ +{% extends "admin/base_site.html" %} +{% load unfold %} +{% load i18n admin_urls static admin_modify %} + +{% block extrahead %}{{ block.super }} + + {{ media }} +{% endblock %} + +{% block bodyclass %}{{ block.super }} app-{{ opts.app_label }} model-{{ opts.model_name }} change-form{% endblock %} + +{% if not is_popup %} + {% block breadcrumbs %} +
+
+
    + {% 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 %} +
+
+
+ {% 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 %} +
+ {% block form_before %}{% endblock %} +
+
+

+ {{original.icon}} + اموزش بخش {{original.content_type}} +

+
+ +
+ {% 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 %} +
+
+ {% if adminform.model_admin.change_form_outer_before_template %} + {% include adminform.model_admin.change_form_outer_before_template %} + {% endif %} + +
+ {% if original and original.video %} +

+ + + {{original.content_type}} + + آموزش بخش +

+
+ +
+ {% else %} +

no video available.

+ {% endif %} +
+ + + + {% if request.user.video_uploader %} +
+ {% csrf_token %} + + {% if adminform.model_admin.change_form_before_template %} + {% include adminform.model_admin.change_form_before_template %} + {% endif %} + + {% block form_top %}{% endblock %} + +
+ {% if is_popup %} + + {% endif %} + + {% if 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 %} + + {% endblock %} + + {% prepopulated_fields_js %} +
+
+ {% endif %} + {% if adminform.model_admin.change_form_outer_after_template %} + {% include adminform.model_admin.change_form_outer_after_template %} + {% endif %} + + {% block form_after %}{% endblock %} +
+{% endblock %} \ No newline at end of file diff --git a/backend/ticket/admin.py b/backend/ticket/admin.py index 121c965..5ae80c6 100644 --- a/backend/ticket/admin.py +++ b/backend/ticket/admin.py @@ -1,6 +1,6 @@ from django.contrib import admin from .models import * -from unfold.admin import ModelAdmin, TabularInline +from unfold.admin import TabularInline from import_export.admin import ImportExportModelAdmin from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm @@ -10,7 +10,7 @@ from unfold.contrib.filters.admin import ( ChoicesDropdownFilter, MultipleChoicesDropdownFilter, ) - +from utils.admin import ModelAdmin diff --git a/backend/ticket/migrations/0008_alter_ticket_ticket_category.py b/backend/ticket/migrations/0008_alter_ticket_ticket_category.py new file mode 100644 index 0000000..e700fbb --- /dev/null +++ b/backend/ticket/migrations/0008_alter_ticket_ticket_category.py @@ -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='دسته بندی تیکت'), + ), + ] diff --git a/backend/utils/admin.py b/backend/utils/admin.py index 61cabce..67786f3 100644 --- a/backend/utils/admin.py +++ b/backend/utils/admin.py @@ -1,7 +1,7 @@ from order.models import OrderModel from product.models import DollorModel, CommentModel from ticket.models import Ticket - +from home.models import LearnVideoModel def admin_pending_count(request): 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() def new_ticket_count(request): - return Ticket.objects.filter(status__in=['open', 'in_progress']).count() \ No newline at end of file + 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/') \ No newline at end of file