diff --git a/AuthApp/__init__.py b/AuthApp/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/AuthApp/admin.py b/AuthApp/admin.py new file mode 100644 index 0000000..b4c6131 --- /dev/null +++ b/AuthApp/admin.py @@ -0,0 +1,150 @@ +# coding=utf-8 +from django.contrib import admin +from django.contrib.auth.admin import UserAdmin +from BaseModels.admin_utils import * +from django.contrib.auth.models import User +from django.utils.translation import gettext_lazy as _ + +from AuthApp.models import * + +from django.contrib.auth.models import Group +from django.db import models +from django.contrib.admin.models import LogEntry + +from django.db.models import F, Value as V +from django.db.models.functions import Concat + +from django.contrib.auth.admin import GroupAdmin as BaseGroupAdmin +from django.contrib.auth.models import Group +from django.contrib.admin import SimpleListFilter + + +class LogEntryAdmin(admin.ModelAdmin): + # pass + list_display = ( + '__str__', 'action_time', 'user', 'content_type', 'object_id', 'object_repr', 'action_flag', 'change_message') + list_filter = ('content_type', 'action_flag') + search_fields = ['user__username', 'change_message', 'object_id', 'object_repr'] + date_hierarchy = 'action_time' + + def has_delete_permission(self, request, obj=None): + return False + + +admin.site.register(LogEntry, LogEntryAdmin) + + +class Admin_ProfileInline(admin.StackedInline): + fieldsets = ( + (None, { + 'classes': ['wide'], + 'fields': ( + ('enable',), + ('phone',), + ('country', 'city'), + ('authMailCode',), + ('birthdate'), + 'comment', 'creator' + ) + }), + ('Дополнительно', { + 'classes': ['wide'], + 'fields': ( + ('json_data',) + ) + }), + ) + + model = UserProfile + can_delete = False + extra = 1 + fk_name = 'user' + + # filter_horizontal = ['regions', 'connected_mailings'] + # raw_id_fields = ("company_obj", 'office') + verbose_name_plural = _(u'Профиль пользователя') + + # list_display = ['company_obj', 'office', 'company_position', 'departament', 'creator'] + readonly_fields = ['creator', ] + + +class Admin_User(UserAdmin): + + fieldsets = ( + (None, { + 'classes': ['wide'], + 'fields': ( + ('username', 'password'), + ('first_name', 'last_name', 'email'), + ('is_active', 'is_staff', 'is_superuser'), + ('groups', 'user_permissions'), + ('last_login', 'date_joined'), + # ('username', 'first_name', 'last_name'), + # ('password'), + # ('email', 'is_active'), + # ('is_staff') + ) + }), + + ) + + save_on_top = True + + list_display = ['id', 'last_name', 'first_name', 'email', 'is_staff', + 'is_active'] + list_editable = ['is_staff', 'is_active'] + list_display_links = ['first_name', 'last_name', 'email'] + search_fields = ['first_name', 'last_name', 'email'] + + inlines = (Admin_ProfileInline,) + # actions = ['del_all_temp_users', ] + + ordering = ['is_staff', 'last_name', 'first_name'] + +# Re-register UserAdmin +admin.site.unregister(User) +admin.site.register(User, Admin_User) + + +class Admin_UserProfile(Admin_BaseIconModel): + + fieldsets = ( + (None, { + 'classes': ['wide'], + 'fields': ( + 'user', 'enable', + ('account_type',), + ('phone',), + ('country', 'city'), + ('authMailCode',), + ('birthdate'), + 'creator' + ) + }), + ('1С', { + 'classes': ['wide'], + 'fields': ( + ('id_1s', 'name',), + ) + }), + ) + + save_on_top = True + + list_display = [ + 'id', 'user', 'enable', 'birthdate', 'modifiedDT', 'createDT' + ] + list_editable = ['enable', 'birthdate'] + list_display_links = ['id', ] # 'user__last_name', 'user__first_name'] + search_fields = [ + 'id', 'user__last_name', 'user__first_name', 'user__email', + ] + + list_filter = ['enable', 'account_type'] + + # filter_horizontal = ['connected_mailings'] + # raw_id_fields = ("favourites",) + verbose_name_plural = _(u'Профиль пользователя') + + +admin.site.register(UserProfile, Admin_UserProfile) diff --git a/AuthApp/forms.py b/AuthApp/forms.py new file mode 100644 index 0000000..2978242 --- /dev/null +++ b/AuthApp/forms.py @@ -0,0 +1,70 @@ +# # coding=utf-8 +# from django import forms +# from django.contrib.auth.forms import AuthenticationForm +# from django.utils.translation import ugettext_lazy as _ +# from django.core.exceptions import ValidationError +# from .models import * +# # from djng.styling.bootstrap3.forms import Bootstrap3ModelForm +# # from djng.forms import fields, NgModelFormMixin, NgFormValidationMixin, NgModelForm +# # from datetimepicker.widgets import DateTimePicker +# # from datetimepicker.helpers import js_loader_url +# +# +# +# # class PersonForm(NgModelFormMixin, NgFormValidationMixin, NgModelForm, Bootstrap3ModelForm): +# # +# # form_name = 'person_form' +# # scope_prefix = 'person_data' +# # +# # class Meta: +# # model = UserProfile +# # fields = ['name', 'departament', 'company', 'company_position', +# # 'days_to_order_cancellation_default', 'days_to_pay_default', +# # 'pay_terms', 'birthdate', +# # 'phone', 'email', 'discount', 'document_sign_person'] +# +# +# +# def emailValid(value): +# if User.objects.filter(username=value, is_active=True): +# raise ValidationError(_(u'пользователь с таким e-mail уже существует, воспользуйтесь восстановлением пароля')) +# +# def check_authorizationBy_cleaned_data(cleaned_data): +# from django.contrib.auth import authenticate +# print('check_authorizationBy_cleaned_data') +# username = cleaned_data.get('username') +# password = cleaned_data.get('password') +# +# user = authenticate(username=username, password=password) +# # print(user) +# if user: +# # if user.is_active: +# return user +# +# def check_activate_by_user(reg_user): +# print('check_activate_by_user') +# if reg_user: +# if reg_user.is_active: +# return True +# +# return False +# +# class LoginForm(AuthenticationForm): +# username = forms.EmailField(label=_('Email'), widget=forms.TextInput()) +# password = forms.CharField(min_length=8, label=_('Пароль'), widget=forms.PasswordInput(render_value=False)) +# +# def clean(self): +# # print('check') +# cleaned_data = super(LoginForm, self).clean() +# reg_user = check_authorizationBy_cleaned_data(cleaned_data) +# # print(reg_user) +# if not reg_user: +# raise ValidationError(_(u'Пользователь с введенными регистрационными данными не зарегистрирован. Проверьте правильность ввода e-mail и пароля.')) +# else: +# if not check_activate_by_user(reg_user): +# raise ValidationError(_(u'Указанная учетная запись не была Активирована')) +# return cleaned_data +# +# +# class ResetPassword_byEmail_Form(AuthenticationForm): +# email = forms.EmailField(label=_('Email'), widget=forms.TextInput()) \ No newline at end of file diff --git a/AuthApp/migrations/0001_initial.py b/AuthApp/migrations/0001_initial.py new file mode 100644 index 0000000..2997cd5 --- /dev/null +++ b/AuthApp/migrations/0001_initial.py @@ -0,0 +1,44 @@ +# Generated by Django 4.2.2 on 2023-06-20 14:50 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='UserProfile', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.TextField(blank=True, help_text='Название', null=True, verbose_name='Название')), + ('name_plural', models.TextField(blank=True, null=True, verbose_name='Название (множественное число)')), + ('order', models.IntegerField(blank=True, null=True, verbose_name='Очередность отображения')), + ('createDT', models.DateTimeField(auto_now_add=True, verbose_name='Дата и время создания')), + ('modifiedDT', models.DateTimeField(blank=True, null=True, verbose_name='Дата и время последнего изменения')), + ('enable', models.BooleanField(db_index=True, default=True, verbose_name='Включено')), + ('json_data', models.JSONField(blank=True, default=dict, verbose_name='Дополнительные данные')), + ('account_type', models.CharField(choices=[('Перевозчик', 'mover'), ('Отправитель', 'sender')], default='base_account', max_length=250, verbose_name='Тип учетной записи')), + ('authMailCode', models.CharField(blank=True, max_length=32, null=True)), + ('phone', models.CharField(blank=True, max_length=100, null=True, verbose_name='Телефон')), + ('country', models.CharField(blank=True, max_length=250, null=True, verbose_name='Страна')), + ('city', models.TextField(blank=True, null=True, verbose_name='Город')), + ('birthdate', models.DateField(blank=True, null=True, verbose_name='Дата рождения')), + ('comment', models.TextField(blank=True, null=True, verbose_name='Дополнительные сведения')), + ('creator', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='rel_users_for_creator', to=settings.AUTH_USER_MODEL, verbose_name='Создатель')), + ('user', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='user_profile', to=settings.AUTH_USER_MODEL, verbose_name='Пользователь')), + ], + options={ + 'verbose_name': 'Профиль', + 'verbose_name_plural': 'Профили', + 'ordering': ('user__last_name', 'user__first_name'), + }, + ), + ] diff --git a/AuthApp/migrations/0002_alter_userprofile_city.py b/AuthApp/migrations/0002_alter_userprofile_city.py new file mode 100644 index 0000000..59ece6e --- /dev/null +++ b/AuthApp/migrations/0002_alter_userprofile_city.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.2 on 2023-06-20 14:52 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('AuthApp', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='userprofile', + name='city', + field=models.CharField(blank=True, max_length=250, null=True, verbose_name='Город'), + ), + ] diff --git a/AuthApp/migrations/__init__.py b/AuthApp/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/AuthApp/models.py b/AuthApp/models.py new file mode 100644 index 0000000..b2e2278 --- /dev/null +++ b/AuthApp/models.py @@ -0,0 +1,82 @@ +# coding=utf-8 +from __future__ import unicode_literals +from django.contrib.auth.models import User +from django.db import models +from django.utils.translation import gettext_lazy as _ +from django.db.models.signals import post_save, pre_save +from django.contrib.contenttypes.fields import GenericRelation +from django.contrib.postgres.fields import JSONField +from BaseModels.base_models import BaseModel +from datetime import datetime + + +def user_name_str(self): + return f'{self.last_name} {self.first_name}' + + +User.add_to_class("__str__", user_name_str) + + +account_type_choices = ( + (_('Перевозчик'), 'mover'), + (_('Отправитель'), 'sender') +) + + +class UserProfile(BaseModel): + + account_type = models.CharField( + max_length=250, verbose_name=_('Тип учетной записи'), choices=account_type_choices, default='base_account') + + user = models.OneToOneField(User, verbose_name=_('Пользователь'), related_name=u'user_profile', + null=True, blank=True, on_delete=models.CASCADE) + + authMailCode = models.CharField(max_length=32, null=True, blank=True) + + phone = models.CharField(max_length=100, verbose_name=_('Телефон'), null=True, blank=True) + country = models.CharField(max_length=250, verbose_name=_('Страна'), null=True, blank=True) + city = models.CharField(max_length=250, verbose_name=_('Город'), null=True, blank=True) + + birthdate = models.DateField(verbose_name=_('Дата рождения'), null=True, blank=True) + + comment = models.TextField(verbose_name=_('Дополнительные сведения'), null=True, blank=True) + + creator = models.ForeignKey( + User, verbose_name=_('Создатель'), related_name='rel_users_for_creator', null=True, blank=True, + on_delete=models.SET_NULL + ) + + + def __str__(self): + if self.user: + return '{0} {1}'.format(self.user.last_name, self.user.first_name) + else: + return str(self.id) + + + class Meta: + verbose_name = _(u'Профиль') + verbose_name_plural = _(u'Профили') + ordering = ('user__last_name', 'user__first_name') + + + +def create_user_profile(sender, instance, created, **kwargs): + if created: + UserProfile.objects.create(user=instance) + + +post_save.connect(create_user_profile, sender=User, dispatch_uid='post_save_connect') + + +def preSaveUser(sender, instance, **kwargs): + if not instance.email: + instance.email = str(instance.username).lower() + + try: + instance.user_profile.modifiedDT = datetime.now() + except: + pass + + +pre_save.connect(preSaveUser, sender=User, dispatch_uid='pre_save_connect') diff --git a/AuthApp/tests.py b/AuthApp/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/AuthApp/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/AuthApp/translation.py b/AuthApp/translation.py new file mode 100644 index 0000000..7289e98 --- /dev/null +++ b/AuthApp/translation.py @@ -0,0 +1,18 @@ +from modeltranslation.translator import translator, TranslationOptions +from .models import * + + +# class UserProfile_TranslationOptions(TranslationOptions): +# fields = ( +# 'name', 'phone', 'city', +# ) +# translator.register(UserProfile, UserProfile_TranslationOptions) +# +# class User_TranslationOptions(TranslationOptions): +# fields = ( +# 'first_name', 'description', 'text', 'title', 'FAQ_title' +# ) +# translator.register(User, User_TranslationOptions) + + + diff --git a/AuthApp/urls.py b/AuthApp/urls.py new file mode 100644 index 0000000..21a087b --- /dev/null +++ b/AuthApp/urls.py @@ -0,0 +1,57 @@ +# coding=utf-8 +# from django.conf.urls import url +# from AuthApp.js_views import * +# from AuthApp.import_funcs import * +from AuthApp.views import * +from django.contrib.auth import views + +urlpatterns = [ + + # ajax ---------------- + # url(r'^login$', user_login_View_ajax, name='user_login_View_ajax'), + # url(r'^login_confirm$', user_login_confirm_ajax, name='user_login_confirm_ajax'), + # + # url(r'^logout$', user_logout_ajax, name='user_logout_View_ajax'), + # url(r'^logout_confirm$', user_logout_confirm_ajax, name='user_logout_confirm_ajax'), + # + # url(r'^check_exists_email$', check_exists_email_ajax, name='check_exists_email_ajax'), + # + # url(r'^registration$', user_registration_View_ajax, name='user_registration_View_ajax'), + # url(r'^user_registration_send_confirmation_mail$', + # user_registration_send_confirmation_mail_ajax, name='user_registration_send_confirmation_mail_ajax'), + # + # url(r'^password_recovery$', password_recovery_View_ajax, name='password_recovery_View_ajax'), + # url(r'^password_reset$', password_reset_send_mail_ajax, name='password_reset_send_mail_ajax'), + # + # url(r'^registration_by_order_data_and_send_confirmation_mail$', + # registration_by_order_data_and_send_confirmation_mail_ajax, name='registration_by_order_data_and_send_confirmation_mail_ajax'), + # + # + # # ----------------------- + # + # url(r'^check_user_registration_and_activate/(?P[\d+]*)/(?P[0-9a-z\+\-\_]+)$', + # check_user_registration_and_activate, + # name='check_user_registration_and_activate'), + # + # # url(r'^user/password/reset/$', + # # 'django.contrib.auth.views.password_reset', + # # {'post_reset_redirect' : '/user/password/reset/done/', + # # 'password_reset_form': ResetForm + # # }, + # # name="password_reset"), + # # url(r'^user/password/reset/done/$', views.password_reset_done, name='password_reset_done'), + # url(r'^reset/(?P[0-9A-Za-z_\-]+)/(?P[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', + # views.password_reset_confirm, name='password_reset_confirm'), + # url(r'^reset/done/$', views.password_reset_complete, name='password_reset_complete'), + # + # + # # import + # url(r'^import_one_user/(?P[\d+]*)$', + # import_json_mipp_user_by_id, name='import_one_mipp'), + # url(r'^import_web_users$', + # import_json_mipp_webUsers, name='import_mipp_webUsers'), + # + # url(r'^import_invoices_for_user_by_user_id/(?P[\d+]*)$', + # import_invoices_for_user_by_user_id, name='import_invoices_for_user_by_user_id'), + +] \ No newline at end of file diff --git a/AuthApp/views.py b/AuthApp/views.py new file mode 100644 index 0000000..cca8d27 --- /dev/null +++ b/AuthApp/views.py @@ -0,0 +1,149 @@ +# coding=utf-8 + +from django.shortcuts import render + +from uuid import uuid1 +from AuthApp.models import * +from django.contrib import auth +from django.http import HttpResponse, Http404 +from django.template import loader, RequestContext +from django.contrib.auth.decorators import login_required +from BaseModels.mailSender import techSendMail +from django.utils.translation import gettext as _ +from datetime import datetime + + +def create_personal_user(data, creator): + + try: + + user_id = str(uuid1().hex)[:10] + user_name = data['email'] + mail = user_name + user = User.objects.create_user(username=user_name, email=mail, password=user_id) + + if 'first_name' in data and data['first_name']: + user.first_name = data['first_name'] + if 'last_name' in data and data['last_name']: + user.last_name = data['last_name'] + user.is_staff = False + user.is_active = False + user.is_superuser = False + # user.set_password(user_id) + user.save() + + user_communications_ads_list = [] + + if 'office__name' in data['user_profile']: + del data['user_profile']['office__name'] + if 'communications' in data['user_profile']: + + user_communications_ads_list.extend(data['user_profile']['communications']) + del data['user_profile']['communications'] + + if not 'creator' in data['user_profile'] and creator: + data['user_profile']['creator'] = creator + + profiles = UserProfile.objects.filter(user=user).update(**data['user_profile']) + + user.refresh_from_db() + + return { + 'name' : mail, + 'pass' : user_id, + 'user' : user + } + except Exception as e: + return { + 'error': 'Ошибка добавление нового пользователя = {0}'.format(str(e)), + } + + + +def decode_get_param(data): + import base64 + import json + + d = data['data'].encode() + token_data = base64.b64decode(d) + + try: + request_data = token_data.decode('utf8') + except: + request_data = token_data + + data = json.loads(request_data) + + return data + + + + +def recovery_password_user(request, uidb64=None, token=None): + from django.contrib.auth.views import PasswordResetConfirmView + + return PasswordResetConfirmView(request=request, uidb64=uidb64, token=token + ) + + + + +def create_temporary_user(): + from django.utils.translation import gettext as _ + user_id = str(uuid1().hex)[:10] + user_name = u'user'+user_id + mail = user_id+u'@truenergy.by' + user = User.objects.create_user(mail, mail,user_id) + user.first_name = _(u'незарег. пользователь') + user.last_name = u'' + user.is_staff = False + user.is_active = True + user.is_superuser = False + user.set_password(user_id) + # print(u'user_create_pass', user.password) + # p = user.get_profile() + # p.address = '' + # p.phone = '' + # p.group = None + # p.discount = 0 + # p.pay_balance = 0 + # p.authMailCode = uuid1().hex + # p.save() + + user.save() + user.mipp_user.temporary_user = True + user.mipp_user.save() + # print('user',user) + # print('created profile',p) + # print('user created', user) + return { + 'name' : mail, + 'pass' : user_id, + 'user' : user + } + + +def get_active_user(request): + if request.user.is_anonymous: + return None + else: + user = request.user + # try: + # bd = user.mipp_user.birthdate + # except MIPPUser.DoesNotExist: + # MIPPUser.objects.create(user=user) + + return user + + +def get_active_user_if_anonymous_create_temporary(request): + + user = get_active_user(request) + + if not user: + new_user_Dict = create_temporary_user() + user = auth.authenticate(username=new_user_Dict['name'], password=new_user_Dict['pass']) + if user: + auth.login(request, user) + + return user \ No newline at end of file diff --git a/BaseModels/admin_utils.py b/BaseModels/admin_utils.py index 2216655..9e32e4c 100644 --- a/BaseModels/admin_utils.py +++ b/BaseModels/admin_utils.py @@ -95,8 +95,8 @@ class AdminImageWidget(AdminFileWidget): return mark_safe(u''.join(output)) -def init_formfield_for_dbfield(class_model, self, db_field, **kwargs): - formfield = super(class_model, self).formfield_for_dbfield(db_field, **kwargs) +def init_formfield_for_dbfield(class_model, self, db_field, request, **kwargs): + formfield = super(class_model, self).formfield_for_dbfield(db_field, request, **kwargs) if db_field.name == 'url' or db_field.name == 'name' or db_field.name == 'title' or db_field.name == 'name_plural': formfield.widget = admin.widgets.AdminTextInputWidget(attrs={'style': 'width: 80%'}) if db_field.name == 'workListForServicePage': @@ -258,8 +258,8 @@ class Admin_BaseIconModel(admin.ModelAdmin): description_exists.short_description = u'Описание' description_exists.allow_tags = True - def formfield_for_dbfield (self, db_field, **kwargs): - return init_formfield_for_dbfield(Admin_BaseIconModel, self, db_field, **kwargs) + def formfield_for_dbfield (self, db_field, request, **kwargs): + return init_formfield_for_dbfield(Admin_BaseIconModel, self, db_field, request, **kwargs) formfield_overrides = { models.ImageField: {'widget': AdminImageWidget}, @@ -273,15 +273,27 @@ class Admin_BaseIconModel(admin.ModelAdmin): # from modeltranslation.admin import TranslationAdmin +# # class CustomTranslationAdmin(TranslationAdmin): +# # # def formfield_for_dbfield(self, db_field, **kwargs): +# # # field = super().formfield_for_dbfield(db_field, **kwargs) +# # # self.patch_translation_field(db_field, field, **kwargs) +# # # return field +# +# # class AdminTranslation_BaseIconModel(Admin_BaseIconModel, TranslationAdmin): # +# # def formfield_for_dbfield(self, db_field, **kwargs): +# # field = super(AdminTranslation_BaseIconModel, self).formfield_for_dbfield(db_field, **kwargs) +# # self.patch_translation_field(db_field, field, **kwargs) +# # return field # # class Media: +# # js = ( -# 'https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js', -# 'https://ajax.googleapis.com/ajax/libs/jqueryui/1.10.2/jquery-ui.min.js', +# 'modeltranslation/js/force_jquery.js', +# 'http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js', +# 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.2/jquery-ui.min.js', # 'modeltranslation/js/tabbed_translation_fields.js', -# # 'cked/ckeditor/ckeditor.js' # ) # css = { # 'screen': ('modeltranslation/css/tabbed_translation_fields.css',), diff --git a/BaseModels/base_models.py b/BaseModels/base_models.py index c8ef726..e1140a0 100644 --- a/BaseModels/base_models.py +++ b/BaseModels/base_models.py @@ -29,7 +29,10 @@ class BaseModel(models.Model): json_data = models.JSONField(verbose_name=_('Дополнительные данные'), default=dict, blank=True) def __str__(self): - return self.name + if self.name: + return self.name + else: + return str(self.id) def get_node_by_name(self, node_name): if not self.json_data or not node_name in self.json_data: diff --git a/GeneralApp/admin.py b/GeneralApp/admin.py index 20bbd25..86dde16 100644 --- a/GeneralApp/admin.py +++ b/GeneralApp/admin.py @@ -2,24 +2,23 @@ from sets.admin import * from .models import * from django.contrib import admin - -class Admin_StaticPage(Admin_BaseModelViewPage): +class Admin_StaticPage(Admin_Trans_BaseModelViewPage): def get_fieldsets(self, request, obj=None): fieldsets = super(type(self), self).get_fieldsets(request, obj) if not request.user.is_superuser and obj.url and obj.url in ('main', 'spec_technics', 'works'): fieldsets[0][1]['fields'].pop(2) - fieldsets.insert( - 1, ('Промо-хэдер', { - 'classes': ['wide'], - 'fields': ( - 'promo_header', - 'title', 'description', 'text', - 'picture', - ) - - }) - ) + # fieldsets.insert( + # 1, ('Промо-хэдер', { + # 'classes': ['wide'], + # 'fields': ( + # 'promo_header', + # 'title', 'description', 'text', + # 'picture', + # ) + # + # }) + # ) return fieldsets def has_delete_permission(self, request, obj=None): diff --git a/GeneralApp/migrations/0002_block_faq_title_en_block_faq_title_ru_and_more.py b/GeneralApp/migrations/0002_block_faq_title_en_block_faq_title_ru_and_more.py new file mode 100644 index 0000000..faffa85 --- /dev/null +++ b/GeneralApp/migrations/0002_block_faq_title_en_block_faq_title_ru_and_more.py @@ -0,0 +1,144 @@ +# Generated by Django 4.2.2 on 2023-06-20 15:48 + +import ckeditor.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('GeneralApp', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='block', + name='FAQ_title_en', + field=models.CharField(blank=True, max_length=250, null=True, verbose_name='FAQ Заголовок'), + ), + migrations.AddField( + model_name='block', + name='FAQ_title_ru', + field=models.CharField(blank=True, max_length=250, null=True, verbose_name='FAQ Заголовок'), + ), + migrations.AddField( + model_name='block', + name='description_en', + field=ckeditor.fields.RichTextField(blank=True, help_text='краткое описание страницы (до 240 символов)', null=True, verbose_name='Краткое описание'), + ), + migrations.AddField( + model_name='block', + name='description_ru', + field=ckeditor.fields.RichTextField(blank=True, help_text='краткое описание страницы (до 240 символов)', null=True, verbose_name='Краткое описание'), + ), + migrations.AddField( + model_name='block', + name='name_en', + field=models.TextField(blank=True, help_text='Название', null=True, verbose_name='Название'), + ), + migrations.AddField( + model_name='block', + name='name_ru', + field=models.TextField(blank=True, help_text='Название', null=True, verbose_name='Название'), + ), + migrations.AddField( + model_name='block', + name='text_en', + field=ckeditor.fields.RichTextField(blank=True, null=True, verbose_name='Полное описание'), + ), + migrations.AddField( + model_name='block', + name='text_ru', + field=ckeditor.fields.RichTextField(blank=True, null=True, verbose_name='Полное описание'), + ), + migrations.AddField( + model_name='block', + name='title_en', + field=models.TextField(blank=True, null=True, verbose_name='Заголовок'), + ), + migrations.AddField( + model_name='block', + name='title_ru', + field=models.TextField(blank=True, null=True, verbose_name='Заголовок'), + ), + migrations.AddField( + model_name='faqitem', + name='answer_en', + field=ckeditor.fields.RichTextField(null=True, verbose_name='Ответ'), + ), + migrations.AddField( + model_name='faqitem', + name='answer_ru', + field=ckeditor.fields.RichTextField(null=True, verbose_name='Ответ'), + ), + migrations.AddField( + model_name='faqitem', + name='name_en', + field=models.TextField(blank=True, help_text='Название', null=True, verbose_name='Название'), + ), + migrations.AddField( + model_name='faqitem', + name='name_ru', + field=models.TextField(blank=True, help_text='Название', null=True, verbose_name='Название'), + ), + migrations.AddField( + model_name='faqitem', + name='question_en', + field=models.TextField(null=True, verbose_name='Вопрос'), + ), + migrations.AddField( + model_name='faqitem', + name='question_ru', + field=models.TextField(null=True, verbose_name='Вопрос'), + ), + migrations.AddField( + model_name='staticpage', + name='FAQ_title_en', + field=models.CharField(blank=True, max_length=250, null=True, verbose_name='FAQ Заголовок'), + ), + migrations.AddField( + model_name='staticpage', + name='FAQ_title_ru', + field=models.CharField(blank=True, max_length=250, null=True, verbose_name='FAQ Заголовок'), + ), + migrations.AddField( + model_name='staticpage', + name='description_en', + field=ckeditor.fields.RichTextField(blank=True, help_text='краткое описание страницы (до 240 символов)', null=True, verbose_name='Краткое описание'), + ), + migrations.AddField( + model_name='staticpage', + name='description_ru', + field=ckeditor.fields.RichTextField(blank=True, help_text='краткое описание страницы (до 240 символов)', null=True, verbose_name='Краткое описание'), + ), + migrations.AddField( + model_name='staticpage', + name='name_en', + field=models.TextField(blank=True, help_text='Название', null=True, verbose_name='Название'), + ), + migrations.AddField( + model_name='staticpage', + name='name_ru', + field=models.TextField(blank=True, help_text='Название', null=True, verbose_name='Название'), + ), + migrations.AddField( + model_name='staticpage', + name='text_en', + field=ckeditor.fields.RichTextField(blank=True, null=True, verbose_name='Полное описание'), + ), + migrations.AddField( + model_name='staticpage', + name='text_ru', + field=ckeditor.fields.RichTextField(blank=True, null=True, verbose_name='Полное описание'), + ), + migrations.AddField( + model_name='staticpage', + name='title_en', + field=models.TextField(blank=True, null=True, verbose_name='Заголовок'), + ), + migrations.AddField( + model_name='staticpage', + name='title_ru', + field=models.TextField(blank=True, null=True, verbose_name='Заголовок'), + ), + ] diff --git a/GeneralApp/models.py b/GeneralApp/models.py index 9beeea7..085058a 100644 --- a/GeneralApp/models.py +++ b/GeneralApp/models.py @@ -39,7 +39,10 @@ class FAQitem(BaseModel): answer = RichTextField(verbose_name='Ответ') def __str__(self): - return self.question + if self.question: + return self.question + else: + return self.id class Meta: verbose_name = 'FAQ' diff --git a/GeneralApp/translation.py b/GeneralApp/translation.py new file mode 100644 index 0000000..d858c2a --- /dev/null +++ b/GeneralApp/translation.py @@ -0,0 +1,23 @@ +from modeltranslation.translator import translator, TranslationOptions +from .models import * + + +class StaticPage_TranslationOptions(TranslationOptions): + fields = ( + 'name', 'description', 'text', 'title', 'FAQ_title' + ) +translator.register(StaticPage, StaticPage_TranslationOptions) + +class Block_TranslationOptions(TranslationOptions): + fields = ( + 'name', 'description', 'text', 'title', 'FAQ_title' + ) +translator.register(Block, Block_TranslationOptions) + + +class FAQitem_TranslationOptions(TranslationOptions): + fields = ( + 'name', 'question', 'answer' + ) +translator.register(FAQitem, FAQitem_TranslationOptions) + diff --git a/TWB/settings.py b/TWB/settings.py index 0b4026a..2396ac6 100644 --- a/TWB/settings.py +++ b/TWB/settings.py @@ -31,6 +31,8 @@ ALLOWED_HOSTS = [] # Application definition INSTALLED_APPS = [ + 'modeltranslation', + 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', @@ -42,7 +44,10 @@ INSTALLED_APPS = [ 'ckeditor', 'ckeditor_uploader', + + 'GeneralApp', + 'AuthApp', ] MIDDLEWARE = [ @@ -137,6 +142,31 @@ STATICFILES_DIRS = [ BASE_DIR / "static", ] + +import os +LOCALE_PATHS = ( + os.path.join(BASE_DIR,'locale'), +) + + +gettext = lambda s: s +LANGUAGES = ( + (u'ru', gettext(u'Russian')), + (u'en', gettext(u'English')), +) +MODELTRANSLATION_LANGUAGES = ('ru', 'en') +MODELTRANSLATION_ENABLE_FALLBACKS = True +MODELTRANSLATION_FALLBACK_LANGUAGES = { + 'default': ('ru','en'), +} + +# Add custom languages not provided by Django +import django.conf.locale +LANG_INFO = dict(django.conf.locale.LANG_INFO.items()) #+ EXTRA_LANG_INFO.items()) +django.conf.locale.LANG_INFO = LANG_INFO + + + # Default primary key field type # https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field diff --git a/TWB/urls.py b/TWB/urls.py index 6fb9822..fc64405 100644 --- a/TWB/urls.py +++ b/TWB/urls.py @@ -8,6 +8,15 @@ urlpatterns = [ path('admin/', admin.site.urls), path('ckeditor/', include('ckeditor_uploader.urls')), - path('', include('GeneralApp.urls')), + # path('', include('GeneralApp.urls')), ] + +from django.conf.urls.i18n import i18n_patterns +urlpatterns += i18n_patterns( + path('admin/', admin.site.urls), + + path('', include('GeneralApp.urls')), + +) + urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) \ No newline at end of file diff --git a/requirements.pip b/requirements.pip index eadface..c93faea 100644 --- a/requirements.pip +++ b/requirements.pip @@ -2,4 +2,5 @@ Django==4.2.2 django-ckeditor==6.5.1 psycopg2-binary==2.9.6 requests -Pillow \ No newline at end of file +Pillow +django-modeltranslation=0.18.10 diff --git a/sets/admin.py b/sets/admin.py index b8b8da7..0a935c6 100644 --- a/sets/admin.py +++ b/sets/admin.py @@ -1,4 +1,4 @@ -from BaseModels.admin_utils import Admin_BaseIconModel, Admin_GenericBaseIconStackedInline +from BaseModels.admin_utils import Admin_GenericBaseIconStackedInline, Admin_BaseIconModel from copy import deepcopy class AdminStacked_FAQitem(Admin_GenericBaseIconStackedInline): @@ -36,12 +36,14 @@ class Admin_BaseModel(Admin_BaseIconModel): list_display_links = ('id', 'name') -class Admin_BaseBlock(Admin_BaseModel): +class Admin_BaseBlock(Admin_BaseIconModel): + pass def get_fieldsets(self, request, obj=None): fieldsets = super(Admin_BaseBlock, self).get_fieldsets(request, obj) return fieldsets -class Admin_BaseModelViewPage(Admin_BaseBlock): +class Admin_BaseModelViewPage(Admin_BaseIconModel): + pass def get_fieldsets(self, request, obj=None): fieldsets = super(Admin_BaseModelViewPage, self).get_fieldsets(request, obj) # fieldsets = deepcopy(self.fieldsets) @@ -66,3 +68,36 @@ class Admin_BaseModelViewPage(Admin_BaseBlock): inlines = [AdminStacked_FAQitem] + + + + +from modeltranslation.admin import TranslationAdmin +class AdminTranslationBase(TranslationAdmin): + + # def formfield_for_dbfield(self, db_field, **kwargs): + # field = super(AdminTranslation_BaseIconModel, self).formfield_for_dbfield(db_field, **kwargs) + # self.patch_translation_field(db_field, field, **kwargs) + # return field + + class Media: + + js = ( + 'modeltranslation/js/force_jquery.js', + 'http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js', + 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.2/jquery-ui.min.js', + 'modeltranslation/js/tabbed_translation_fields.js', + ) + css = { + 'screen': ('modeltranslation/css/tabbed_translation_fields.css',), + } + + +class Admin_Trans_BaseModel(Admin_BaseModel, AdminTranslationBase): + pass +# +# class Admin_Trans_BaseModelViewPage(AdminTranslation_BaseIconModel): +# pass + +class Admin_Trans_BaseModelViewPage(Admin_BaseModelViewPage, AdminTranslationBase): + pass \ No newline at end of file