Compare commits
594 Commits
cc6bd781e0
...
feature/su
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
15c9d589fe | ||
|
|
fa116c08c1 | ||
|
|
4f9129e718 | ||
|
|
df45f3a704 | ||
|
|
90ef093fca | ||
| 4331b26542 | |||
| dd8a8ddd53 | |||
| abb0d488eb | |||
| be97b848d0 | |||
| 6bc112d689 | |||
| dc534a0c51 | |||
| e71ed05e6c | |||
| 2048ed6baf | |||
| c146bd6155 | |||
| 98665abf4d | |||
| 9954140d3a | |||
| fafee63a64 | |||
| c623d69767 | |||
| 670eb28bc0 | |||
| 144ff286f6 | |||
| 05f94de0b4 | |||
| c4650ce603 | |||
| 3971a8ee23 | |||
| a3ba6bc783 | |||
| b87df02714 | |||
| 713695cf7d | |||
| a25f30eda7 | |||
| eddb3a1858 | |||
| 5a89200f1d | |||
| 2f47a9e3db | |||
| 155b6272ec | |||
| 1479584bfc | |||
| f86be5bd97 | |||
| c87a7095ad | |||
| ac4df7a5f7 | |||
| c48839ff8c | |||
| ea296e3f05 | |||
| 8124ed62fe | |||
| cc643d2641 | |||
| 6de42c5ba9 | |||
| 36b7f4dee7 | |||
| 2328f09023 | |||
| 60faeeace9 | |||
| abe53dd88b | |||
| c76a18c5ff | |||
| 3725ce1882 | |||
| 6a69ff02b1 | |||
| 6ba41af305 | |||
| 5815a08b55 | |||
| 7805161829 | |||
| 6fa31f3866 | |||
| 0763faf224 | |||
| a3d3e12467 | |||
| ab22a3ec88 | |||
| 9d0a059909 | |||
| 1011f112b2 | |||
| d07ab2c71f | |||
| 96bfef04a8 | |||
| 779dd7e93d | |||
| 0abcb34829 | |||
| 33c028207a | |||
| 64b3e40ed0 | |||
| 0023676b28 | |||
| b90039f21a | |||
| b5f24ebf2e | |||
| f99a010e4a | |||
| a4944360a6 | |||
| a2b5d81c98 | |||
| 13b7c2572d | |||
| 47b12882ba | |||
| c008aa585b | |||
| 406b5e8480 | |||
| 584a196784 | |||
| 618f7751d1 | |||
| faaea1129a | |||
| dd7afc28f7 | |||
| 9ecf5ce073 | |||
| 422373f00e | |||
| 60636daeb8 | |||
| 9d47f4c2bc | |||
| 4d6dbddd28 | |||
| 3f00ff39d2 | |||
| bff6a81586 | |||
| 9cb8036d3c | |||
| a43de1fa91 | |||
| 93717bee2d | |||
| 8db1d6fdce | |||
| b41f8c7eca | |||
| c19405d32a | |||
| 7b75c533a8 | |||
| 649dbab901 | |||
| 1a4498d19f | |||
| 2786ef454d | |||
| 961c0dd2a5 | |||
| 0a0835d3a6 | |||
| bc87d10d59 | |||
| 792693848b | |||
| de229c5f78 | |||
| 03f9a836e6 | |||
| 91751574cc | |||
| d5453dada6 | |||
| 22adb18a39 | |||
| 0a3c40dd5d | |||
| b29825d62b | |||
| c9bda8aab2 | |||
| 284a4b064a | |||
| 6f20f53d75 | |||
| 473a047af9 | |||
| 481f9a881f | |||
| 6ceedddbc1 | |||
| bd9e0fad48 | |||
| 6b118d00b6 | |||
| 01e221196f | |||
| ccf016999b | |||
| cb79e47796 | |||
| 4076bd6065 | |||
| e54c258007 | |||
| c3b7401255 | |||
| 9af72d30f4 | |||
| dbe948ae5f | |||
| 885d36a90c | |||
| 7acfbc0113 | |||
| 43c5faf988 | |||
| 437142fba0 | |||
| acf7b702ee | |||
| 74ca1be884 | |||
| 26b987d6ce | |||
| 3f7f1d88ed | |||
| 59225b1688 | |||
| 108aee2c43 | |||
| 9062ce32a1 | |||
| 7c74a0f3fe | |||
| 4fb3a12f47 | |||
| 59bc25f31c | |||
| 87fbe7852c | |||
| 793d283d97 | |||
| 651ae18345 | |||
| 67eb32968e | |||
| c6d41513c0 | |||
| 67ba698b60 | |||
| 15d1c00ac6 | |||
| 9e9a82ffc0 | |||
| a0eb5210ab | |||
| 3dacc0316e | |||
| e2c347c912 | |||
| 758f8b1f55 | |||
| b446a8f519 | |||
| c8ba0dd770 | |||
| f13a1329ca | |||
| 4b3604098f | |||
| defbf6746f | |||
| bf3f26ec4f | |||
| 76018333b0 | |||
| e6e345b9fe | |||
| eafccabb66 | |||
| f2e0628de1 | |||
| 2e1f3a10ab | |||
| bf18c96dbd | |||
| 23718a5f3f | |||
| c6a1d5bdcf | |||
| f75e94f706 | |||
| 11c9bb6c23 | |||
| b1ff9c47da | |||
| 35c09dc70b | |||
| f0efae5987 | |||
| 65120cd2d4 | |||
| 231d062814 | |||
| 615922a881 | |||
| 61b2b824d5 | |||
| 317445998a | |||
| 4ad3813499 | |||
| 9a88243323 | |||
| df0f32c71a | |||
| 4ddd402442 | |||
| a05c4b3898 | |||
| a3ab0973c9 | |||
| 0f801aa44b | |||
| 7bc386bc44 | |||
| e148c60d70 | |||
| 4667352ec4 | |||
| e7cf694d88 | |||
| b2abb3046b | |||
| 6c1011e59e | |||
| ad909b98bf | |||
| 9d2e35246a | |||
| 48dc573c0f | |||
| e559660912 | |||
| aa3bec304a | |||
| c7bc22813f | |||
| 46e73db10a | |||
| ad451c2ae0 | |||
| 0b5b557a35 | |||
| fb9228c432 | |||
| fbcbe93042 | |||
| ca44deb077 | |||
| 61403bfac2 | |||
| 190efa4b74 | |||
| ca06836b11 | |||
| b31241872f | |||
| f80e2844bf | |||
| 1dae86f0e7 | |||
| 0c146caeef | |||
| 410733211b | |||
| 14df8969c2 | |||
| 4388414ac2 | |||
| 791ac8d436 | |||
| a3d6f498b1 | |||
| b8fdd61948 | |||
| 4437372d7c | |||
| f8d29d80b7 | |||
| 36fd9599af | |||
| 65eccde487 | |||
| 037b4cc562 | |||
| 9c971a6fa4 | |||
| a3faa17754 | |||
| 085f905125 | |||
| dc16ced786 | |||
| d5cba26098 | |||
| 001dd2cb87 | |||
| 16e860a29f | |||
| 6a5331d8eb | |||
| aff0b0fe98 | |||
| fd3612c370 | |||
| d14a46d3d7 | |||
| d7ace77de8 | |||
| 885e4722af | |||
| 72ed6369d8 | |||
| b23e440efd | |||
| 75ddb002fd | |||
| 28a36335ce | |||
| fba225aa70 | |||
| af800ac84c | |||
| 87e90d7152 | |||
| c25942a6ca | |||
| 692419816f | |||
| 3a109340fd | |||
| 5925ecb975 | |||
| 325acd3580 | |||
| 3ac85784a9 | |||
| 5c4e715970 | |||
| 89b57feb4e | |||
| fc194d3f85 | |||
| 12af0ea238 | |||
| 6e758cf62e | |||
| f7783c070b | |||
| fb3cd30db4 | |||
| ff949a8205 | |||
| 624653f581 | |||
| f3e5f02f07 | |||
| d0792e9e84 | |||
| f752eb5d4a | |||
| f0861fde84 | |||
| 4e7aa09c21 | |||
| e68a0dc151 | |||
| fc37bea98a | |||
| 8a91e611ac | |||
| 7208db6981 | |||
| 447a78cd3a | |||
| 95dff519b8 | |||
| 62aeebae95 | |||
| c2e03728f8 | |||
| a64fbab270 | |||
| 00ea16f631 | |||
| e3aafcdfe9 | |||
| 421a3a2dab | |||
| 61e4f7e450 | |||
| 3b52cab162 | |||
| fe9be61772 | |||
| 0818f880cc | |||
| cca062efec | |||
| 2eb7ac85d3 | |||
| 3469a3923c | |||
| 20fb49b3e4 | |||
| afe8feebc2 | |||
| ae6a68d85b | |||
| d80c45acd5 | |||
| 3a9ac2c289 | |||
| 2d68836724 | |||
| 0deb85b5a3 | |||
| 7b38f6e3b3 | |||
| 43f050f070 | |||
| 098b7c4fb5 | |||
| eae56199e0 | |||
| 71e8f0f465 | |||
| 66d7183278 | |||
| 92b92f2d65 | |||
| d5ab7d82eb | |||
| 1ebd9f9c0b | |||
| 7fd2c60ddb | |||
| f068182557 | |||
| 02945b0691 | |||
| 21b959e6a3 | |||
| 747091c744 | |||
| 7b70052ff1 | |||
| 49fd26bc4c | |||
| 77f365ef45 | |||
| 6d34d46e38 | |||
| 970c2e0837 | |||
| b87549d567 | |||
| 78abdb2fef | |||
| f73ebb08c9 | |||
| 628e8eec09 | |||
| 66ddcaec5b | |||
| 3901c82aae | |||
| 9f682b66a5 | |||
| c74aff7b91 | |||
| 1be50b1277 | |||
| af00d1a54b | |||
| dd4ad82248 | |||
| 38c08cbced | |||
| ed2c74a280 | |||
| 90ab1bb6b4 | |||
| 3e2220e5f2 | |||
| 33e27620b1 | |||
| fbdef2a1ec | |||
| 1834639b50 | |||
| f9606a3c88 | |||
| c803d7abbb | |||
| efd75817bc | |||
| 36fff15e2b | |||
| 7573bfb344 | |||
| 0c33d638ba | |||
| 7d3da34e22 | |||
| 0e2723a367 | |||
| b102c44031 | |||
| 4b480c35e5 | |||
| 8e7bcd8fd8 | |||
| c60c545031 | |||
| 51d075f799 | |||
| db54ec1650 | |||
| 14b362442f | |||
| fcfbeece87 | |||
| aea501aedb | |||
| f1d175fe84 | |||
| 0f432c4fd9 | |||
| b53e19c439 | |||
| bebd20abf0 | |||
| 5dc2293212 | |||
| 37f480c01e | |||
| f16efa24b0 | |||
| e11d05eb02 | |||
| 32cd45106d | |||
| 7b95893b34 | |||
| b6769f6350 | |||
| 5650b2d6b9 | |||
| f0fe8edf80 | |||
| b30df5b6ed | |||
| 0ef26556a2 | |||
| ea92feab27 | |||
| 1720e156d2 | |||
| 9ed06e741e | |||
| d39a3a78d0 | |||
| 09dc2984f3 | |||
| 660e3f8a99 | |||
| cc9797eb71 | |||
| 6a8aa73e63 | |||
| 689495e410 | |||
| 415fad4f4e | |||
| 396db7a439 | |||
| 61bea5639b | |||
| c9d6812d11 | |||
| 18dd435678 | |||
| a7a4112312 | |||
| cf8cb9a6a4 | |||
| b31f1ddb0f | |||
| 382ddd48e4 | |||
| 0b57fa9238 | |||
| fe7721270b | |||
| 49b35abb0b | |||
| 41dbb6bad7 | |||
| fde640e997 | |||
| fd1f4ff9b1 | |||
| 3a4c1b12a6 | |||
| ce68dbee8a | |||
| 1976a4c1dc | |||
| 0dc3419651 | |||
| 7769608e03 | |||
| 9772d7670b | |||
| 36e9edb51b | |||
| 6191980dc7 | |||
| 7179b67137 | |||
| 65362e34b8 | |||
| ec76d336f3 | |||
| 12d5e4546d | |||
| 4a97b02010 | |||
| aa492f6ca4 | |||
| 7547d2cb89 | |||
| 3febf729b6 | |||
| fbfdec2380 | |||
| fb665b409c | |||
| f86e76615d | |||
| 7cfe3f699a | |||
| 03ab2ae2cd | |||
| ad1016a427 | |||
| 6fc40452d9 | |||
| de098bdf55 | |||
| dcfd66324e | |||
| ff962b9658 | |||
| 006ff44858 | |||
| f9fdcc5314 | |||
| e49605dea6 | |||
| e429f48320 | |||
| 43ef016751 | |||
| 4a59adc73f | |||
| 2ebc28519e | |||
| 23de94b8cd | |||
| 42cf20137b | |||
| d5bb15e695 | |||
| 039985fe5f | |||
| d618c10e8b | |||
| 069f2094f0 | |||
| 2b6bbba265 | |||
| f7e032a5bc | |||
| 0d394fb6b7 | |||
| 9635a1dcf2 | |||
| 6ae3a88d7b | |||
| 512499ab12 | |||
| b8e3092fc4 | |||
| 4b9e5e5f34 | |||
| a7d9dfe79a | |||
| cc503ec6d1 | |||
| 7eb8edbe1f | |||
| 1f4ccaec4a | |||
| 66e0edebc5 | |||
| ebdc84f7e1 | |||
| cd1b8d4579 | |||
| a733649521 | |||
| 01d72c5f45 | |||
| 55681c7fb8 | |||
| 4a19726a99 | |||
| 61f26299b8 | |||
| 8a6317da2b | |||
| 1124149cf8 | |||
| 426071fe15 | |||
| c97aa44723 | |||
| de6bd9682e | |||
| 16e7ea3109 | |||
| 41fa14351a | |||
| 35f135a10b | |||
| 037abac188 | |||
| fecd32a254 | |||
| 446af5e438 | |||
| 71ecd65814 | |||
| 3e101493dc | |||
| 453d4b7349 | |||
| 40a8bc158a | |||
| 2c711ed370 | |||
| fc1654dedb | |||
| dfec56fef9 | |||
| 942db49daf | |||
| d4562e7ca4 | |||
| 3a0845fe2a | |||
| 3740ac642f | |||
| c1ccf00302 | |||
| 4400a6b13f | |||
| 66fbf984e9 | |||
| 30ebc6037a | |||
| ac60b08f2d | |||
| f32e127148 | |||
| 8e3b798bce | |||
| 57dddf528b | |||
| 35d5e05f00 | |||
| 4ecc89a4e7 | |||
| 87bc1be15a | |||
| b1c599e71d | |||
| da3fb36a22 | |||
| ded7761c91 | |||
| d4de2ef739 | |||
| 7637f6fdd1 | |||
| f663954f03 | |||
| f2fd95b04e | |||
| 3880b97cae | |||
| 2fb00ee112 | |||
| dc92877beb | |||
| d9103e62a7 | |||
| e5a8c3cb8f | |||
| 97b00d94cf | |||
| 381f0a8490 | |||
| b8b3fd02fa | |||
| 3b244f4de0 | |||
| c4d101275a | |||
| c9b21ded98 | |||
| f5115f82fb | |||
| d6a6b4f319 | |||
| f3e418cf68 | |||
| a74a0c1f57 | |||
| 0f10e274e6 | |||
| 57a419eeaa | |||
| aa18a3c542 | |||
| dea8d064d4 | |||
| d022fb231f | |||
| 415784bf06 | |||
| 246974c1b8 | |||
| 34d2fea31f | |||
| 0571de3dd0 | |||
| 4e2d453ff1 | |||
| f4ba38654b | |||
| 7831973cdb | |||
| 4f2c7aeb2c | |||
| 237666d96f | |||
| f6d0486a19 | |||
| 200a9c308c | |||
| 28d3138c43 | |||
| 0d41c95e3d | |||
| e5ea92df3d | |||
| 9f7550eaae | |||
| 3e88458fce | |||
| a5cbf8c128 | |||
| 704b88320a | |||
| 0aae04eca8 | |||
| 3f1cd5431f | |||
| 5081b6ce3e | |||
| 7e7fb437a6 | |||
| addca29f0f | |||
| f1775237fb | |||
| f09ff3f7df | |||
| 4259f84764 | |||
| 707bbf1863 | |||
| a989f85b2b | |||
| b62396a907 | |||
| 998c91c727 | |||
| 64b8e74612 | |||
| 55eff16b9c | |||
| 31857131be | |||
| 77de950af8 | |||
| 176c84cf2d | |||
| 15ea6a982c | |||
| 6230b77473 | |||
| 2f81a73078 | |||
| cf83ae059e | |||
| 4418d4ad6f | |||
| 239b6a0da1 | |||
| cc02495459 | |||
| 153d0380de | |||
| 87fb930c63 | |||
| 38a8cef3d9 | |||
| 6f7551abbf | |||
| 64d6860e58 | |||
| 88e6c7eee8 | |||
| 75c5553852 | |||
| 9d1815c21f | |||
| c93cda4eaf | |||
| cce969d870 | |||
| 0b177d845c | |||
| 42f288e0e4 | |||
| 3948c79891 | |||
| c8a28de46a | |||
| c660d8cb72 | |||
| a2688c4a15 | |||
| 9d2e9b7acd | |||
| f37ed72b39 | |||
| 6fd3c11f06 | |||
| 414ffc703d | |||
| f7a587b7a5 | |||
| 534defa36b | |||
| 1fbf846270 | |||
| e6a1cd967e | |||
| c9adf1a785 | |||
| 8380b7e66e | |||
| e01c7e81f2 | |||
| 4751dd9079 | |||
| f82ae16e31 | |||
| 8a00446b5c | |||
| 39f37bcd23 | |||
| c8e4df8150 | |||
| 1e9e2cb048 | |||
| 06661cb187 | |||
| fade021048 | |||
| 9d90138847 | |||
| b7a677d79d | |||
| 3660f5af6d | |||
| 61e1c35f02 | |||
| 89721ce797 | |||
| 55b4c0ac11 | |||
| 70df8a53c8 | |||
| 3311ab5b37 | |||
| 49ad367a70 | |||
| cc3a5c4a4f | |||
| f7af979b7e | |||
| 6f06f96a94 | |||
| a3ef86ba37 | |||
| d6da292d5f | |||
| ccb8c6585c | |||
| ea567008c6 | |||
| 6cbde10b11 | |||
| 7e23776501 | |||
| e6a91ebc72 | |||
| 06a2e883fb | |||
| 00b0e00fd3 | |||
| 8086d5344e | |||
| ea76733305 | |||
| f0f8af48b3 | |||
| 9bc02c7752 | |||
| 3067535fe0 |
1
.gitignore
vendored
@@ -414,4 +414,5 @@ fabric.properties
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
celerybeat-schedule.db
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from django.contrib import admin
|
||||
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from ArticlesApp.models import ArticleModel, UserPageModel
|
||||
from sets.admin import *
|
||||
|
||||
@@ -68,7 +68,7 @@ class Admin_Article(Admin_Trans_BaseModelViewPage):
|
||||
# ('devices'),
|
||||
)
|
||||
}),
|
||||
(u'Статья', {
|
||||
(_('Статья'), {
|
||||
'classes': ['wide'],
|
||||
'fields': (
|
||||
'description', 'text',
|
||||
@@ -114,7 +114,7 @@ class Admin_UserPage(Admin_Trans_BaseModelViewPage):
|
||||
# ('devices'),
|
||||
)
|
||||
}),
|
||||
(u'Статья', {
|
||||
(_('Статья'), {
|
||||
'classes': ['wide'],
|
||||
'fields': ('picture', 'description', 'text')
|
||||
}),
|
||||
@@ -149,7 +149,7 @@ class Admin_UserPage(Admin_Trans_BaseModelViewPage):
|
||||
if request.user.is_superuser:
|
||||
return True
|
||||
|
||||
if obj and obj.url in ('for-partners', 'dealers', 'about-truenergy', 'contacts'):
|
||||
if obj and obj.url in ('for-partners', 'dealers', 'contacts'):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
from .models import *
|
||||
|
||||
|
||||
elements_on_page = 10
|
||||
|
||||
def get_articles(art_kwargs, request_Data=None, from_el=None, to_el=None):
|
||||
|
||||
if request_Data:
|
||||
@@ -20,17 +22,24 @@ def get_articles(art_kwargs, request_Data=None, from_el=None, to_el=None):
|
||||
elif to_el:
|
||||
arts = arts[:to_el]
|
||||
else:
|
||||
to_el = 3
|
||||
to_el = elements_on_page
|
||||
arts = arts[:to_el]
|
||||
|
||||
last_block = False
|
||||
if not to_el or to_el >= el_count:
|
||||
last_block = True
|
||||
|
||||
if el_count - to_el > elements_on_page:
|
||||
next_page_els_count = elements_on_page
|
||||
else:
|
||||
next_page_els_count = el_count - to_el
|
||||
|
||||
Dict = {
|
||||
'articles': arts,
|
||||
'last_block': last_block,
|
||||
'last_el': to_el
|
||||
'last_el': to_el,
|
||||
'next_page_els_count': next_page_els_count,
|
||||
'elements_on_page': elements_on_page
|
||||
}
|
||||
|
||||
return Dict
|
||||
|
||||
@@ -37,7 +37,8 @@ def get_articles_block_ajax(request):
|
||||
|
||||
res_Dict = {
|
||||
'html': html,
|
||||
'last_block': Dict['last_block']
|
||||
'last_block': Dict['last_block'],
|
||||
'next_page_els_count': Dict['next_page_els_count'],
|
||||
# 'form': RouteForm(initial=data)
|
||||
}
|
||||
|
||||
@@ -45,9 +46,10 @@ def get_articles_block_ajax(request):
|
||||
|
||||
except Exception as e:
|
||||
|
||||
|
||||
errors_Dict = {
|
||||
'errors': {
|
||||
'all__': f'ошибка в запросе = {str(e)}'
|
||||
'all__': f'{_("ошибка в запросе")} = {str(e)}'
|
||||
}
|
||||
}
|
||||
return JsonResponse(errors_Dict, status=400)
|
||||
@@ -19,11 +19,11 @@ from django.utils.translation import gettext_lazy as _
|
||||
|
||||
class UserPageModel(BaseModelViewPage):
|
||||
# pub_DT = models.DateTimeField(verbose_name=u'Дата и время публикации', auto_created=True)
|
||||
text = RichTextUploadingField(verbose_name=u'Текст')
|
||||
text = RichTextUploadingField(verbose_name=_('Текст'))
|
||||
|
||||
class Meta:
|
||||
verbose_name=u'Пользовательская страница'
|
||||
verbose_name_plural =u'Пользовательские страницы'
|
||||
verbose_name=_("Пользовательская страница")
|
||||
verbose_name_plural =_("Пользовательские страницы")
|
||||
# unique_together = ('url', 'region')
|
||||
# managed=True
|
||||
# app_label = u'ArticlesApp'
|
||||
@@ -31,8 +31,8 @@ class UserPageModel(BaseModelViewPage):
|
||||
|
||||
class ArticleModel(BaseModelViewPage):
|
||||
# pub_DT = models.DateTimeField(verbose_name=u'Дата и время публикации', auto_created=True)
|
||||
text = RichTextUploadingField(verbose_name=u'Текст')
|
||||
text = RichTextUploadingField(verbose_name=_("Текст"))
|
||||
|
||||
class Meta:
|
||||
verbose_name='Статья'
|
||||
verbose_name_plural ='Статьи'
|
||||
verbose_name=_("Статья")
|
||||
verbose_name_plural =_("Статьи")
|
||||
1
ArticlesApp/templatetags/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
__author__ = 'SDE'
|
||||
48
ArticlesApp/templatetags/arts_tags_extra.py
Normal file
@@ -0,0 +1,48 @@
|
||||
__author__ = 'SDE'
|
||||
|
||||
from django import template
|
||||
from django.template.defaultfilters import stringfilter
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
# @register.filter('get_side_art')
|
||||
@register.simple_tag
|
||||
def get_side_art(last_el, counter, els_on_page):
|
||||
cur_el = last_el - els_on_page + counter
|
||||
if els_on_page < 4:
|
||||
first_left_el = els_on_page + 1
|
||||
else:
|
||||
first_left_el = 4
|
||||
if (cur_el - first_left_el) % 2:
|
||||
return 'even'
|
||||
else:
|
||||
return 'odd'
|
||||
|
||||
# @register.filter()
|
||||
# def get_numbers_list(from_el, to_el):
|
||||
# res = range(from_el, to_el+1)
|
||||
# return res
|
||||
#
|
||||
#
|
||||
# def val_type(value):
|
||||
# res = type(value)
|
||||
# return res.__name__
|
||||
# register.filter('val_type', val_type)
|
||||
#
|
||||
# @register.filter()
|
||||
# def get_cols_table_data_for_row_when_cols3(value, row):
|
||||
# el_count = 3
|
||||
# from_el = (row-1) * el_count
|
||||
# to_el = row * el_count
|
||||
# part = list(value)[from_el:to_el]
|
||||
# return part
|
||||
# # register.filter('val_type', val_type)
|
||||
#
|
||||
#
|
||||
# @register.filter
|
||||
# @stringfilter
|
||||
# def correct_for_tables(value):
|
||||
# if value in ['None', '0.0']:
|
||||
# return '-'
|
||||
# return value
|
||||
@@ -7,6 +7,7 @@ from django.http import Http404, HttpResponse
|
||||
from django.template import loader
|
||||
from .funcs import *
|
||||
from GeneralApp.funcs import get_inter_http_respose
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
# from django.contrib.auth.decorators import login_required
|
||||
# from BaseModels.search_optimization.ld_json.ld_article_news import get_ld_article_news
|
||||
@@ -17,7 +18,7 @@ from GeneralApp.funcs import get_inter_http_respose
|
||||
def get_flat_pages_links_Dict(site):
|
||||
|
||||
flat_pages_links = UserPageModel.objects.filter(
|
||||
url__in=('about-truenergy', 'for-partners', 'contacts'),
|
||||
url__in=('for-partners', 'contacts'),
|
||||
sites=site
|
||||
).values_list('url', flat=True)
|
||||
|
||||
@@ -27,20 +28,23 @@ def get_flat_pages_links_Dict(site):
|
||||
|
||||
def get_article_breadcrumbs(request, art):
|
||||
# print('get_article_breadcrumbs')
|
||||
articles_add_count = 1
|
||||
articles_add_count = 3
|
||||
# half_count = articlesCountInBlock / 2
|
||||
|
||||
arts_top = ArticleModel.objects.filter(enable=True, createDT__gt=art.createDT).order_by(
|
||||
'createDT')[:articles_add_count]
|
||||
arts_down = ArticleModel.objects.filter(enable=True, createDT__lt=art.createDT).order_by(
|
||||
'-createDT')[:articles_add_count]
|
||||
# arts_top = ArticleModel.objects.filter(enable=True, createDT__gt=art.createDT).order_by(
|
||||
# 'createDT')[:articles_add_count]
|
||||
# arts_down = ArticleModel.objects.filter(enable=True, createDT__lt=art.createDT).order_by(
|
||||
# '-createDT')[:articles_add_count]
|
||||
# if len(artListDown)<half_count:
|
||||
# art_List = ArticleModel.objects.filter(enable=True, article_DT__gte=art.article_DT).order_by(
|
||||
# 'article_DT')[:art.articlesCountInBlock-len(artListDown)]
|
||||
|
||||
breadcrumbs_arts = ArticleModel.objects.exclude(id=art.id).order_by('?')[:3]
|
||||
|
||||
Dict = {
|
||||
'arts_top': arts_top,
|
||||
'arts_down': arts_down
|
||||
'breadcrumbs_arts': breadcrumbs_arts
|
||||
# 'arts_top': arts_top,
|
||||
# 'arts_down': arts_down
|
||||
}
|
||||
return Dict
|
||||
|
||||
@@ -79,6 +83,13 @@ def ArticlesPageView(request, year=None):
|
||||
|
||||
|
||||
Dict = get_articles(art_kwargs=kwargs)
|
||||
Dict.update({
|
||||
'page': {
|
||||
'title': _('Страница списка новостей'),
|
||||
'description': _('Все новости сайта tripwb.com'),
|
||||
'keywords': _('Все новости сайта tripwb.com'),
|
||||
}
|
||||
})
|
||||
|
||||
t = loader.get_template('pages/p_articles.html')
|
||||
return get_inter_http_respose(t, Dict, request)
|
||||
@@ -105,7 +116,7 @@ def UserPageView(request, page_url):
|
||||
# print('article_breadcrumbs',article_breadcrumbs)
|
||||
|
||||
Dict = {
|
||||
'art' : art,
|
||||
'page' : art,
|
||||
'user_page' : True,
|
||||
# 'service' : service,
|
||||
# 'article_breadcrumbs' : article_breadcrumbs
|
||||
@@ -136,7 +147,7 @@ def ArticlesOnePageView(request, art_url):
|
||||
# print('article_breadcrumbs',article_breadcrumbs)
|
||||
|
||||
Dict = {
|
||||
'art' : art,
|
||||
'page' : art,
|
||||
}
|
||||
|
||||
Dict.update(get_article_breadcrumbs(request, art))
|
||||
|
||||
@@ -39,16 +39,17 @@ class Admin_ProfileInline(admin.StackedInline):
|
||||
(None, {
|
||||
'classes': ['wide'],
|
||||
'fields': (
|
||||
('account_type',),
|
||||
# ('account_type',),
|
||||
('enable',),
|
||||
('phone',),
|
||||
('country', 'city'),
|
||||
('mailing_on', ),
|
||||
('authMailCode',),
|
||||
('birthdate'),
|
||||
'comment', 'creator'
|
||||
)
|
||||
}),
|
||||
('Дополнительно', {
|
||||
(_('Дополнительно'), {
|
||||
'classes': ['wide'],
|
||||
'fields': (
|
||||
('json_data',)
|
||||
@@ -71,6 +72,10 @@ class Admin_ProfileInline(admin.StackedInline):
|
||||
|
||||
class Admin_User(UserAdmin):
|
||||
|
||||
def mailing_on(self, obj):
|
||||
return obj.user_profile.mailing_on
|
||||
mailing_on.boolean = True
|
||||
|
||||
fieldsets = (
|
||||
(None, {
|
||||
'classes': ['wide'],
|
||||
@@ -91,61 +96,63 @@ class Admin_User(UserAdmin):
|
||||
|
||||
save_on_top = True
|
||||
|
||||
list_display = ['id', 'last_name', 'first_name', 'email', 'is_staff',
|
||||
list_display = ['id', 'last_name', 'first_name', 'mailing_on', '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']
|
||||
|
||||
list_filter = ['user_profile__mailing_on', 'is_staff', 'is_active']
|
||||
|
||||
inlines = (Admin_ProfileInline,)
|
||||
# actions = ['del_all_temp_users', ]
|
||||
|
||||
ordering = ['is_staff', 'last_name', 'first_name']
|
||||
ordering = ['is_staff', '-id', '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': (
|
||||
('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)
|
||||
# class Admin_UserProfile(Admin_BaseIconModel):
|
||||
#
|
||||
# fieldsets = (
|
||||
# (None, {
|
||||
# 'classes': ['wide'],
|
||||
# 'fields': (
|
||||
# 'user', 'enable',
|
||||
# ('account_type',),
|
||||
# ('phone',),
|
||||
# ('country', 'city'),
|
||||
# ('authMailCode',),
|
||||
# ('birthdate'),
|
||||
# 'creator'
|
||||
# )
|
||||
# }),
|
||||
# ('1С', {
|
||||
# 'classes': ['wide'],
|
||||
# 'fields': (
|
||||
# ('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)
|
||||
|
||||
@@ -29,22 +29,61 @@ class RegistrationForm(forms.Form):
|
||||
tel = forms.CharField()
|
||||
agreement = forms.BooleanField(initial=False, required=True)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
required_password = True
|
||||
required_agreement = True
|
||||
required_email = True
|
||||
create_new_account = True
|
||||
if 'not_required_password' in kwargs.keys() and kwargs['not_required_password']:
|
||||
required_password = False
|
||||
del kwargs['not_required_password']
|
||||
if 'not_required_agreement' in kwargs.keys() and kwargs['not_required_agreement']:
|
||||
required_agreement = False
|
||||
del kwargs['not_required_agreement']
|
||||
if 'not_required_email' in kwargs.keys() and kwargs['not_required_email']:
|
||||
required_email = False
|
||||
del kwargs['not_required_email']
|
||||
if 'create_new_account' in kwargs.keys() and not kwargs['create_new_account']:
|
||||
create_new_account = False
|
||||
del kwargs['create_new_account']
|
||||
|
||||
super(RegistrationForm, self).__init__(*args, **kwargs)
|
||||
|
||||
self.fields['password'].required = required_password
|
||||
self.fields['confirm_password'].required = required_password
|
||||
|
||||
self.fields['agreement'].required = required_agreement
|
||||
|
||||
self.fields['email'].required = required_email
|
||||
|
||||
self.create_new_account = create_new_account
|
||||
|
||||
def clean(self):
|
||||
pass
|
||||
# cleaned_data = super().clean()
|
||||
# for item in self.changed_data:
|
||||
# if item in self.data:
|
||||
#
|
||||
#
|
||||
# cc_myself = cleaned_data.get("cc_myself")
|
||||
# subject = cleaned_data.get("subject")
|
||||
#
|
||||
# if cc_myself and subject:
|
||||
# # Only do something if both fields are valid so far.
|
||||
# if "help" not in subject:
|
||||
# raise ValidationError(
|
||||
# "Did not send for 'help' in the subject despite " "CC'ing yourself."
|
||||
# )
|
||||
cleaned_data = super().clean()
|
||||
# i = 0
|
||||
# names = list(cleaned_data.keys())
|
||||
# while i < len(names):
|
||||
# if not cleaned_data[names[i]]:
|
||||
# if self.fields[names[i]].required:
|
||||
# self.add_error(names[i], _('Обязательное поле'))
|
||||
# i += 1
|
||||
|
||||
if 'tel' in cleaned_data and 'tel' in cleaned_data:
|
||||
from BaseModels.validators.form_field_validators import get_phone_valid_error
|
||||
error = get_phone_valid_error(cleaned_data["tel"])
|
||||
if error:
|
||||
self.add_error('tel', error)
|
||||
|
||||
if cleaned_data and 'confirm_password' in cleaned_data and 'password' in cleaned_data:
|
||||
if cleaned_data['confirm_password'] != cleaned_data['password']:
|
||||
self.add_error("password", _('Пароль и подтверждение пароля не совпадают'))
|
||||
self.add_error("confirm_password", _('Пароль и подтверждение пароля не совпадают'))
|
||||
|
||||
if self.create_new_account and cleaned_data and 'email' in cleaned_data:
|
||||
users = User.objects.filter(email=cleaned_data['email'])
|
||||
if users:
|
||||
self.add_error('email', _("Пользователь с указанным email уже существует"))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,8 +1,25 @@
|
||||
from django.template.loader import render_to_string
|
||||
|
||||
|
||||
def get_user_timezone_Dict(user, request=None):
|
||||
tz = None
|
||||
if request:
|
||||
tz = request.COOKIES.get("user_tz")
|
||||
if not tz and user.is_authenticated:
|
||||
tz = user.user_profile.get_timezone()
|
||||
|
||||
if not tz:
|
||||
from django.conf import settings
|
||||
tz = settings.TIME_ZONE
|
||||
|
||||
return {'user_tz': tz}
|
||||
|
||||
def get_dashboard_page_content_html(request):
|
||||
|
||||
from ChatServiceApp.funcs import get_unanswered_msgs_count_for_user
|
||||
|
||||
Dict = {
|
||||
'unanswered_msgs_count': get_unanswered_msgs_count_for_user(request.user)
|
||||
}
|
||||
|
||||
html = render_to_string('blocks/profile/b_profile_first_page.html', Dict, request=request)
|
||||
@@ -15,10 +32,10 @@ def get_profile_page_content_html(request, page_name, data):
|
||||
return get_chat_page_content_html(request, data)
|
||||
elif page_name == 'create_route_for_customer':
|
||||
from RoutesApp.funcs import get_profile_new_route_page_html
|
||||
return get_profile_new_route_page_html(request, {})
|
||||
return get_profile_new_route_page_html(request, {'owner_type': 'customer'})
|
||||
elif page_name == 'create_route_for_mover':
|
||||
from RoutesApp.funcs import get_profile_new_route_page_html
|
||||
return get_profile_new_route_page_html(request, {})
|
||||
return get_profile_new_route_page_html(request, {'owner_type': 'mover'})
|
||||
elif page_name == 'my_routes':
|
||||
from RoutesApp.funcs import get_profile_my_routes_page_content_html
|
||||
return get_profile_my_routes_page_content_html(request)
|
||||
@@ -73,5 +90,7 @@ def get_profile_support_page_content_html(request, data=None):
|
||||
}
|
||||
tpl_name = 'blocks/profile/b_support_tickets.html'
|
||||
|
||||
Dict.update(get_user_timezone_Dict(request.user, request=request))
|
||||
|
||||
html = render_to_string(tpl_name, Dict, request=request)
|
||||
return html
|
||||
@@ -27,4 +27,9 @@ urlpatterns = [
|
||||
path('change_profile/', change_profile_ajax, name='change_profile_ajax'),
|
||||
path('change_profile_confirm/', change_profile_confirm_ajax, name='change_profile_confirm_ajax'),
|
||||
path('change_avatar_confirm/', change_avatar_confirm_ajax, name='change_avatar_confirm_ajax'),
|
||||
|
||||
path('send_message/', send_message_ajax, name='send_message_ajax'),
|
||||
|
||||
path('mailing_subscribe/', mailing_subscribe_ajax, name='mailing_subscribe_ajax')
|
||||
|
||||
]
|
||||
@@ -16,6 +16,8 @@ from django.core.exceptions import ValidationError
|
||||
import json
|
||||
from django.core.files import File
|
||||
import base64
|
||||
from django.core.validators import validate_email
|
||||
from django.urls import reverse
|
||||
|
||||
|
||||
# @login_required(login_url='/profile/login/')
|
||||
@@ -29,6 +31,182 @@ import base64
|
||||
# html = render_to_string('blocks/profile/b_subscribe.html', Dict, request=request)
|
||||
# return JsonResponse({'html': html}, status=200)
|
||||
|
||||
|
||||
def mailing_subscribe_ajax(request):
|
||||
if request.method != 'POST':
|
||||
raise Http404
|
||||
|
||||
try:
|
||||
|
||||
email = request.POST['email']
|
||||
user = None
|
||||
if request.user and request.user.is_authenticated:
|
||||
user = request.user
|
||||
user.user_profile.mailing_on = True
|
||||
user.user_profile.save(update_fields=['mailing_on'])
|
||||
|
||||
return JsonResponse({
|
||||
'status': 'sended',
|
||||
'del_form': True,
|
||||
'html': _('Подписка на рассылку для адреса ') + user.email + _(' одобрена')
|
||||
})
|
||||
|
||||
if not user:
|
||||
try:
|
||||
user = User.objects.get(email=email)
|
||||
except User.DoesNotExist:
|
||||
user = None
|
||||
|
||||
if user:
|
||||
redirect_url = f"{reverse('login_profile')}?mailingSubscribeRequired=true"
|
||||
else:
|
||||
redirect_url = f"{reverse('registration_page')}?mailingSubscribeRequired=true"
|
||||
|
||||
return JsonResponse({
|
||||
'status': 'sended',
|
||||
'redirect_url': redirect_url,
|
||||
'email': email
|
||||
})
|
||||
|
||||
|
||||
except Exception as e:
|
||||
return JsonResponse({
|
||||
'status': 'error',
|
||||
'html': str(e)
|
||||
}, status=400)
|
||||
|
||||
|
||||
def send_message_ajax(request):
|
||||
if request.method != 'POST':
|
||||
raise Http404
|
||||
|
||||
try:
|
||||
|
||||
data = request.POST
|
||||
if not data and request.body:
|
||||
data = request.body
|
||||
|
||||
from GeneralApp.funcs_options import get_options_by_opt_types, get_mail_send_options
|
||||
sets = get_options_by_opt_types(['domain', 'project_name'], only_vals=True)
|
||||
|
||||
request_type = None
|
||||
subject = _('Получен запрос')
|
||||
if 'form_name' in data:
|
||||
if data['form_name'] == 'msg_from_advertisement':
|
||||
subject = _('Получен запрос на рекламу')
|
||||
request_type = _('запрос на рекламу')
|
||||
if data['form_name'] == 'msg_from_partners':
|
||||
subject = _('Получен запрос на подключение к партнерской сети')
|
||||
request_type = _('запрос на партнерство')
|
||||
if data['form_name'] == 'msg_from_customer_service':
|
||||
subject = _('Получен запрос в службу техподдержки')
|
||||
request_type = _('запрос в техподдержку')
|
||||
if data['form_name'] == 'msg_from_contacts':
|
||||
subject = _('Получен запрос со страницы контактов')
|
||||
request_type = _('запрос со страницы контактов')
|
||||
if data['form_name'] == 'msg_from_about_service':
|
||||
subject = _('Получен запрос со страницы О сервисе')
|
||||
request_type = _('запрос со страницы о сервисе')
|
||||
if data['form_name'] == 'msg_from_footer':
|
||||
subject = _('Получен запрос на рассылку')
|
||||
request_type = _('запрос на рассылку')
|
||||
|
||||
request_type_str = ''
|
||||
name_str = ''
|
||||
phone_str = ''
|
||||
email_str = ''
|
||||
msg_str = ''
|
||||
form_type = 'one_field'
|
||||
errors = {}
|
||||
|
||||
for name, val in data.items():
|
||||
if not val:
|
||||
errors.update({name: _('Обязательное поле')})
|
||||
|
||||
if name == 'form_name':
|
||||
request_type_str = f'<b>{_("Тип запроса")}:</b> {request_type}<br>'
|
||||
|
||||
if name == 'name':
|
||||
name_str = f'<b>{_("Имя")}:</b> {data["name"]}<br>'
|
||||
if form_type == 'one_field':
|
||||
form_type = 'two_fields'
|
||||
|
||||
if name =='phone':
|
||||
from BaseModels.validators.form_field_validators import get_phone_valid_error
|
||||
error = get_phone_valid_error(data["phone"])
|
||||
if error:
|
||||
errors.update({name: _(error)})
|
||||
phone_str = f'<b>{_("Телефон")}:</b> {data["phone"]}<br>'
|
||||
|
||||
if name =='email':
|
||||
try:
|
||||
error = validate_email(data["email"])
|
||||
except ValidationError as e:
|
||||
error = e.message
|
||||
if error:
|
||||
errors.update({name: _(error)})
|
||||
email_str = f'<b>{_("email")}:</b> {data["email"]}<br>'
|
||||
|
||||
if name =='text_msg':
|
||||
msg_str = (f'<b>{_("Сообщение")}:</b><br>'
|
||||
f'<div style="margin-left: 40px; line-height: 20px;">{data["text_msg"]}</div><br>')
|
||||
form_type = 'full'
|
||||
|
||||
if errors:
|
||||
Dict = {
|
||||
'form': data.dict()
|
||||
}
|
||||
Dict['form'].update({
|
||||
'errors': errors
|
||||
})
|
||||
|
||||
tpl = 'forms/f_one_field_form.html'
|
||||
if form_type == 'full':
|
||||
tpl = 'forms/f_feedback_form.html'
|
||||
elif form_type == 'two_fields':
|
||||
tpl = 'forms/f_commercial_offer.html'
|
||||
|
||||
html = render_to_string(tpl, Dict, request)
|
||||
return JsonResponse({'html': html}, status=400)
|
||||
|
||||
Dict = {
|
||||
'logo': f'{sets["domain"]}/static/img/svg/LogoMobile.svg',
|
||||
'project_name': sets['project_name'],
|
||||
'message_title': subject,
|
||||
'message_text': f'<p><b>{_("ДАННЫЕ ЗАПРОСА")}</b></p>'
|
||||
f'<p style="padding-left: 20px; line-height: 30px;">'
|
||||
f'{request_type_str}'
|
||||
f'{name_str}'
|
||||
f'{phone_str}'
|
||||
f'{email_str}'
|
||||
f'{msg_str}'
|
||||
f'</p>'
|
||||
}
|
||||
|
||||
html = render_to_string('mail/m_request_offer.html', Dict, request)
|
||||
from BaseModels.mailSender import admin_send_mail_by_SMTPlib
|
||||
mail_sets = get_mail_send_options()
|
||||
to = [mail_sets['sender_email'], 'web@syncsystems.net']
|
||||
res = admin_send_mail_by_SMTPlib(
|
||||
mail_sets,
|
||||
subject=subject,
|
||||
from_email=mail_sets['sender_email'], to=to,
|
||||
html_content=html
|
||||
)
|
||||
|
||||
html = render_to_string('widgets/w_msg_send_success.html', Dict, request)
|
||||
|
||||
return JsonResponse({
|
||||
'status': 'sended',
|
||||
'html': html
|
||||
})
|
||||
except Exception as e:
|
||||
return JsonResponse({
|
||||
'status': 'error',
|
||||
'html': str(e)
|
||||
}, status=400)
|
||||
|
||||
|
||||
@login_required(login_url='/profile/login/')
|
||||
def chats_ajax(request):
|
||||
if request.method != 'POST':
|
||||
@@ -54,6 +232,7 @@ def chats_ajax(request):
|
||||
'receivers': receivers,
|
||||
# 'messages': cur_chat_msgs
|
||||
}
|
||||
Dict.update(get_user_timezone_Dict(request.user, request=request))
|
||||
|
||||
html = render_to_string('blocks/profile/b_chats.html', Dict, request=request)
|
||||
return JsonResponse({'html': html}, status=200)
|
||||
@@ -71,6 +250,7 @@ def support_tickets_ajax(request):
|
||||
@login_required(login_url='/profile/login/')
|
||||
def change_avatar_confirm_ajax(request):
|
||||
from django.core.files.base import ContentFile
|
||||
from django.core.exceptions import RequestDataTooBig
|
||||
|
||||
if request.method != 'POST':
|
||||
raise Http404
|
||||
@@ -83,11 +263,15 @@ def change_avatar_confirm_ajax(request):
|
||||
file = ContentFile(content)
|
||||
request.user.user_profile.avatar.save(file_data['file_name'], file)
|
||||
request.user.user_profile.save(update_fields=['avatar'])
|
||||
except RequestDataTooBig:
|
||||
msg = _('Слишком большой размер файла. Размер файла не должен быть больше 3МБ')
|
||||
print(msg)
|
||||
return JsonResponse({'error': msg}, status=400)
|
||||
|
||||
except Exception as e:
|
||||
msg = f'change_avatar_confirm_ajax Error = {str(e)}'
|
||||
print(msg)
|
||||
JsonResponse({'error': msg})
|
||||
return JsonResponse({'error': msg}, status=400)
|
||||
|
||||
return JsonResponse({'url': request.user.user_profile.avatar.url})
|
||||
|
||||
@@ -102,7 +286,19 @@ def change_profile_confirm_ajax(request):
|
||||
data = json.loads(request.body)
|
||||
|
||||
from .forms import RegistrationForm
|
||||
form = RegistrationForm(data)
|
||||
kwargs = {
|
||||
'not_required_password': True,
|
||||
'not_required_agreement': True,
|
||||
'not_required_email': True,
|
||||
'create_new_account': False,
|
||||
}
|
||||
form = RegistrationForm(data, **kwargs)
|
||||
if not form.is_valid():
|
||||
form.initial = data
|
||||
Dict = {'profileForm': form}
|
||||
|
||||
html = render_to_string('blocks/profile/b_profile.html', Dict, request=request)
|
||||
return JsonResponse({'html': html}, status=400)
|
||||
|
||||
data_for_save = {}
|
||||
users = User.objects.filter(id=request.user.id)
|
||||
@@ -128,8 +324,8 @@ def change_profile_confirm_ajax(request):
|
||||
if password and confirm_password:
|
||||
if password != confirm_password:
|
||||
errors = {
|
||||
'password': 'Не совпадают пароли',
|
||||
'confirm_password': 'Не совпадают пароли',
|
||||
'password': _("Не совпадают пароли"),
|
||||
'confirm_password': _("Не совпадают пароли"),
|
||||
}
|
||||
raise ValidationError(errors)
|
||||
|
||||
@@ -215,10 +411,13 @@ def login_ajax(request):
|
||||
user = authenticate(username=form.data['username'], password=form.data['password'])
|
||||
if user is not None:
|
||||
auth.login(request, user)
|
||||
if 'mailingSubscribeRequired' in data and data['mailingSubscribeRequired'] == 'true':
|
||||
user.user_profile.mailing_on = True
|
||||
user.user_profile.save(update_fields=['mailing_on'])
|
||||
else:
|
||||
errors_Dict = {
|
||||
'errors': {
|
||||
'all__': f'неверный логин и\или пароль'
|
||||
'all__': _("неверный логин и\или пароль")
|
||||
}
|
||||
}
|
||||
Dict = {'form': errors_Dict}
|
||||
@@ -236,7 +435,7 @@ def login_ajax(request):
|
||||
|
||||
errors_Dict = {
|
||||
'errors': {
|
||||
'all__': f'ошибка в запросе = {str(e)}'
|
||||
'all__': f'{_("ошибка в запросе")} = {str(e)}'
|
||||
}
|
||||
}
|
||||
Dict = {'form': errors_Dict}
|
||||
@@ -244,6 +443,42 @@ def login_ajax(request):
|
||||
return JsonResponse({'html': html}, status=400)
|
||||
|
||||
|
||||
|
||||
|
||||
def send_registration_mail(data_Dict, user):
|
||||
|
||||
try:
|
||||
|
||||
from GeneralApp.funcs_options import get_options_by_opt_types, get_mail_send_options
|
||||
sets = get_options_by_opt_types(['domain', 'project_name'], only_vals=True)
|
||||
|
||||
subject = _('Добро пожаловать в Trip With Bonus!')
|
||||
|
||||
Dict = {
|
||||
'logo': f'{sets["domain"]}/static/img/svg/LogoMobile.svg',
|
||||
'project_name': sets['project_name'],
|
||||
'message_title': subject,
|
||||
}
|
||||
Dict.update(data_Dict)
|
||||
|
||||
html = render_to_string('mail/m_registration.html', Dict)
|
||||
from BaseModels.mailSender import admin_send_mail_by_SMTPlib
|
||||
mail_sets = get_mail_send_options()
|
||||
to = [user.email, 'web@syncsystems.net', 'sa@a3-global.com', 'sysadmin.hax@gmail.com']
|
||||
res = admin_send_mail_by_SMTPlib(
|
||||
mail_sets,
|
||||
subject=subject,
|
||||
from_email=mail_sets['sender_email'], to=to,
|
||||
html_content=html
|
||||
)
|
||||
|
||||
return res
|
||||
except Exception as e:
|
||||
print(f'send_registration_mail Error = {str(e)}')
|
||||
return None
|
||||
|
||||
|
||||
|
||||
def registration_ajax(request):
|
||||
if request.method != 'POST':
|
||||
raise Http404
|
||||
@@ -259,17 +494,20 @@ def registration_ajax(request):
|
||||
html = render_to_string('forms/f_registration.html', Dict, request=request)
|
||||
return JsonResponse({'html': html}, status=400)
|
||||
|
||||
users = User.objects.filter(email=form.data['email'])
|
||||
if users:
|
||||
form.errors['email'] = 'Пользователь с указанным email уже существует'
|
||||
Dict = {'form': form}
|
||||
html = render_to_string('forms/f_registration.html', Dict, request=request)
|
||||
return JsonResponse({'html': html}, status=400)
|
||||
# users = User.objects.filter(email=form.data['email'])
|
||||
# if users:
|
||||
# form.errors['email'] = _("Пользователь с указанным email уже существует")
|
||||
# Dict = {'form': form}
|
||||
# html = render_to_string('forms/f_registration.html', Dict, request=request)
|
||||
# return JsonResponse({'html': html}, status=400)
|
||||
|
||||
user = User.objects.create_user(username=form.data['email'], email=form.data['email'], password=form.data['password'])
|
||||
# user = auth.authenticate(username=new_user_Dict['name'], password=new_user_Dict['pass'])
|
||||
if user:
|
||||
auth.login(request, user)
|
||||
auth.login(request, user, backend='django.contrib.auth.backends.ModelBackend')
|
||||
|
||||
if 'mailingSubscribeRequired' in data and data['mailingSubscribeRequired'] == 'true':
|
||||
user.user_profile.mailing_on = True
|
||||
|
||||
user.last_name = form.data['lastname']
|
||||
user.first_name = form.data['firstname']
|
||||
@@ -277,6 +515,12 @@ def registration_ajax(request):
|
||||
user.user_profile.phone = form.data['tel']
|
||||
user.user_profile.save()
|
||||
|
||||
mail_Dict = {
|
||||
'user': user,
|
||||
'pass': form.data['password']
|
||||
}
|
||||
res = send_registration_mail(mail_Dict, user)
|
||||
|
||||
res_Dict = {
|
||||
'redirect_url': reverse('profile_page', args=['dashboard'])
|
||||
}
|
||||
@@ -287,7 +531,7 @@ def registration_ajax(request):
|
||||
|
||||
errors_Dict = {
|
||||
'errors': {
|
||||
'__all__': f'ошибка в запросе = {str(e)}'
|
||||
'__all__': f'{_("ошибка в запросе")} = {str(e)}'
|
||||
}
|
||||
}
|
||||
Dict = {'form': errors_Dict}
|
||||
|
||||
@@ -31,10 +31,12 @@ class ResponseInterceptionMiddleware:
|
||||
|
||||
def __call__(self, request):
|
||||
response = self.get_response(request)
|
||||
for_save_to_session = None
|
||||
|
||||
try:
|
||||
if type(response) == JsonResponse:
|
||||
for_save_to_session = request.user.user_profile.pop_node_by_name('for_save_to_session')
|
||||
if request.user and not request.user.is_anonymous and request.user.user_profile:
|
||||
for_save_to_session = request.user.user_profile.pop_node_by_name('for_save_to_session')
|
||||
if for_save_to_session:
|
||||
data = json.loads(response.content)
|
||||
data.update(for_save_to_session)
|
||||
|
||||
18
AuthApp/migrations/0005_userprofile_mailing_on.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.2 on 2024-02-01 17:17
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('AuthApp', '0004_alter_userprofile_account_type'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='userprofile',
|
||||
name='mailing_on',
|
||||
field=models.BooleanField(default=False, verbose_name='Рассылка'),
|
||||
),
|
||||
]
|
||||
@@ -51,6 +51,14 @@ class UserProfile(BaseModel):
|
||||
on_delete=models.SET_NULL
|
||||
)
|
||||
|
||||
mailing_on = models.BooleanField(default=False, verbose_name=_('Рассылка'))
|
||||
|
||||
def get_timezone(self):
|
||||
tz = None
|
||||
if 'user_timezone' in self.json_data:
|
||||
tz = self.json_data['user_timezone']
|
||||
return tz
|
||||
|
||||
def save_user_alerts_to_session(self, request):
|
||||
for_save_to_session = self.get_node_by_name('for_save_to_session')
|
||||
if for_save_to_session:
|
||||
@@ -74,8 +82,23 @@ class UserProfile(BaseModel):
|
||||
|
||||
|
||||
def create_user_profile(sender, instance, created, **kwargs):
|
||||
user_profile = None
|
||||
if created:
|
||||
UserProfile.objects.create(user=instance)
|
||||
user_profile = UserProfile.objects.create(user=instance)
|
||||
|
||||
# if user_profile and not user_profile.avatar:
|
||||
# from allauth.socialaccount.models import SocialAccount
|
||||
# # try:
|
||||
# social_accounts = SocialAccount.objects.filter(user=instance)
|
||||
# if social_accounts:
|
||||
# for social_account in social_accounts:
|
||||
# if 'picture' in social_account.account.extra_data and social_account.account.extra_data['picture']:
|
||||
# with open(social_account.account.extra_data['picture'], 'rb') as fd:
|
||||
# user_profile.avatar.save(f'avatar_{instance.id}.jpeg', fd.read(), True)
|
||||
#
|
||||
# # except Exception as e:
|
||||
# # msg = f'post_save create_user_profile Error = {str(e)}'
|
||||
# # print(msg)
|
||||
|
||||
|
||||
post_save.connect(create_user_profile, sender=User, dispatch_uid='post_save_connect')
|
||||
@@ -85,6 +108,7 @@ def preSaveUser(sender, instance, **kwargs):
|
||||
if not instance.email:
|
||||
instance.email = str(instance.username).lower()
|
||||
|
||||
|
||||
try:
|
||||
instance.user_profile.modifiedDT = datetime.now()
|
||||
except:
|
||||
|
||||
@@ -21,6 +21,8 @@ urlpatterns = [
|
||||
path('login/', login_View, name='login_profile'),
|
||||
path('logout/', logout_View, name='logout_profile'),
|
||||
|
||||
path('account/signup/', login_View, name="custom_singup" ),
|
||||
|
||||
|
||||
# ajax ----------------
|
||||
# url(r'^login$', user_login_View_ajax, name='user_login_View_ajax'),
|
||||
|
||||
@@ -19,6 +19,11 @@ def registration_View(request):
|
||||
|
||||
Dict = {}
|
||||
|
||||
if request.GET and 'mailingSubscribeRequired' in request.GET and request.GET['mailingSubscribeRequired'] == 'true':
|
||||
request.session['mailingSubscribeRequired'] = 'true'
|
||||
|
||||
# if request.p
|
||||
|
||||
t = loader.get_template('pages/profile/p_registration.html')
|
||||
return get_inter_http_respose(t, Dict, request)
|
||||
# return HttpResponse(t.render(Dict, request))
|
||||
@@ -44,6 +49,26 @@ def profile_page_View(request, page_name, id=None):
|
||||
'page_type': 'profile'
|
||||
}
|
||||
|
||||
if request.session and 'mailingSubscribeRequired' in request.session and request.session['mailingSubscribeRequired'] == 'true':
|
||||
request.user.user_profile.mailing_on = True
|
||||
request.user.user_profile.save(update_fields=['mailing_on'])
|
||||
del request.session['mailingSubscribeRequired']
|
||||
|
||||
title = f"{_('Личный кабинет пользователя')} {request.user.first_name} {request.user.last_name}"
|
||||
|
||||
Dict.update({
|
||||
'page': {
|
||||
'title': title,
|
||||
'description': title,
|
||||
'keywords': title,
|
||||
}
|
||||
})
|
||||
|
||||
# if request.GET and 'mobile' in request.GET and request.GET['mobile'] == 'true':
|
||||
# Dict.update({
|
||||
# 'mobile': True
|
||||
# })
|
||||
|
||||
t = loader.get_template('pages/profile/p_user_profile.html')
|
||||
return get_inter_http_respose(t, Dict, request)
|
||||
# return HttpResponse(t.render(Dict, request))
|
||||
@@ -102,7 +127,14 @@ def logout_View(request):
|
||||
|
||||
def login_View(request):
|
||||
|
||||
Dict = {}
|
||||
from allauth.socialaccount.models import SocialApp
|
||||
auth_google_allow = SocialApp.objects.filter(provider='google')
|
||||
Dict = {
|
||||
'auth_google_allow': auth_google_allow
|
||||
}
|
||||
|
||||
if request.GET and 'mailingSubscribeRequired' in request.GET and request.GET['mailingSubscribeRequired'] == 'true':
|
||||
request.session['mailingSubscribeRequired'] = 'true'
|
||||
|
||||
t = loader.get_template('pages/profile/p_login.html')
|
||||
return get_inter_http_respose(t, Dict, request)
|
||||
@@ -153,7 +185,7 @@ def create_personal_user(data, creator):
|
||||
}
|
||||
except Exception as e:
|
||||
return {
|
||||
'error': 'Ошибка добавление нового пользователя = {0}'.format(str(e)),
|
||||
'error': f'{_("Ошибка добавление нового пользователя")} = {str(e)}',
|
||||
}
|
||||
|
||||
|
||||
@@ -190,7 +222,7 @@ 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'
|
||||
mail = user_id+u'@domain'
|
||||
user = User.objects.create_user(mail, mail,user_id)
|
||||
user.first_name = _(u'незарег. пользователь')
|
||||
user.last_name = u''
|
||||
|
||||
70
BaseModels/PIL/pillow_backend.py
Normal file
@@ -0,0 +1,70 @@
|
||||
import os
|
||||
from io import BytesIO
|
||||
|
||||
from django.conf import settings
|
||||
from django.utils.functional import cached_property
|
||||
from PIL import Image
|
||||
|
||||
from ckeditor_uploader import utils
|
||||
|
||||
|
||||
THUMBNAIL_SIZE = getattr(settings, "CKEDITOR_THUMBNAIL_SIZE", (75, 75))
|
||||
|
||||
|
||||
class PillowBackend:
|
||||
def __init__(self, storage_engine, file_object):
|
||||
self.file_object = file_object
|
||||
self.storage_engine = storage_engine
|
||||
|
||||
@cached_property
|
||||
def is_image(self):
|
||||
try:
|
||||
Image.open(
|
||||
BytesIO(self.file_object.read())
|
||||
).verify() # verify closes the file
|
||||
return True
|
||||
except OSError:
|
||||
return False
|
||||
finally:
|
||||
self.file_object.seek(0)
|
||||
|
||||
def _compress_image(self, image):
|
||||
quality = getattr(settings, "CKEDITOR_IMAGE_QUALITY", 75)
|
||||
image = image.resize(image.size, Image.ANTIALIAS).convert("RGB")
|
||||
image_tmp = BytesIO()
|
||||
image.save(image_tmp, format="JPEG", quality=quality, optimize=True)
|
||||
return image_tmp
|
||||
|
||||
def save_as(self, filepath):
|
||||
if not self.is_image:
|
||||
saved_path = self.storage_engine.save(filepath, self.file_object)
|
||||
return saved_path
|
||||
|
||||
image = Image.open(self.file_object)
|
||||
|
||||
should_compress = getattr(settings, "CKEDITOR_FORCE_JPEG_COMPRESSION", False)
|
||||
is_animated = hasattr(image, "is_animated") and image.is_animated
|
||||
if should_compress and not is_animated:
|
||||
file_object = self._compress_image(image)
|
||||
filepath = f"{os.path.splitext(filepath)[0]}.jpg"
|
||||
saved_path = self.storage_engine.save(filepath, file_object)
|
||||
else:
|
||||
file_object = self.file_object
|
||||
saved_path = self.storage_engine.save(filepath, self.file_object)
|
||||
|
||||
if not is_animated:
|
||||
self.create_thumbnail(file_object, saved_path)
|
||||
return saved_path
|
||||
|
||||
def create_thumbnail(self, file_object, file_path):
|
||||
thumbnail_filename = utils.get_thumb_filename(file_path)
|
||||
thumbnail_io = BytesIO()
|
||||
# File object after saving e.g. to S3 can be closed.
|
||||
try:
|
||||
image = Image.open(file_object).convert("RGBA")
|
||||
except ValueError:
|
||||
file_object = self.storage_engine.open(file_path)
|
||||
image = Image.open(file_object).convert("RGBA")
|
||||
image.thumbnail(THUMBNAIL_SIZE, Image.ANTIALIAS)
|
||||
image.save(thumbnail_io, format="PNG", optimize=True)
|
||||
return self.storage_engine.save(thumbnail_filename, thumbnail_io)
|
||||
@@ -26,9 +26,9 @@ def send_SMS(phone, text, urgent=False, staff=False):
|
||||
phone.encode('utf-8')
|
||||
|
||||
http_request = 'http://cp.websms.by/?r=api/msg_send' \
|
||||
'&user=administrator@baldenini.by' \
|
||||
'&apikey=zTwevODOYl' \
|
||||
'&sender=Baldenini'
|
||||
'&user=administrator@site.by' \
|
||||
'&apikey=key' \
|
||||
'&sender=company'
|
||||
# '&test=1'
|
||||
|
||||
if urgent:
|
||||
|
||||
@@ -8,6 +8,7 @@ from django.utils.safestring import mark_safe
|
||||
from django.db import models
|
||||
from django.contrib import admin
|
||||
from django.contrib.contenttypes.admin import GenericTabularInline, GenericStackedInline
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
import re
|
||||
# from modeltranslation.admin import TranslationAdmin
|
||||
@@ -36,14 +37,14 @@ def get_base_fieldsets():
|
||||
)
|
||||
}],
|
||||
|
||||
(u'Описание и текст', {
|
||||
(_('Описание и текст'), {
|
||||
'classes': ['wide', 'collapse'],
|
||||
'fields': (
|
||||
'description', 'text',
|
||||
)
|
||||
}),
|
||||
|
||||
(u'Промо ФОН', {
|
||||
(_('Промо ФОН'), {
|
||||
'classes': ['wide', 'collapse'],
|
||||
'fields': (
|
||||
'background_promo_show', 'background_promo_inherits',
|
||||
@@ -63,7 +64,7 @@ def get_base_fieldsets():
|
||||
)
|
||||
}),
|
||||
|
||||
(u'Партнерские ссылки', {
|
||||
(_('Партнерские ссылки'), {
|
||||
'classes': ['wide', 'collapse'],
|
||||
'fields': (
|
||||
'link_left_promo_show',
|
||||
@@ -218,7 +219,7 @@ class Admin_GenericBaseIconStackedInline(GenericStackedInline):
|
||||
def image_thumb(self, obj):
|
||||
return get_image_thumb(self, obj)
|
||||
|
||||
image_thumb.short_description = u'Миниатюра'
|
||||
image_thumb.short_description = _('Миниатюра')
|
||||
image_thumb.allow_tags = True
|
||||
|
||||
|
||||
@@ -231,7 +232,7 @@ class Admin_BaseIconStackedInline(admin.StackedInline):
|
||||
def image_thumb(self, obj):
|
||||
return get_image_thumb(self, obj)
|
||||
|
||||
image_thumb.short_description = u'Миниатюра'
|
||||
image_thumb.short_description = _('Миниатюра')
|
||||
image_thumb.allow_tags = True
|
||||
|
||||
|
||||
@@ -243,7 +244,7 @@ class Admin_BaseIconTabularModel(admin.TabularInline):
|
||||
def image_thumb(self, obj):
|
||||
return get_image_thumb(self, obj)
|
||||
|
||||
image_thumb.short_description = u'Миниатюра'
|
||||
image_thumb.short_description = _('Миниатюра')
|
||||
image_thumb.allow_tags = True
|
||||
|
||||
|
||||
@@ -258,7 +259,7 @@ class Admin_BaseIconModel(admin.ModelAdmin):
|
||||
|
||||
return s
|
||||
|
||||
description_exists.short_description = u'Описание'
|
||||
description_exists.short_description = _('Описание')
|
||||
description_exists.allow_tags = True
|
||||
|
||||
def formfield_for_dbfield (self, db_field, request, **kwargs):
|
||||
@@ -271,7 +272,7 @@ class Admin_BaseIconModel(admin.ModelAdmin):
|
||||
def image_thumb(self, obj):
|
||||
return get_image_thumb(self, obj)
|
||||
|
||||
image_thumb.short_description = u'Миниатюра'
|
||||
image_thumb.short_description = _('Миниатюра')
|
||||
image_thumb.allow_tags = True
|
||||
|
||||
|
||||
|
||||
@@ -112,6 +112,23 @@ class BaseModelViewPage(BaseModel):
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
def get_title(self):
|
||||
if self.seo_title:
|
||||
return self.seo_title
|
||||
elif self.title:
|
||||
return self.title
|
||||
else:
|
||||
return self.name
|
||||
|
||||
def get_description(self):
|
||||
if self.seo_description:
|
||||
return self.seo_description
|
||||
else:
|
||||
return self.description
|
||||
|
||||
def get_FAQ_items(self):
|
||||
return self.FAQ_items.filter(enable=True).order_by('order')
|
||||
|
||||
def get_description_exists(self):
|
||||
if self.description:
|
||||
return True
|
||||
|
||||
@@ -96,27 +96,27 @@ def sortByLength(inputStr):
|
||||
return len(inputStr)
|
||||
|
||||
|
||||
def add_domain(request, url, add_lang=False):
|
||||
domain = get_domain_by_request(request)
|
||||
if add_lang:
|
||||
cur_lang = get_cur_lang_by_request(request)
|
||||
return '{0}/{1}/{2}'.format(domain, cur_lang, url)
|
||||
else:
|
||||
return '{0}{1}'.format(domain, url)
|
||||
# def add_domain(request, url, add_lang=False):
|
||||
# domain = get_domain_by_request(request)
|
||||
# if add_lang:
|
||||
# cur_lang = get_cur_lang_by_request(request)
|
||||
# return '{0}/{1}/{2}'.format(domain, cur_lang, url)
|
||||
# else:
|
||||
# return '{0}{1}'.format(domain, url)
|
||||
|
||||
|
||||
def get_domain_by_request(request):
|
||||
from project_sets import domain
|
||||
if request.query_params and 'domain' in request.query_params:
|
||||
return request.query_params['domain']
|
||||
return domain
|
||||
|
||||
|
||||
def get_cur_lang_by_request(request):
|
||||
from project_sets import lang
|
||||
if request.query_params and 'cur_lang' in request.query_params:
|
||||
return request.query_params['cur_lang']
|
||||
return lang
|
||||
# def get_domain_by_request(request):
|
||||
# from project_sets import domain
|
||||
# if request.query_params and 'domain' in request.query_params:
|
||||
# return request.query_params['domain']
|
||||
# return domain
|
||||
#
|
||||
#
|
||||
# def get_cur_lang_by_request(request):
|
||||
# from project_sets import lang
|
||||
# if request.query_params and 'cur_lang' in request.query_params:
|
||||
# return request.query_params['cur_lang']
|
||||
# return lang
|
||||
|
||||
|
||||
def get_img_type_by_request(request):
|
||||
@@ -416,6 +416,8 @@ def kill_pretexts(txt):
|
||||
return ' '.join(words)
|
||||
|
||||
|
||||
|
||||
|
||||
def stay_only_text_and_numbers(txt):
|
||||
bad_symbols = '"~`{}[]|!@#$%^&*()_+№;:?= '
|
||||
nums = '0123456789'
|
||||
|
||||
@@ -20,11 +20,7 @@ import random
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
# tech@truenergy.by
|
||||
# k7n2d3ZFZo4@CU5$4YDk
|
||||
|
||||
# administrator@truenergy.by
|
||||
# 6&#WfW8$qR2w8uv69e5$
|
||||
|
||||
|
||||
# def fix_mailing_links_in_mail(html):
|
||||
@@ -86,34 +82,20 @@ def prepare_xls_attach_by_xls_virtual_file(virtual_file, filename):
|
||||
return file
|
||||
|
||||
|
||||
def admin_send_mail_by_SMTPlib(subject, from_email, to, html_content, attachments=None):
|
||||
def admin_send_mail_by_SMTPlib(sets, subject, from_email, to, html_content, attachments=None):
|
||||
res = None
|
||||
|
||||
try:
|
||||
# smtp_server = 'mail.cln.by' # 'mail.truenergy.by'
|
||||
# smtp_port = 2525 # 587
|
||||
# smtp_password = 'clNdt6a8a' # u'98q3$IjxH%RUIxySw8R2'
|
||||
# smtp_login = 'support@cln.by' # 'support@truenergy.by'
|
||||
# from_email = smtp_login
|
||||
|
||||
try:
|
||||
smtp_server = 'mail.truenergy.by'
|
||||
smtp_port = 587
|
||||
smtp_password = 'eg4$#95Xp0T*V%ig5BbR'
|
||||
smtp_login = 'support@truenergy.by'
|
||||
res = send_mail_by_SMTPlib(subject, from_email, to, html_content, smtp_server, smtp_port, smtp_login,
|
||||
smtp_password, attachments)
|
||||
except:
|
||||
smtp_server = 'mail.truenergy.by'
|
||||
smtp_port = 25
|
||||
smtp_password = 'PowH@aL0a4%$iz0Uo5V$'
|
||||
smtp_login = 'tech@truenergy.by'
|
||||
res = send_mail_by_SMTPlib(subject, smtp_login, to, html_content, smtp_server, smtp_port, smtp_login,
|
||||
smtp_password, attachments)
|
||||
smtp_server = sets['mail_server_url']
|
||||
smtp_port = sets['mail_server_smtp_port']
|
||||
smtp_password = sets['sender_mail_password']
|
||||
smtp_login = sets['sender_mail_login']
|
||||
res = send_mail_by_SMTPlib(sets, subject, from_email, to, html_content, smtp_server, smtp_port, smtp_login,
|
||||
smtp_password, attachments)
|
||||
|
||||
|
||||
except Exception as e:
|
||||
# from Baldenini_site.SMS_sender import send_SMS
|
||||
# send_SMS(u'375296177827', u'send_mail_by_SMTPlib error = {0}'.format(str(e)), urgent=True)
|
||||
msg = 'admin_send_mail_by_SMTPlib error = {0}'.format(str(e))
|
||||
print(msg)
|
||||
# techSendMail(msg)
|
||||
@@ -121,17 +103,17 @@ def admin_send_mail_by_SMTPlib(subject, from_email, to, html_content, attachment
|
||||
return str(res)
|
||||
|
||||
|
||||
def send_mail_by_SMTPlib(subject, from_email, to_init, html_content, smtp_server, smtp_port, smtp_login, smtp_password,
|
||||
def send_mail_by_SMTPlib(sets, subject, from_email, to_init, html_content, smtp_server, smtp_port, smtp_login, smtp_password,
|
||||
attachments=None):
|
||||
to = to_init
|
||||
if not settings.prod_server:
|
||||
to = 'web@syncsystems.net'
|
||||
else:
|
||||
to = to_init
|
||||
try:
|
||||
from settings_local import DEBUG
|
||||
except:
|
||||
print('get settings_local fail')
|
||||
# if not settings.prod_server:
|
||||
# to = 'web@syncsystems.net'
|
||||
# else:
|
||||
# to = to_init
|
||||
# try:
|
||||
# from settings_local import DEBUG
|
||||
# except:
|
||||
# print('get settings_local fail')
|
||||
|
||||
res = None
|
||||
mail_lib = None
|
||||
@@ -163,16 +145,16 @@ def send_mail_by_SMTPlib(subject, from_email, to_init, html_content, smtp_server
|
||||
res = None
|
||||
|
||||
if type(to) in (list, tuple):
|
||||
if 'support@truenergy.by' in to:
|
||||
to.remove('support@truenergy.by')
|
||||
if sets['sender_email'] in to:
|
||||
to.remove(sets['sender_email'])
|
||||
|
||||
if len(to) > 1:
|
||||
to_str = u', '.join(to)
|
||||
else:
|
||||
to_str = to[0]
|
||||
else:
|
||||
if to == 'support@truenergy.by':
|
||||
return None
|
||||
# if to == sets['sender_email']:
|
||||
# return None
|
||||
to_str = to
|
||||
to = []
|
||||
to.append(to_str)
|
||||
@@ -216,8 +198,6 @@ def send_mail_by_SMTPlib(subject, from_email, to_init, html_content, smtp_server
|
||||
# print('mail_lib.quit = {0}'.format(str(msg)))
|
||||
|
||||
except Exception as e:
|
||||
# from Baldenini_site.SMS_sender import send_SMS
|
||||
# send_SMS(u'375296177827', u'send_mail_by_SMTPlib error = {0}'.format(str(e)), urgent=True)
|
||||
msg = 'send_mail_by_SMTPlib error = {0}'.format(str(e))
|
||||
print(msg)
|
||||
try:
|
||||
@@ -241,10 +221,10 @@ def send_mail_by_SMTPlib(subject, from_email, to_init, html_content, smtp_server
|
||||
return msg
|
||||
|
||||
|
||||
def sendMail(subject, text_content, from_email, to, html_content):
|
||||
def sendMail(sets, subject, text_content, from_email, to, html_content):
|
||||
print('sendMail to {0}'.format(str(to)))
|
||||
|
||||
admin_send_mail_by_SMTPlib(subject, from_email, [to], html_content)
|
||||
admin_send_mail_by_SMTPlib(sets, subject, from_email, [to], html_content)
|
||||
|
||||
# msg = EmailMultiAlternatives(subject, text_content, from_email, [to])
|
||||
# msg.attach_alternative(html_content, "text/html")
|
||||
@@ -253,52 +233,10 @@ def sendMail(subject, text_content, from_email, to, html_content):
|
||||
return u'Accept'
|
||||
|
||||
|
||||
# def techSendMail_for_top_management(html_content, title=None):
|
||||
# try:
|
||||
#
|
||||
# # if not prod_server:
|
||||
# # msg = '{0}. Not sended because is local'.format(html_content)
|
||||
# # print(msg)
|
||||
# # return msg
|
||||
# from AuthApp.models import User
|
||||
# from django.db.models import Q
|
||||
#
|
||||
# # to = ['web@syncsystems.net']
|
||||
# to = User.objects.filter(
|
||||
# Q(is_superuser=True) | Q(groups__name__in=[
|
||||
# 'Отдел продаж: Начальник отдела продаж', 'Управляющий',
|
||||
# 'Бухгалтерия: Главный бухгалтер'
|
||||
# ]),
|
||||
# is_active=True,
|
||||
# is_staff=True
|
||||
# ).values_list('email', flat=True)
|
||||
# to = list(to)
|
||||
# to.append('office@truenergy.by')
|
||||
#
|
||||
# print('techSendMail_for_top_management')
|
||||
# if title:
|
||||
# subject = title
|
||||
# else:
|
||||
# subject = u'truEnergy Data техническое оповещение'
|
||||
# from_email = 'support@truenergy.by'
|
||||
#
|
||||
# res = admin_send_mail_by_SMTPlib(subject, from_email, to, html_content)
|
||||
#
|
||||
# # msg = EmailMultiAlternatives(subject, text_content, from_email, to)
|
||||
# # msg.attach_alternative(html_content, "text/html")
|
||||
# # msg.send()
|
||||
# print(res)
|
||||
# return u'Accept'
|
||||
#
|
||||
# except Exception as e:
|
||||
# msg = 'techSendMail_for_top_management error={0}'.format(str(e))
|
||||
# techSendMail(msg)
|
||||
# print(msg)
|
||||
#
|
||||
# return 'Fail'
|
||||
|
||||
|
||||
def techSendMail_for_specified_email_list(html_content, email_list, title=None):
|
||||
|
||||
def techSendMail_for_specified_email_list(sets, html_content, email_list, title=None):
|
||||
try:
|
||||
|
||||
print('techSendMail_for_specified_email_list')
|
||||
@@ -308,41 +246,44 @@ def techSendMail_for_specified_email_list(html_content, email_list, title=None):
|
||||
subject = u'truEnergy Data техническое оповещение'
|
||||
from_email = 'support@truenergy.by'
|
||||
|
||||
res = admin_send_mail_by_SMTPlib(subject, from_email, email_list, html_content)
|
||||
res = admin_send_mail_by_SMTPlib(sets, subject, from_email, email_list, html_content)
|
||||
|
||||
print(res)
|
||||
return u'Accept'
|
||||
|
||||
except Exception as e:
|
||||
msg = 'techSendMail_for_specified_email_list error={0}'.format(str(e))
|
||||
techSendMail(msg)
|
||||
techSendMail(sets, msg)
|
||||
print(msg)
|
||||
|
||||
return 'Fail'
|
||||
|
||||
|
||||
def techSendMail(html_content, title=None, add_emails=None):
|
||||
def techSendMail(sets, html_content, title=None, add_emails=None):
|
||||
# if not prod_server:
|
||||
# msg = '{0}. Not sended because is local'.format(html_content)
|
||||
# print(msg)
|
||||
# return msg
|
||||
|
||||
print('techSendMail')
|
||||
project_name = ''
|
||||
if 'project_name' in sets:
|
||||
project_name = sets['project_name']
|
||||
|
||||
try:
|
||||
# subject = u'truEnergy Data техническое оповещение'
|
||||
from_email = 'support@truenergy.by'
|
||||
from_email = sets['sender_email']
|
||||
to = ['web@syncsystems.net']
|
||||
if add_emails:
|
||||
to.extend(add_emails)
|
||||
text_content = 'Technical message from truEnergy.'
|
||||
text_content = f'Technical message from {project_name}'
|
||||
|
||||
if title:
|
||||
subject = title
|
||||
else:
|
||||
subject = u'truEnergy Data техническое оповещение'
|
||||
subject = f'{project_name} - техническое оповещение'
|
||||
|
||||
res = admin_send_mail_by_SMTPlib(subject, from_email, to, html_content)
|
||||
res = admin_send_mail_by_SMTPlib(sets, subject, from_email, to, html_content)
|
||||
|
||||
print(res)
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
__author__ = 'SDE'
|
||||
# from Baldenini_site.inter import jsonify
|
||||
|
||||
def get_error_message_Dict(show_icon=None):
|
||||
print('get_error_message_Dict')
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
__author__ = 'SDE'
|
||||
|
||||
def get_paging_Dict(request, elements_count, elements_on_page, from_page, to_page=None):
|
||||
def get_paging_Dict(request, elements_count, next_page_els_count, from_page, to_page=None):
|
||||
|
||||
|
||||
|
||||
pages_count = elements_count / elements_on_page
|
||||
if elements_count % elements_on_page > 0:
|
||||
pages_count = elements_count / next_page_els_count
|
||||
if elements_count % next_page_els_count > 0:
|
||||
pages_count = pages_count + 1
|
||||
|
||||
pages = []
|
||||
|
||||
@@ -8,7 +8,7 @@ def get_ld_search(domain):
|
||||
data = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebSite",
|
||||
"url": domain, #"https://truenergy.by/",
|
||||
"url": domain,
|
||||
"potentialAction": {
|
||||
"@type": "SearchAction",
|
||||
"target": {
|
||||
|
||||
@@ -1,258 +1,75 @@
|
||||
from BaseModels.inter import cut_to_number_w_point
|
||||
|
||||
|
||||
def generate_seotext_by_properties(product_data_Dict):
|
||||
|
||||
power_txt = ''
|
||||
ip_txt = ''
|
||||
lm_txt = ''
|
||||
temp_txt = ''
|
||||
install_txt = ''
|
||||
diametr_txt = ''
|
||||
|
||||
try:
|
||||
|
||||
if 'diameter' in product_data_Dict:
|
||||
val = int(product_data_Dict['diameter'])
|
||||
else:
|
||||
val = int(product_data_Dict['width'])
|
||||
|
||||
diametr_txt = '{0} truEnergy {1} серии {2}.<br>'.format(
|
||||
product_data_Dict['product_type']['name'].upper(),
|
||||
product_data_Dict['article'],
|
||||
product_data_Dict['product_series']['name'].upper()
|
||||
)
|
||||
|
||||
# if product_data_Dict['product_type']['name'] == 'Светильник светодиодный':
|
||||
#
|
||||
# if val < 100:
|
||||
# diametr_txt = '{0} truEnergy {1} серии {2} - это хорошее решение для дома.<br>'.format(
|
||||
# product_data_Dict['product_type']['name'].upper(),
|
||||
# product_data_Dict['article'],
|
||||
# product_data_Dict['product_series']['name'].upper()
|
||||
# )
|
||||
#
|
||||
# elif val < 150:
|
||||
# diametr_txt = '{0} truEnergy {1} серии {2} отлично подойдет для освещения вашей квартиры, дома или офиса.<br>'.format(
|
||||
# product_data_Dict['product_type']['name'].upper(),
|
||||
# product_data_Dict['article'],
|
||||
# product_data_Dict['product_series']['name'].upper()
|
||||
# )
|
||||
#
|
||||
# else:
|
||||
# diametr_txt = '{0} truEnergy {1} серии {2} - это энергоэффективное освещение для различных площадей и объектов.<br>'.format(
|
||||
# product_data_Dict['product_type']['name'].upper(),
|
||||
# product_data_Dict['article'],
|
||||
# product_data_Dict['product_series']['name'].upper()
|
||||
# )
|
||||
# # не светильник
|
||||
# else:
|
||||
# diametr_txt = '{0} truEnergy {1} серии {2} - это энергоэффективное решение для освещения различных пространств.<br>'.format(
|
||||
# product_data_Dict['product_type']['name'].upper(),
|
||||
# product_data_Dict['article'],
|
||||
# product_data_Dict['product_series']['name'].upper()
|
||||
# )
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
# ---------
|
||||
for property in product_data_Dict['properties_w_values_filtred']:
|
||||
|
||||
# ------
|
||||
|
||||
try:
|
||||
|
||||
if property['property']['name'] == 'Мощность':
|
||||
power = int(property['property_value'])
|
||||
|
||||
if power < 7:
|
||||
power_txt = 'Обладая низким энергопотреблением, этот {0} является заменой лампочки накаливания мощностью до 40 Ватт.<br>'.format(
|
||||
product_data_Dict['product_type']['name'].lower(),
|
||||
)
|
||||
|
||||
elif power < 13:
|
||||
power_txt = 'Энергоэффективность этого устройства позволяет использовть его в местах, ' \
|
||||
'где ранее использовались светильники с лампами накаливания мощностью до 75 Ватт.<br>'.format(
|
||||
)
|
||||
elif power < 19:
|
||||
power_txt = 'Этот {0} мощностью {1} Ватт легко заменит старые лампы накаливания мощностью до 100 Ватт ' \
|
||||
'или люминесцентные лампы мощностью до 40 Ватт.<br>'.format(
|
||||
product_data_Dict['product_type']['name'].lower(),
|
||||
str(power)
|
||||
)
|
||||
|
||||
elif power < 37:
|
||||
power_txt = 'Данная модель подходит для освещения больших пространств. ' \
|
||||
'Она не только поможет решить вопрос освещения, но и существенно сэкономит бюджет, ' \
|
||||
'выделенный на решение этой задачи.<br>'.format(
|
||||
product_data_Dict['product_type']['name'].lower(),
|
||||
)
|
||||
else:
|
||||
power_txt = '{0} Ватт, в данной модели обеспечивает мощный световой поток. ' \
|
||||
'Это дает возможность установки одного изделия для освещения помещений с большой ' \
|
||||
'площадью или открытых пространств.<br>'.format(
|
||||
str(power),
|
||||
product_data_Dict['product_type']['name'].lower(),
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
# ------
|
||||
|
||||
try:
|
||||
|
||||
if property['property']['name'] == 'Световой поток' and product_data_Dict['article'] != '11043':
|
||||
val = int(property['property_value'])
|
||||
|
||||
if product_data_Dict['product_type']['name'] == 'Светильник светодиодный':
|
||||
lm_txt = 'Один {0} данной модели способен осветить до {1} м.кв. площади ' \
|
||||
'для рабочих зон и жилых комнат, и до {2} м.кв. площади для проходных и подсобных помещений ' \
|
||||
'(при стандартной высоте потолка и нормальной освещенности помещения).<br>'.format(
|
||||
product_data_Dict['product_type']['name'].lower(),
|
||||
str(round(val / 300,2)),
|
||||
str(round(val / 120, 2)),
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
# -------
|
||||
|
||||
try:
|
||||
|
||||
if property['property']['name'] == 'IP (пылевлагозащита)':
|
||||
val = int(property['property_value'])
|
||||
|
||||
if val > 66:
|
||||
ip_txt = 'Максимальная защита IP{0} способна выдержать самые сильные испытания водой. ' \
|
||||
'Освещение с такой защитой используют для фонтанов и бассейнов.<br>'.format(
|
||||
str(val),
|
||||
)
|
||||
|
||||
elif val > 64:
|
||||
ip_txt = 'Данный продукт имеет высокую степень пылевлагозащиты - IP{0}. В связи с этим данная модель прекрасно подходит как ' \
|
||||
'для отапливаемых помещений с нормальным уровнем влажности, так и для помещений неотапливаемых, ' \
|
||||
'а также для эксплуатации на улице. Устройство с данной степенью защиты не боится пыли и влаги' \
|
||||
'а так же имеет защиту от струй воды со всех направлений.<br>'.format(
|
||||
str(val),
|
||||
)
|
||||
|
||||
elif val > 60:
|
||||
ip_txt = 'Степень защиты IP{0} обозначает полную защиту от брызг с любых сторон и имеет полную пылинепроницаемость ' \
|
||||
'(никакая пыль не может проникнуть внутрь корпуса устройства). ' \
|
||||
'Светильники подходят для установки в помещении и на улице, при рабочих температурах -20 до +40 градусов.<br>'.format(
|
||||
str(val),
|
||||
)
|
||||
|
||||
elif val > 53:
|
||||
ip_txt = 'У изделия с степенью защиты IP{0} снижена возможность попадания пыли внутрь корпуса ' \
|
||||
'и обеспечена полная защита расположенной внутри устройстав электроники.' \
|
||||
'Часто используют для рабочих помещений с повышенным содержанием пыли и влаги, а также под навесами.<br>'.format(
|
||||
str(val),
|
||||
product_data_Dict['product_type']['name'].lower(),
|
||||
product_data_Dict['product_type']['name_plural'].lower(),
|
||||
)
|
||||
|
||||
elif val > 40:
|
||||
ip_txt = 'Могут устанавливаться в помещения с повышенным уровнем пыли.'.format(
|
||||
product_data_Dict['product_type']['name'].lower(),
|
||||
)
|
||||
else:
|
||||
ip_txt = 'IP{0} - степень защиты данной модели, в связи с этим могут устанавливаться в' \
|
||||
' отапливаемые помещения с умеренным уровнем влажности.<br>'.format(
|
||||
str(val),
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
# -------
|
||||
|
||||
try:
|
||||
|
||||
if property['property']['name'] == 'Цветовая температура':
|
||||
val = int(property['property_value'])
|
||||
|
||||
if val < 3001:
|
||||
temp_txt = 'Теплый свет, генерируемый этой моделью способствует отдыху и расслаблению. ' \
|
||||
'Он приятен для глаз. В связи с этим рекомендуется устанавливать {0} ' \
|
||||
'с температурой {1}К в зоны отдыха, жилые комнаты и спальни, кафе, лаундж зоны. ' \
|
||||
'Очень удачное решение для обеденных и гостинных комнат.<br>'.format(
|
||||
product_data_Dict['product_type']['name_plural'].lower(),
|
||||
str(val),
|
||||
)
|
||||
|
||||
elif val < 4601:
|
||||
temp_txt = 'Модель обладает нейтральным цветом свечения, который прекрасно подходит и как для жилых помещений и комнат, ' \
|
||||
'так и для рабочих зон (офисов, кабинетов, производств) . ' \
|
||||
'Данный свет стимулирует к работе не вызывая перенапряжения глаз и не искажая цветопередачу. ' \
|
||||
'Универсальное и наиболее распространенное решение.<br>'.format(
|
||||
str(val),
|
||||
)
|
||||
|
||||
elif val < 7001:
|
||||
temp_txt = 'Цветовая температура {0}К - наиболее оптимально использование в помещениях промышленного назначения, ' \
|
||||
'административных зданиях, на производствах, складах, гаражах, паркингах. ' \
|
||||
'Однако могут применяться и в интерьере для создания акцентов в дизайне, ' \
|
||||
'либо если предпочтения потребителя отданы в пользу белого света. <br>'.format(
|
||||
str(val),
|
||||
)
|
||||
|
||||
|
||||
|
||||
else:
|
||||
temp_txt = 'От показателя цветовой температуры зависит то, как Вы будут воспринимать предметы и другие объекты освещенные устройством. ' \
|
||||
'С помощью цветовой температуры можно сделать более приятным отдых и улучшить эффективность работы. ' \
|
||||
'Отниситесь внимательно к выбору устройства по этому параметру.<br>'.format(
|
||||
str(val),
|
||||
)
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
# -------
|
||||
|
||||
try:
|
||||
|
||||
if property['property']['name'] == 'Тип монтажа':
|
||||
val = property['property_value']
|
||||
|
||||
if val == 'встраиваемый':
|
||||
install_txt = 'Устройство устанавливается в предварительно вырезанное в поверхности отверстие. ' \
|
||||
'Этот вариант монтажа используется для подвесных и натяжных потолков, а так же для фальш-стен и ниш.'.format(
|
||||
str(val),
|
||||
)
|
||||
|
||||
elif val == 'накладной':
|
||||
install_txt = 'Способ крепления - накладной. Значит эта модель может быть закреплена на любую ровную поверхность.'.format(
|
||||
str(val),
|
||||
)
|
||||
|
||||
elif val == 'встраиваемый/накладной':
|
||||
install_txt = '{0} обладает возможностью монтажа как в отверстия на поверхности плоскостей, так и на любую ровную поверхность.'.format(
|
||||
product_data_Dict['article'],
|
||||
)
|
||||
|
||||
else:
|
||||
pass
|
||||
|
||||
if 'height_visible_part' in product_data_Dict and product_data_Dict['height_visible_part']:
|
||||
install_txt = install_txt + ' Высота видимой части устройства после монтажа составит {0}мм.<br>'.format(
|
||||
str(round(product_data_Dict['height_visible_part']))
|
||||
)
|
||||
else:
|
||||
install_txt = install_txt + '<br>'
|
||||
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
product_data_Dict['seo_text'] = '{0}{1}{2}{3}{4}{5}'.format(
|
||||
diametr_txt,
|
||||
power_txt,
|
||||
lm_txt,
|
||||
ip_txt,
|
||||
temp_txt,
|
||||
install_txt
|
||||
)
|
||||
|
||||
return product_data_Dict
|
||||
# def generate_seotext_by_properties(product_data_Dict):
|
||||
#
|
||||
# power_txt = ''
|
||||
# ip_txt = ''
|
||||
# lm_txt = ''
|
||||
# temp_txt = ''
|
||||
# install_txt = ''
|
||||
# diametr_txt = ''
|
||||
#
|
||||
# try:
|
||||
#
|
||||
#
|
||||
#
|
||||
# except Exception as e:
|
||||
# pass
|
||||
#
|
||||
# # ---------
|
||||
# for property in product_data_Dict['properties_w_values_filtred']:
|
||||
#
|
||||
# # ------
|
||||
#
|
||||
# try:
|
||||
#
|
||||
#
|
||||
# except Exception as e:
|
||||
# pass
|
||||
#
|
||||
# # ------
|
||||
#
|
||||
# try:
|
||||
#
|
||||
#
|
||||
#
|
||||
# except Exception as e:
|
||||
# pass
|
||||
#
|
||||
# # -------
|
||||
#
|
||||
# try:
|
||||
#
|
||||
#
|
||||
#
|
||||
# except Exception as e:
|
||||
# pass
|
||||
#
|
||||
# # -------
|
||||
#
|
||||
# try:
|
||||
#
|
||||
#
|
||||
# except Exception as e:
|
||||
# pass
|
||||
#
|
||||
# # -------
|
||||
#
|
||||
# try:
|
||||
#
|
||||
#
|
||||
#
|
||||
# except Exception as e:
|
||||
# pass
|
||||
#
|
||||
# product_data_Dict['seo_text'] = '{0}{1}{2}{3}{4}{5}'.format(
|
||||
# diametr_txt,
|
||||
# power_txt,
|
||||
# lm_txt,
|
||||
# ip_txt,
|
||||
# temp_txt,
|
||||
# install_txt
|
||||
# )
|
||||
#
|
||||
# return product_data_Dict
|
||||
24
BaseModels/validators/form_field_validators.py
Normal file
@@ -0,0 +1,24 @@
|
||||
from django.utils.translation import gettext as _
|
||||
from django.utils.safestring import mark_safe
|
||||
def get_phone_valid_error(val):
|
||||
allow_chars = '01234567890()+ -'
|
||||
|
||||
error_msg = mark_safe(_('Некорректные символы в номере, введите номер в международном формате с кодом страны'))
|
||||
|
||||
if not val:
|
||||
return None
|
||||
|
||||
if len(val) < 10:
|
||||
return error_msg
|
||||
|
||||
if '+' in val and val[0] != '+':
|
||||
return error_msg
|
||||
|
||||
i = 0
|
||||
while i < len(val):
|
||||
if val[i] not in allow_chars:
|
||||
return error_msg
|
||||
|
||||
i += 1
|
||||
|
||||
return None
|
||||
@@ -1,6 +1,11 @@
|
||||
from sets.admin import *
|
||||
from .models import *
|
||||
from django.contrib import admin
|
||||
from django import forms
|
||||
from django.forms import widgets
|
||||
|
||||
|
||||
|
||||
|
||||
class Admin_MsgGroup(Admin_BaseModel):
|
||||
list_display = [
|
||||
@@ -11,8 +16,33 @@ class Admin_MsgGroup(Admin_BaseModel):
|
||||
admin.site.register(MsgGroup,Admin_MsgGroup)
|
||||
|
||||
class Admin_Message(Admin_BaseModel):
|
||||
|
||||
def cut_group_text(self, obj):
|
||||
if obj.group:
|
||||
return obj.group.name[:10]
|
||||
return '-'
|
||||
cut_group_text.allow_tags = True
|
||||
cut_group_text.short_description = 'ticket'
|
||||
|
||||
|
||||
def cut_text(self, obj):
|
||||
if obj.text:
|
||||
if len(obj.text) > 20:
|
||||
return f'{obj.text[:20]}...'
|
||||
else:
|
||||
return obj.text
|
||||
return '-'
|
||||
cut_text.allow_tags = True
|
||||
cut_text.short_description = 'сообщение'
|
||||
|
||||
search_fields = ['group__name', 'text', 'name', 'id']
|
||||
|
||||
list_filter = ['status']
|
||||
|
||||
list_display = [
|
||||
'id', 'msg_type', 'group', 'status', 'sender', 'receiver', 'text',
|
||||
'id',
|
||||
# 'msg_type',
|
||||
'cut_group_text', 'status', 'sender', 'receiver', 'cut_text',
|
||||
'name',
|
||||
'order', 'modifiedDT', 'createDT'
|
||||
]
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import copy
|
||||
|
||||
from .models import *
|
||||
from django.db.models import Q, Value as V, Count, OuterRef, Subquery
|
||||
from django.http import HttpResponse, Http404, JsonResponse
|
||||
@@ -11,6 +13,13 @@ from django.urls import reverse
|
||||
import json
|
||||
from datetime import datetime, time
|
||||
from django.conf import settings
|
||||
from AuthApp.funcs import get_user_timezone_Dict
|
||||
|
||||
|
||||
def get_unanswered_msgs_count_for_user(user):
|
||||
msgs = Message.objects.filter(receiver=user, status='sended', group=None)
|
||||
return msgs.count()
|
||||
|
||||
|
||||
|
||||
def get_update_chat_Dict(data):
|
||||
@@ -45,11 +54,22 @@ def get_update_chat_Dict(data):
|
||||
receiver = User.objects.get(id=data['receiver'])
|
||||
|
||||
if data['sender'] == data['cur_user']:
|
||||
context_Dict.update({'user': sender})
|
||||
user = copy.copy(sender)
|
||||
cur_receiver = copy.copy(receiver)
|
||||
else:
|
||||
context_Dict.update({'user': receiver})
|
||||
user = copy.copy(receiver)
|
||||
cur_receiver = copy.copy(sender)
|
||||
# context_Dict.update({'user': receiver})
|
||||
|
||||
context_Dict.update({'cur_receiver': receiver})
|
||||
# context_Dict.update({'cur_receiver': receiver})
|
||||
context_Dict.update({
|
||||
'cur_receiver': cur_receiver,
|
||||
'user': user,
|
||||
})
|
||||
context_Dict.update(get_user_timezone_Dict(user))
|
||||
|
||||
if sender == receiver:
|
||||
print('!')
|
||||
|
||||
required_beep = data['required_beep']
|
||||
|
||||
@@ -92,7 +112,7 @@ def get_update_chat_Dict(data):
|
||||
|
||||
context_Dict.update({
|
||||
'messages': msgs,
|
||||
'MEDIA_URL': settings.MEDIA_URL
|
||||
'MEDIA_URL': settings.MEDIA_URL,
|
||||
})
|
||||
html = render_to_string(tpl_name, context_Dict)
|
||||
if required_full_support_chat_html:
|
||||
@@ -268,6 +288,7 @@ def send_msg(data):
|
||||
|
||||
def get_chat_page_content_html(request, receiver_id=None):
|
||||
from AuthApp.models import User
|
||||
from AuthApp.funcs import get_user_timezone_Dict
|
||||
|
||||
msgs = []
|
||||
try:
|
||||
@@ -287,6 +308,7 @@ def get_chat_page_content_html(request, receiver_id=None):
|
||||
'receivers': receivers,
|
||||
'page': 'chat',
|
||||
}
|
||||
Dict.update(get_user_timezone_Dict(request.user, request=request))
|
||||
tpl_name = 'blocks/profile/b_chats.html'
|
||||
|
||||
html = render_to_string(tpl_name, Dict, request=request)
|
||||
|
||||
@@ -53,6 +53,7 @@ def show_chat_w_user_ajax(request):
|
||||
|
||||
data = json.loads(request.body)
|
||||
Dict = get_chat_page_content_Dict(request, data['user_id'])
|
||||
Dict.update(get_user_timezone_Dict(request.user, request=request))
|
||||
|
||||
tpl_name = 'blocks/profile/b_chats.html'
|
||||
|
||||
@@ -99,7 +100,7 @@ def update_chat_ajax2(request):
|
||||
receiver = User.objects.get(id=data['receiver'])
|
||||
|
||||
context_Dict.update({'cur_receiver': receiver})
|
||||
|
||||
context_Dict.update(get_user_timezone_Dict(request.user, request=request))
|
||||
|
||||
if not ticket:
|
||||
|
||||
@@ -123,6 +124,7 @@ def update_chat_ajax2(request):
|
||||
|
||||
# формируем правую панель
|
||||
context_Dict.update({'receivers': receivers})
|
||||
|
||||
users_list_html = render_to_string(
|
||||
'blocks/profile/b_list_of_users_messenger.html', context_Dict, request=request)
|
||||
res_Dict.update({
|
||||
@@ -190,6 +192,7 @@ def update_chat_ajax(request):
|
||||
receiver = User.objects.get(id=data['receiver'])
|
||||
|
||||
context_Dict.update({'cur_receiver': receiver})
|
||||
context_Dict.update(get_user_timezone_Dict(request.user, request=request))
|
||||
|
||||
if ticket:
|
||||
|
||||
@@ -201,6 +204,8 @@ def update_chat_ajax(request):
|
||||
context_Dict.update({'messages': msgs})
|
||||
context_Dict = get_ticketsDict_for_staff(request.user)
|
||||
|
||||
context_Dict.update(get_user_timezone_Dict(request.user))
|
||||
|
||||
tickets_list_html = render_to_string(
|
||||
'blocks/profile/b_list_of_tickets_support_chat.html', context_Dict, request=request)
|
||||
res_Dict.update({
|
||||
@@ -220,6 +225,8 @@ def update_chat_ajax(request):
|
||||
required_beep = True
|
||||
|
||||
context_Dict.update({'receivers': receivers})
|
||||
context_Dict.update(get_user_timezone_Dict(request.user))
|
||||
|
||||
users_list_html = render_to_string(
|
||||
'blocks/profile/b_list_of_users_messenger.html', context_Dict, request=request)
|
||||
res_Dict.update({
|
||||
@@ -402,12 +409,16 @@ def support_show_chat_by_ticket_ajax(request):
|
||||
'ticket': ticket,
|
||||
'messages': msgs,
|
||||
'cur_receiver': cur_receiver,
|
||||
'new_msg_allow': new_msg_allow
|
||||
'new_msg_allow': new_msg_allow,
|
||||
'staff': request.user.is_staff,
|
||||
# 'mobile': data['mobile']
|
||||
}
|
||||
Dict.update(get_ticketsDict_for_staff(request.user))
|
||||
|
||||
tpl_name = 'blocks/profile/b_support_chat.html'
|
||||
Dict.update(get_user_timezone_Dict(request.user))
|
||||
|
||||
tpl_name = 'blocks/profile/b_support_chat.html'
|
||||
Dict.update(get_user_timezone_Dict(request.user, request=request))
|
||||
html = render_to_string(tpl_name, Dict, request=request)
|
||||
return JsonResponse({'html': html}, status=200)
|
||||
|
||||
@@ -427,6 +438,9 @@ def support_create_ticket_form_ajax(request):
|
||||
Dict = {
|
||||
'form': TicketForm()
|
||||
}
|
||||
|
||||
Dict.update(get_user_timezone_Dict(request.user))
|
||||
|
||||
tpl_name = 'blocks/profile/b_create_ticket.html'
|
||||
|
||||
html = render_to_string(tpl_name, Dict, request=request)
|
||||
@@ -448,6 +462,8 @@ def create_ticket_ajax(request):
|
||||
if not form.is_valid():
|
||||
form.initial = form.cleaned_data
|
||||
Dict = {'form': form}
|
||||
Dict.update(get_user_timezone_Dict(request.user))
|
||||
|
||||
html = render_to_string('blocks/profile/b_create_ticket.html', Dict, request=request)
|
||||
return JsonResponse({'html': html}, status=400)
|
||||
|
||||
@@ -488,6 +504,8 @@ def create_ticket_ajax(request):
|
||||
'messages': msgs_for_ticket
|
||||
}
|
||||
|
||||
Dict.update(get_user_timezone_Dict(request.user))
|
||||
|
||||
html = render_to_string('blocks/profile/b_support_chat.html', Dict, request=request)
|
||||
|
||||
res_Dict = {
|
||||
@@ -498,9 +516,11 @@ def create_ticket_ajax(request):
|
||||
|
||||
except Exception as e:
|
||||
|
||||
msg = f'{_("ошибка в запросе")} = {str(e)}'
|
||||
|
||||
errors_Dict = {
|
||||
'errors': {
|
||||
'all__': f'ошибка в запросе = {str(e)}'
|
||||
'all__': msg
|
||||
}
|
||||
}
|
||||
Dict = {'form': errors_Dict}
|
||||
|
||||
@@ -3,41 +3,53 @@ from BaseModels.base_models import BaseModel
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
msg_type_choices = (
|
||||
('support', 'техподдержка'),
|
||||
('private', 'личное')
|
||||
('support', _('техподдержка')),
|
||||
('private', _('личное'))
|
||||
)
|
||||
|
||||
msg_status_choices = (
|
||||
('sended', 'Отправлено'),
|
||||
('seen', 'Просмотрено')
|
||||
('sended', _('Отправлено')),
|
||||
('seen', _('Просмотрено'))
|
||||
)
|
||||
|
||||
grp_msg_status = (
|
||||
('open', 'Открыт'),
|
||||
('answered', 'Отвечен'),
|
||||
('closed', 'Закрыт')
|
||||
('open', _('Открыт')),
|
||||
('answered', _('Отвечен')),
|
||||
('closed', _('Закрыт'))
|
||||
)
|
||||
|
||||
|
||||
grp_msg_department = (
|
||||
('support', 'Отдел: Техническая поддержка'),
|
||||
('finance', 'Отдел: Финансовый департамент'),
|
||||
('support', _('Отдел: Техническая поддержка')),
|
||||
('finance', _('Отдел: Финансовый департамент')),
|
||||
)
|
||||
|
||||
|
||||
class MsgGroup(BaseModel):
|
||||
from AuthApp.models import User
|
||||
|
||||
department = models.CharField(verbose_name='Отдел', default='support', choices=grp_msg_department)
|
||||
status = models.CharField(verbose_name='Статус', default='open', choices=grp_msg_status)
|
||||
department = models.CharField(verbose_name=_('Отдел'), default='support', choices=grp_msg_department)
|
||||
status = models.CharField(verbose_name=_('Статус'), default='open', choices=grp_msg_status)
|
||||
|
||||
text = models.TextField(verbose_name='Сообщение')
|
||||
text = models.TextField(verbose_name=_('Сообщение'))
|
||||
|
||||
owner = models.ForeignKey(User, verbose_name=_('Владелец'), related_name='rel_msgGroups_for_owner',
|
||||
on_delete=models.SET_NULL, null=True)
|
||||
manager = models.ForeignKey(User, verbose_name=_('Менеджер'), related_name='rel_msgGroups_for_manager',
|
||||
on_delete=models.SET_NULL, null=True)
|
||||
|
||||
def get_last_msg_txt(self):
|
||||
msg = self.rel_messages_for_group.all().order_by('-createDT').first()
|
||||
if not msg:
|
||||
return self.text
|
||||
|
||||
if msg.text:
|
||||
return msg.text
|
||||
elif msg.files:
|
||||
return msg.files[0]['file_name']
|
||||
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Тикет')
|
||||
verbose_name_plural = _('Тикеты')
|
||||
@@ -46,23 +58,23 @@ class MsgGroup(BaseModel):
|
||||
class Message(BaseModel):
|
||||
from AuthApp.models import User
|
||||
|
||||
msg_type = models.CharField(max_length=50, verbose_name='Тип сообщения', default='private', choices=msg_type_choices)
|
||||
msg_type = models.CharField(max_length=50, verbose_name=_('Тип сообщения'), default='private', choices=msg_type_choices)
|
||||
group = models.ForeignKey(
|
||||
MsgGroup, verbose_name='Группа сообщений', related_name='rel_messages_for_group',
|
||||
MsgGroup, verbose_name=_('Группа сообщений'), related_name='rel_messages_for_group',
|
||||
on_delete=models.SET_NULL, null=True)
|
||||
|
||||
sender = models.ForeignKey(
|
||||
User, verbose_name='Отправитель', on_delete=models.CASCADE, related_name='rel_messages_for_sender'
|
||||
User, verbose_name=_('Отправитель'), on_delete=models.CASCADE, related_name='rel_messages_for_sender'
|
||||
)
|
||||
receiver = models.ForeignKey(
|
||||
User, verbose_name='Получатель', on_delete=models.CASCADE, related_name='rel_messages_for_receiver'
|
||||
User, verbose_name=_('Получатель'), on_delete=models.CASCADE, related_name='rel_messages_for_receiver'
|
||||
)
|
||||
|
||||
text = models.TextField(verbose_name='Сообщение')
|
||||
text = models.TextField(verbose_name=_('Сообщение'))
|
||||
|
||||
status = models.CharField(verbose_name='Статус', default='sended', choices=msg_status_choices)
|
||||
status = models.CharField(verbose_name=_('Статус'), default='sended', choices=msg_status_choices)
|
||||
|
||||
files = models.JSONField(verbose_name='Прикрепленные файлы', default=dict)
|
||||
files = models.JSONField(verbose_name=_('Прикрепленные файлы'), default=dict)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Сообщение')
|
||||
|
||||
@@ -41,6 +41,10 @@ def get_filesize(size):
|
||||
@register.simple_tag
|
||||
def get_msg_side(cur_user, ticket, msg):
|
||||
if msg:
|
||||
# if msg.sender == cur_user:
|
||||
# return 'left'
|
||||
# else:
|
||||
# return 'right'
|
||||
if msg.sender == cur_user:
|
||||
return 'right'
|
||||
else:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from sets.admin import *
|
||||
from .models import *
|
||||
from django.contrib import admin
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
class Admin_StaticPage(Admin_Trans_BaseModelViewPage):
|
||||
|
||||
@@ -14,6 +15,12 @@ class Admin_StaticPage(Admin_Trans_BaseModelViewPage):
|
||||
'order',
|
||||
)
|
||||
}),
|
||||
(_('Настройки'), {
|
||||
'classes': ['wide', 'collapse'],
|
||||
'fields': (
|
||||
'FAQ_title',
|
||||
)
|
||||
}),
|
||||
('SEO', {
|
||||
'classes': ['wide', 'collapse'],
|
||||
'fields': (
|
||||
@@ -45,46 +52,61 @@ class Admin_StaticPage(Admin_Trans_BaseModelViewPage):
|
||||
|
||||
admin.site.register(StaticPage,Admin_StaticPage)
|
||||
|
||||
class Admin_Block(Admin_BaseBlock):
|
||||
# class Admin_Block(Admin_Trans_BaseModel):
|
||||
# pass
|
||||
#
|
||||
# # def get_fieldsets(self, request, obj=None):
|
||||
# # fieldsets = super(type(self), self).get_fieldsets(request, obj)
|
||||
# # if not request.user.is_superuser and obj.name and obj.name in ('About US', 'machines', 'works'):
|
||||
# # fieldsets[0][1]['fields'].pop(0)
|
||||
# # fieldsets.insert(
|
||||
# # 1, (_('Контент'), {
|
||||
# # 'classes': ['wide'],
|
||||
# # 'fields': (
|
||||
# # 'title', 'description', 'text',
|
||||
# # 'picture',
|
||||
# # )
|
||||
# #
|
||||
# # })
|
||||
# # )
|
||||
# # return fieldsets
|
||||
# #
|
||||
# # def has_delete_permission(self, request, obj=None):
|
||||
# # if request.user.is_superuser:
|
||||
# # return True
|
||||
# #
|
||||
# # if obj.name in ('About US', 'machines', 'works'):
|
||||
# # return False
|
||||
#
|
||||
# admin.site.register(Block,Admin_Block)
|
||||
|
||||
def get_fieldsets(self, request, obj=None):
|
||||
fieldsets = super(type(self), self).get_fieldsets(request, obj)
|
||||
if not request.user.is_superuser and obj.name and obj.name in ('About US', 'machines', 'works'):
|
||||
fieldsets[0][1]['fields'].pop(0)
|
||||
fieldsets.insert(
|
||||
1, ('Контент', {
|
||||
'classes': ['wide'],
|
||||
'fields': (
|
||||
'title', 'description', 'text',
|
||||
'picture',
|
||||
)
|
||||
class Admin_Option(Admin_Trans_BaseModel):
|
||||
|
||||
})
|
||||
)
|
||||
return fieldsets
|
||||
# def get_fieldsets(self, request, obj=None):
|
||||
# fieldsets = super(type(self), self).get_fieldsets(request, obj)
|
||||
# fieldsets.insert(
|
||||
# 1, ('Контент', {
|
||||
# 'classes': ['wide'],
|
||||
# 'fields': (
|
||||
# 'opt_type', 'prefix', 'value', 'picture'
|
||||
# )
|
||||
#
|
||||
# })
|
||||
# )
|
||||
# return fieldsets
|
||||
|
||||
def has_delete_permission(self, request, obj=None):
|
||||
if request.user.is_superuser:
|
||||
return True
|
||||
|
||||
if obj.name in ('About US', 'machines', 'works'):
|
||||
return False
|
||||
fieldsets = [
|
||||
(_('Контент'), {
|
||||
'classes': ['wide'],
|
||||
'fields': (
|
||||
'name', 'opt_type', 'prefix', 'value', 'picture'
|
||||
)
|
||||
}),
|
||||
]
|
||||
|
||||
admin.site.register(Block,Admin_Block)
|
||||
|
||||
class Admin_Option(Admin_BaseModel):
|
||||
|
||||
def get_fieldsets(self, request, obj=None):
|
||||
fieldsets = super(type(self), self).get_fieldsets(request, obj)
|
||||
fieldsets.insert(
|
||||
1, ('Контент', {
|
||||
'classes': ['wide'],
|
||||
'fields': (
|
||||
'opt_type', 'prefix', 'value', 'picture'
|
||||
)
|
||||
|
||||
})
|
||||
)
|
||||
return fieldsets
|
||||
list_display = ['image_thumb', 'opt_type', 'name', 'value', 'prefix']
|
||||
list_editable = ['value', 'prefix']
|
||||
list_filter = ['opt_type']
|
||||
|
||||
admin.site.register(Option,Admin_Option)
|
||||
|
||||
51
GeneralApp/allauth_funcs.py
Normal file
@@ -0,0 +1,51 @@
|
||||
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
|
||||
from allauth.account.utils import user_field
|
||||
from django.conf import settings
|
||||
from allauth.account.adapter import DefaultAccountAdapter
|
||||
import requests
|
||||
from django.core.files import File
|
||||
from django.core.files.temp import NamedTemporaryFile
|
||||
|
||||
class MyAccountAdapter(DefaultAccountAdapter):
|
||||
|
||||
def get_login_redirect_url(self, request):
|
||||
path = super(MyAccountAdapter, self).get_login_redirect_url(request)
|
||||
|
||||
try:
|
||||
user = request.user
|
||||
user_profile = user.user_profile
|
||||
if user_profile and not user_profile.avatar:
|
||||
social_accounts = user.socialaccount_set.all()
|
||||
if social_accounts:
|
||||
for social_account in social_accounts:
|
||||
if 'picture' in social_account.extra_data and social_account.extra_data['picture']:
|
||||
r = requests.get(social_account.extra_data['picture'])
|
||||
|
||||
img_temp = NamedTemporaryFile()
|
||||
img_temp.write(r.content)
|
||||
img_temp.flush()
|
||||
user_profile.avatar.save(f'avatar_{user.id}.jpeg', File(img_temp), True)
|
||||
break
|
||||
|
||||
except Exception as e:
|
||||
msg = f'post_save create_user_profile Error = {str(e)}'
|
||||
print(msg)
|
||||
|
||||
return path
|
||||
|
||||
# class CustomSocialAccountAdapter(DefaultSocialAccountAdapter):
|
||||
# def populate_user(self, request, sociallogin, data):
|
||||
# from AuthApp.models import UserProfile
|
||||
#
|
||||
# user = super().populate_user(request, sociallogin, data)
|
||||
# try:
|
||||
# picture = sociallogin.account.extra_data['picture']
|
||||
# user_profile = UserProfile.objects.get_or_create(user=user)
|
||||
# with open(picture, 'rb') as fd:
|
||||
# user_profile.avatar.save(f'user_{user.id}_avatar.jpeg', fd.read(), True)
|
||||
# # user_field(user, "profile_photo", picture)
|
||||
# except Exception as e:
|
||||
# msg = f'CustomSocialAccountAdapter populate_user Error = {str(e)}'
|
||||
# print(msg)
|
||||
#
|
||||
# return user
|
||||
@@ -1,14 +1,45 @@
|
||||
from django.http import HttpResponse, Http404, FileResponse
|
||||
from django.conf import settings
|
||||
|
||||
def get_inter_Dict(user):
|
||||
|
||||
from SubscribesApp.funcs import get_cur_user_subscribe
|
||||
user_subscribe = get_cur_user_subscribe(user)
|
||||
|
||||
return {'user_subscribe': user_subscribe}
|
||||
|
||||
Dict = {
|
||||
'user_subscribe': user_subscribe,
|
||||
'prod': True
|
||||
}
|
||||
|
||||
if settings.WS_ADDRESS == 'localhost:8000':
|
||||
Dict.update({'prod': False})
|
||||
|
||||
|
||||
from PushMessages.views import get_key_Dict
|
||||
Dict.update(get_key_Dict())
|
||||
|
||||
return Dict
|
||||
|
||||
def get_inter_http_respose(template_obj, context_Dict, request):
|
||||
|
||||
context_Dict.update(get_inter_Dict(request.user))
|
||||
|
||||
from PushMessages.views import send_push
|
||||
if request and 'page' in context_Dict:
|
||||
text = None
|
||||
title = None
|
||||
|
||||
if context_Dict['page'] == dict:
|
||||
if 'title' in context_Dict['page']:
|
||||
title = context_Dict['page']['title']
|
||||
if 'description' in context_Dict['page']:
|
||||
text = context_Dict['page']['description']
|
||||
else:
|
||||
title = getattr(context_Dict['page'], 'title', None)
|
||||
text = getattr(context_Dict['page'], 'description', None)
|
||||
|
||||
# if text and title and not request.user.is_anonymous:
|
||||
# send_push(user=request.user, title=title, text=text)
|
||||
|
||||
return HttpResponse(template_obj.render(context_Dict, request))
|
||||
44
GeneralApp/funcs_options.py
Normal file
@@ -0,0 +1,44 @@
|
||||
from .models import *
|
||||
|
||||
def get_options_by_opt_types(opt_types, only_vals=False):
|
||||
if type(opt_types) == str:
|
||||
kwargs = {'opt_type': opt_types}
|
||||
elif type(opt_types) == dict:
|
||||
kwargs = opt_types
|
||||
else:
|
||||
kwargs = {'opt_type__in': opt_types}
|
||||
|
||||
opts = Option.objects.filter(**kwargs)
|
||||
if opts and only_vals:
|
||||
res = {}
|
||||
opts = opts.values('opt_type', 'value', 'prefix')
|
||||
for item in opts:
|
||||
if item['opt_type'] == 'domain':
|
||||
|
||||
try:
|
||||
from django.contrib.sites.models import Site
|
||||
current_site = Site.objects.get_current()
|
||||
res.update({item['opt_type']: current_site.domain})
|
||||
continue
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
|
||||
if item['prefix']:
|
||||
res.update({item['opt_type']: f"{item['prefix']}{item['value']}"})
|
||||
else:
|
||||
res.update({item['opt_type']: f"{item['value']}"})
|
||||
return res
|
||||
|
||||
return opts
|
||||
|
||||
def get_first_option_value_by_opt_type(opt_type):
|
||||
opts = get_options_by_opt_types(opt_type)
|
||||
if opts:
|
||||
return opts[0].value
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_mail_send_options():
|
||||
opt_types = ['mail_server_url', 'mail_server_smtp_port', 'sender_mail_login', 'sender_mail_password', 'sender_email', 'project_name']
|
||||
|
||||
return get_options_by_opt_types(opt_types, only_vals=True)
|
||||
66
GeneralApp/init_options.py
Normal file
@@ -0,0 +1,66 @@
|
||||
from .models import *
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
|
||||
required_options_Dict = {
|
||||
'mail_server_url': {
|
||||
'name_ru': 'Адрес почтового сервера',
|
||||
'opt_type': 'mail_server_url',
|
||||
'value': '213.142.147.40',
|
||||
},
|
||||
'mail_server_smtp_port': {
|
||||
'name_ru': 'SMTP порт почтового сервера',
|
||||
'opt_type': 'mail_server_smtp_port',
|
||||
'value': 587,
|
||||
},
|
||||
'sender_mail_login': {
|
||||
'name_ru': 'email для отправки писем с сайта',
|
||||
'opt_type': 'sender_mail_login',
|
||||
'value': 'admin@tripwb.com',
|
||||
},
|
||||
'sender_email': {
|
||||
'name_ru': 'email для отправки',
|
||||
'opt_type': 'sender_email',
|
||||
'value': 'admin@tripwb.com',
|
||||
},
|
||||
'sender_mail_password': {
|
||||
'name_ru': 'пароль для отправки писем с сайта',
|
||||
'opt_type': 'sender_mail_password',
|
||||
'value': 't5Fdcah^gdajY',
|
||||
},
|
||||
'project_name': {
|
||||
'name_ru': 'Название проекта',
|
||||
'opt_type': 'project_name',
|
||||
'value': 'TWB',
|
||||
},
|
||||
'domain': {
|
||||
'name_ru': 'Адрес сайта',
|
||||
'opt_type': 'domain',
|
||||
'value': 'tripwb.com',
|
||||
},
|
||||
'support_email': {
|
||||
'name_ru': 'email техподдержки',
|
||||
'opt_type': 'support_email',
|
||||
'value': 'admin@tripwb.com',
|
||||
},
|
||||
'corp_email': {
|
||||
'name_ru': 'корпоративный email',
|
||||
'opt_type': 'corp_email',
|
||||
'value': 'admin@tripwb.com',
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
def init_options():
|
||||
options = Option.objects.all()
|
||||
option_types_list = options.values_list('opt_type', flat=True)
|
||||
|
||||
opts_for_create = []
|
||||
for opt_type, data_Dict in required_options_Dict.items():
|
||||
if not opt_type in option_types_list:
|
||||
opt = Option(**data_Dict)
|
||||
opts_for_create.append(opt)
|
||||
|
||||
Option.objects.bulk_create(opts_for_create)
|
||||
|
||||
return True
|
||||
@@ -0,0 +1,43 @@
|
||||
# Generated by Django 4.2.2 on 2023-11-30 13:42
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('GeneralApp', '0004_alter_block_description_alter_block_description_en_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='option',
|
||||
name='name_en',
|
||||
field=models.TextField(blank=True, help_text='Название', null=True, verbose_name='Название'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='option',
|
||||
name='name_ru',
|
||||
field=models.TextField(blank=True, help_text='Название', null=True, verbose_name='Название'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='option',
|
||||
name='prefix_en',
|
||||
field=models.CharField(blank=True, max_length=250, null=True, verbose_name='Префикс'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='option',
|
||||
name='prefix_ru',
|
||||
field=models.CharField(blank=True, max_length=250, null=True, verbose_name='Префикс'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='option',
|
||||
name='value_en',
|
||||
field=models.CharField(max_length=250, null=True, verbose_name='Значение'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='option',
|
||||
name='value_ru',
|
||||
field=models.CharField(max_length=250, null=True, verbose_name='Значение'),
|
||||
),
|
||||
]
|
||||
@@ -5,7 +5,7 @@ from django.utils.translation import gettext_lazy as _
|
||||
from ckeditor_uploader.fields import RichTextUploadingField
|
||||
|
||||
class StaticPage(BaseModelViewPage):
|
||||
promo_header = models.BooleanField(verbose_name='Промо-хэдер', default=False)
|
||||
promo_header = models.BooleanField(verbose_name=_('Промо-хэдер'), default=False)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Статическая страница')
|
||||
@@ -17,9 +17,9 @@ class Block(BaseModelViewPage):
|
||||
verbose_name_plural = _('Блоки на страницах')
|
||||
|
||||
class Option(BaseModel):
|
||||
opt_type = models.CharField(max_length=250, verbose_name='Тип', blank=True, null=True)
|
||||
prefix = models.CharField(max_length=250, verbose_name='Префикс', blank=True, null=True)
|
||||
value = models.CharField(max_length=250, verbose_name='Значение')
|
||||
opt_type = models.CharField(max_length=250, verbose_name=_('Тип'), blank=True, null=True)
|
||||
prefix = models.CharField(max_length=250, verbose_name=_('Префикс'), blank=True, null=True)
|
||||
value = models.CharField(max_length=250, verbose_name=_('Значение'))
|
||||
picture = models.ImageField(upload_to='uploads/', verbose_name=_('Миниатюра'), null=True, blank=True,
|
||||
help_text=u'')
|
||||
|
||||
@@ -36,8 +36,8 @@ class FAQitem(BaseModel):
|
||||
object_id = models.PositiveIntegerField()
|
||||
content_object = GenericForeignKey('content_type', 'object_id')
|
||||
|
||||
question = models.TextField(verbose_name='Вопрос')
|
||||
answer = RichTextUploadingField(verbose_name='Ответ')
|
||||
question = models.TextField(verbose_name=_('Вопрос'))
|
||||
answer = RichTextUploadingField(verbose_name=_('Ответ'))
|
||||
|
||||
def __str__(self):
|
||||
if self.question:
|
||||
|
||||
@@ -154,3 +154,7 @@ def get_color_by_number(value, arg=None):
|
||||
#
|
||||
# return s
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -14,6 +14,12 @@ class Block_TranslationOptions(TranslationOptions):
|
||||
)
|
||||
translator.register(Block, Block_TranslationOptions)
|
||||
|
||||
class Option_TranslationOptions(TranslationOptions):
|
||||
fields = (
|
||||
'name', 'value', 'prefix'
|
||||
)
|
||||
translator.register(Option, Option_TranslationOptions)
|
||||
|
||||
|
||||
class FAQitem_TranslationOptions(TranslationOptions):
|
||||
fields = (
|
||||
|
||||
@@ -6,41 +6,88 @@ from django.contrib.auth.decorators import login_required
|
||||
from .models import *
|
||||
from django.conf import settings
|
||||
from .funcs import get_inter_http_respose
|
||||
from django.http.response import JsonResponse, HttpResponse
|
||||
from django.views.decorators.http import require_GET, require_POST
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.contrib.auth.models import User
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from webpush import send_user_notification
|
||||
import json
|
||||
|
||||
def test_code(request):
|
||||
from RoutesApp.funcs import get_city_by_type_transport_and_address_point
|
||||
from RoutesApp.models import Route
|
||||
from ReferenceDataApp.models import Airport, City
|
||||
|
||||
routes = Route.objects.all()
|
||||
# import allauth
|
||||
# from allauth.socialaccount.models import SocialApp
|
||||
# apps = SocialApp.objects.all()
|
||||
# apps.delete()
|
||||
|
||||
for route in routes:
|
||||
print(route.id)
|
||||
required_save = False
|
||||
if not route.from_city:
|
||||
route.from_city = get_city_by_type_transport_and_address_point(route.type_transport, route.from_address_point)
|
||||
required_save = True
|
||||
from RoutesApp.search_matches import search_matches
|
||||
search_matches()
|
||||
|
||||
if not route.to_city:
|
||||
route.to_city = get_city_by_type_transport_and_address_point(route.type_transport,
|
||||
route.to_address_point)
|
||||
required_save = True
|
||||
# try:
|
||||
# # body = request.body
|
||||
# # data = json.loads(body)
|
||||
# # if 'head' not in data or 'body' not in data or 'id' not in data:
|
||||
# # return JsonResponse(status=400, data={"message": "Invalid data format"})
|
||||
# # user_id = data['id']
|
||||
# user = request.user
|
||||
# payload = {'head': '123', 'body': 'qwerty'}
|
||||
# send_user_notification(user=user, payload=payload, ttl=1000)
|
||||
# return JsonResponse(status=200, data={"message": "Web push successful"})
|
||||
# except TypeError:
|
||||
# return JsonResponse(status=500, data={"message": "An error occurred"})
|
||||
|
||||
if required_save:
|
||||
route.save()
|
||||
# routes = Route.objects.all()
|
||||
#
|
||||
# for route in routes:
|
||||
# print(route.id)
|
||||
# required_save = False
|
||||
# if not route.from_city:
|
||||
# route.from_city = get_city_by_type_transport_and_address_point(route.type_transport, route.from_address_point)
|
||||
# required_save = True
|
||||
#
|
||||
# if not route.to_city:
|
||||
# route.to_city = get_city_by_type_transport_and_address_point(route.type_transport,
|
||||
# route.to_address_point)
|
||||
# required_save = True
|
||||
#
|
||||
# if required_save:
|
||||
# route.save()
|
||||
|
||||
return HttpResponse('finished')
|
||||
|
||||
|
||||
|
||||
def Page404(request, exeption=None):
|
||||
|
||||
Dict = {}
|
||||
|
||||
t = loader.get_template('404.html')
|
||||
try:
|
||||
res = get_inter_http_respose(t, Dict, request)
|
||||
return HttpResponse(res, status=404)
|
||||
except Exception as e:
|
||||
return HttpResponse(str(e))
|
||||
|
||||
|
||||
|
||||
|
||||
def MainPage(request):
|
||||
from RoutesApp.forms import RouteForm
|
||||
|
||||
from .init_options import init_options
|
||||
init_options()
|
||||
|
||||
|
||||
print(f'LOCALE_PATHS = {str(settings.LOCALE_PATHS)}')
|
||||
|
||||
page = StaticPage.objects.get(url='main')
|
||||
|
||||
from ArticlesApp.models import ArticleModel
|
||||
arts = ArticleModel.objects.filter(enable=True).order_by('-createDT')[:4]
|
||||
arts = ArticleModel.objects.filter(enable=True).order_by('-createDT')[:3]
|
||||
|
||||
Dict = {
|
||||
'page': page,
|
||||
@@ -50,6 +97,8 @@ def MainPage(request):
|
||||
'owner_type': 'mover'
|
||||
}
|
||||
|
||||
|
||||
|
||||
breadcrumbs_Dict = {
|
||||
}
|
||||
Dict.update({'breadcrumbs': breadcrumbs_Dict})
|
||||
|
||||
0
PushMessages/__init__.py
Normal file
3
PushMessages/admin.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
6
PushMessages/apps.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class PushmessagesConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'PushMessages'
|
||||
0
PushMessages/migrations/__init__.py
Normal file
3
PushMessages/models.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.db import models
|
||||
|
||||
# Create your models here.
|
||||
3
PushMessages/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
16
PushMessages/urls.py
Normal file
@@ -0,0 +1,16 @@
|
||||
# coding=utf-8
|
||||
from django.urls import path, include
|
||||
# from AuthApp.js_views import *
|
||||
# from AuthApp.import_funcs import *
|
||||
from .views import *
|
||||
from django.contrib.auth import views
|
||||
from RoutesApp.js_views import new_route_view_ajax
|
||||
from django.views.generic import TemplateView
|
||||
|
||||
urlpatterns = [
|
||||
|
||||
path('send_push', send_push),
|
||||
path('webpush/', include('webpush.urls')),
|
||||
path('sw.js', TemplateView.as_view(template_name='sw.js', content_type='application/x-javascript')),
|
||||
|
||||
]
|
||||
49
PushMessages/views.py
Normal file
@@ -0,0 +1,49 @@
|
||||
from django.http.response import JsonResponse, HttpResponse
|
||||
from django.views.decorators.http import require_GET, require_POST
|
||||
from django.contrib.auth.models import User
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from webpush import send_user_notification
|
||||
import json
|
||||
from django.shortcuts import render, get_object_or_404
|
||||
from django.conf import settings
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
|
||||
def get_key_Dict():
|
||||
webpush_settings = getattr(settings, 'WEBPUSH_SETTINGS', {})
|
||||
vapid_key = webpush_settings.get('VAPID_PUBLIC_KEY')
|
||||
Dict = {
|
||||
'vapid_key': vapid_key
|
||||
}
|
||||
return Dict
|
||||
|
||||
def send_push(user, title, text, url=None, button_name=None, img=None):
|
||||
try:
|
||||
# body = request.body
|
||||
# data = json.loads(body)
|
||||
#
|
||||
# if 'head' not in data or 'body' not in data or 'id' not in data:
|
||||
# return JsonResponse(status=400, data={"message": "Invalid data format"})
|
||||
#
|
||||
# user_id = data['id']
|
||||
# user = get_object_or_404(User, pk=user_id)
|
||||
Dict = {
|
||||
'head': title,
|
||||
'body': text,
|
||||
}
|
||||
if url:
|
||||
Dict['url'] = url
|
||||
if button_name:
|
||||
Dict['button_name'] = button_name
|
||||
else:
|
||||
Dict['button_name'] = _('Перейти'),
|
||||
|
||||
if img:
|
||||
Dict['img'] = img
|
||||
|
||||
# payload = {'head': data['head'], 'body': data['body']}
|
||||
send_user_notification(user=user, payload=Dict, ttl=1000)
|
||||
|
||||
return JsonResponse(status=200, data={"message": "Web push successful"})
|
||||
except TypeError:
|
||||
return JsonResponse(status=500, data={"message": "An error occurred"})
|
||||
3
README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
celery -A TWB.celery:app worker -l info
|
||||
|
||||
celery -A TWB.celery:app beat -l info
|
||||
@@ -55,7 +55,7 @@ def get_address_point_ajax(request):
|
||||
else:
|
||||
item['city_name'] = item['name']
|
||||
item['country_name'] = item['country__name']
|
||||
item['fullname'] = f'{item["country_name"]} / {item["city_name"]}'
|
||||
item['fullname'] = f'{item["city_name"]} / {item["country_name"]}'
|
||||
html = f"{html}{render_to_string('widgets/w_ac_input_address_point.html', item)}"
|
||||
i += 1
|
||||
|
||||
|
||||
@@ -3,21 +3,21 @@ from BaseModels.base_models import BaseModel
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
class Country(BaseModel):
|
||||
international_name = models.CharField(max_length=250, verbose_name='Международное название', blank=True, null=True)
|
||||
official_name = models.CharField(max_length=250, verbose_name='Официальное название', blank=True, null=True)
|
||||
international_name = models.CharField(max_length=250, verbose_name=_('Международное название'), blank=True, null=True)
|
||||
official_name = models.CharField(max_length=250, verbose_name=_('Официальное название'), blank=True, null=True)
|
||||
|
||||
short_code = models.CharField(max_length=2, verbose_name='Код страны по ISO3166-1:alpha2')
|
||||
code = models.CharField(max_length=3, verbose_name='Код страны по ISO3166-1:alpha3')
|
||||
num_code = models.CharField(max_length=3, verbose_name='Код страны по ISO3166-1:numeric', blank=True, null=True)
|
||||
short_code = models.CharField(max_length=2, verbose_name=_('Код страны по ISO3166-1:alpha2'))
|
||||
code = models.CharField(max_length=3, verbose_name=_('Код страны по ISO3166-1:alpha3'))
|
||||
num_code = models.CharField(max_length=3, verbose_name=_('Код страны по ISO3166-1:numeric'), blank=True, null=True)
|
||||
|
||||
flag_img_url = models.URLField(verbose_name='Ссылка на изображение флага', blank=True, null=True)
|
||||
flag_img_url = models.URLField(verbose_name=_('Ссылка на изображение флага'), blank=True, null=True)
|
||||
|
||||
geo_lat = models.CharField(max_length=20, verbose_name='GPS широта', blank=True, null=True)
|
||||
geo_lon = models.CharField(max_length=20, verbose_name='GPS долгота', blank=True, null=True)
|
||||
geo_lat = models.CharField(max_length=20, verbose_name=_('GPS широта'), blank=True, null=True)
|
||||
geo_lon = models.CharField(max_length=20, verbose_name=_('GPS долгота'), blank=True, null=True)
|
||||
|
||||
area_id = models.BigIntegerField(blank=True, null=True)
|
||||
|
||||
parsing_finished_DT = models.DateTimeField(verbose_name='Дата и время завершения парсинга', blank=True, null=True)
|
||||
parsing_finished_DT = models.DateTimeField(verbose_name=_('Дата и время завершения парсинга'), blank=True, null=True)
|
||||
|
||||
def __str__(self):
|
||||
if self.name:
|
||||
@@ -39,14 +39,14 @@ class Country(BaseModel):
|
||||
class City(BaseModel):
|
||||
|
||||
country = models.ForeignKey(
|
||||
Country, verbose_name='Страна', related_name='rel_cities_for_country', on_delete=models.CASCADE)
|
||||
Country, verbose_name=_('Страна'), related_name='rel_cities_for_country', on_delete=models.CASCADE)
|
||||
|
||||
geo_lat = models.CharField(max_length=20, verbose_name='GPS широта', blank=True, null=True)
|
||||
geo_lon = models.CharField(max_length=20, verbose_name='GPS долгота', blank=True, null=True)
|
||||
geo_lat = models.CharField(max_length=20, verbose_name=_('GPS широта'), blank=True, null=True)
|
||||
geo_lon = models.CharField(max_length=20, verbose_name=_('GPS долгота'), blank=True, null=True)
|
||||
|
||||
area_id = models.BigIntegerField(blank=True, null=True)
|
||||
|
||||
parsing_finished_DT = models.DateTimeField(verbose_name='Дата и время завершения парсинга', blank=True, null=True)
|
||||
parsing_finished_DT = models.DateTimeField(verbose_name=_('Дата и время завершения парсинга'), blank=True, null=True)
|
||||
|
||||
def __str__(self):
|
||||
if self.name:
|
||||
@@ -55,7 +55,7 @@ class City(BaseModel):
|
||||
return f'{self.id}'
|
||||
|
||||
def get_country_n_city_str(self):
|
||||
country = 'Неизвестно'
|
||||
country = _('Неизвестно')
|
||||
city = self.name
|
||||
if self.country:
|
||||
country = self.country
|
||||
@@ -72,20 +72,20 @@ class City(BaseModel):
|
||||
class Airport(BaseModel):
|
||||
|
||||
city = models.ForeignKey(
|
||||
City, verbose_name='Город', related_name='rel_airports_for_city', on_delete=models.CASCADE,
|
||||
City, verbose_name=_('Город'), related_name='rel_airports_for_city', on_delete=models.CASCADE,
|
||||
blank=True, null=True)
|
||||
|
||||
international_name = models.CharField(max_length=250, verbose_name='Международное название', blank=True, null=True)
|
||||
international_name = models.CharField(max_length=250, verbose_name=_('Международное название'), blank=True, null=True)
|
||||
|
||||
iata_code = models.CharField(max_length=3, verbose_name='IATA')
|
||||
icao_code = models.CharField(max_length=4, verbose_name='ICAO')
|
||||
|
||||
geo_lat = models.CharField(max_length=20, verbose_name='GPS широта', blank=True, null=True)
|
||||
geo_lon = models.CharField(max_length=20, verbose_name='GPS долгота', blank=True, null=True)
|
||||
geo_lat = models.CharField(max_length=20, verbose_name=_('GPS широта'), blank=True, null=True)
|
||||
geo_lon = models.CharField(max_length=20, verbose_name=_('GPS долгота'), blank=True, null=True)
|
||||
|
||||
area_id = models.BigIntegerField(blank=True, null=True)
|
||||
|
||||
parsing_finished_DT = models.DateTimeField(verbose_name='Дата и время завершения парсинга', blank=True, null=True)
|
||||
parsing_finished_DT = models.DateTimeField(verbose_name=_('Дата и время завершения парсинга'), blank=True, null=True)
|
||||
|
||||
def __str__(self):
|
||||
if self.name:
|
||||
|
||||
@@ -4,7 +4,7 @@ from django.contrib import admin
|
||||
|
||||
class Admin_Route(Admin_Trans_BaseModel):
|
||||
list_display = [
|
||||
'id', 'owner_type', 'type_transport', 'cargo_type',
|
||||
'id', 'owner_type', 'receive_msg_by_email', 'type_transport', 'cargo_type',
|
||||
'departure_DT', 'from_city', 'from_place',
|
||||
'arrival_DT', 'to_city', 'to_place', 'owner',
|
||||
'order', 'modifiedDT', 'createDT'
|
||||
@@ -14,5 +14,6 @@ class Admin_Route(Admin_Trans_BaseModel):
|
||||
|
||||
list_filter = ['owner_type', 'type_transport', 'cargo_type', 'from_place', 'arrival_DT', 'modifiedDT', 'createDT']
|
||||
search_fields = ['owner__first_name', 'owner__last_name']
|
||||
raw_id_fields = ['from_city', 'to_city']
|
||||
|
||||
admin.site.register(Route,Admin_Route)
|
||||
|
||||
@@ -6,6 +6,47 @@ from django.core.exceptions import ValidationError
|
||||
from .models import *
|
||||
|
||||
|
||||
def routeForm_assign_choices_by_type_transport(form, type_transport):
|
||||
if type_transport == 'avia':
|
||||
transfer_location_choices = (
|
||||
('airport', _('В аэропорту')),
|
||||
('city', _('По городу')),
|
||||
('other', _('По договоренности'))
|
||||
)
|
||||
|
||||
cargo_type_choices = (
|
||||
('cargo', _('Груз')),
|
||||
('parcel', _('Бандероль')),
|
||||
('package', _('Посылка')),
|
||||
('letter', _('Письмо\Документ'))
|
||||
)
|
||||
|
||||
else:
|
||||
transfer_location_choices = (
|
||||
('city', _('По городу')),
|
||||
('other', _('По договоренности'))
|
||||
)
|
||||
|
||||
cargo_type_choices = (
|
||||
('passenger', _('Пассажир')),
|
||||
('cargo', _('Груз')),
|
||||
('parcel', _('Бандероль')),
|
||||
('package', _('Посылка')),
|
||||
('letter', _('Письмо\Документ'))
|
||||
)
|
||||
|
||||
form.fields['from_place'].choices = transfer_location_choices
|
||||
form.fields['to_place'].choices = transfer_location_choices
|
||||
form.fields['cargo_type'].choices = cargo_type_choices
|
||||
|
||||
form.base_fields['from_place'].choices = transfer_location_choices
|
||||
form.base_fields['to_place'].choices = transfer_location_choices
|
||||
form.base_fields['cargo_type'].choices = cargo_type_choices
|
||||
|
||||
return form
|
||||
|
||||
|
||||
|
||||
class RouteForm(forms.ModelForm):
|
||||
from_address_point_txt = forms.CharField(required=True)
|
||||
to_address_point_txt = forms.CharField(required=True)
|
||||
@@ -24,6 +65,22 @@ class RouteForm(forms.ModelForm):
|
||||
|
||||
try:
|
||||
|
||||
if 'phone' in cleaned_data and 'phone' in cleaned_data:
|
||||
from BaseModels.validators.form_field_validators import get_phone_valid_error
|
||||
error = get_phone_valid_error(cleaned_data["phone"])
|
||||
if error:
|
||||
self.add_error('phone', error)
|
||||
|
||||
if 'extra_phone' in cleaned_data and 'extra_phone' in cleaned_data:
|
||||
from BaseModels.validators.form_field_validators import get_phone_valid_error
|
||||
error = get_phone_valid_error(cleaned_data["extra_phone"])
|
||||
if error:
|
||||
self.add_error('extra_phone', error)
|
||||
|
||||
if 'departure_DT' in cleaned_data and 'arrival_DT' in cleaned_data and cleaned_data['arrival_DT'] < cleaned_data['departure_DT']:
|
||||
self.add_error('arrival_DT', _('Указана неверная дата прибытия'))
|
||||
|
||||
|
||||
if 'from_place' in self.data and self.data['from_place'] not in [item[0] for item in self.fields['from_place'].choices]:
|
||||
cleaned_data['from_place'] = self.fields['from_place'].choices[0][0]
|
||||
if 'from_place' in self.errors and self.errors['from_place'].data[0].code == 'invalid_choice':
|
||||
|
||||
@@ -4,12 +4,22 @@ from django.utils.translation import gettext as _
|
||||
from django.template.loader import render_to_string
|
||||
from datetime import datetime
|
||||
|
||||
elements_on_page = 25
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def get_profile_new_route_page_html(request, data):
|
||||
|
||||
form = RouteForm()
|
||||
Dict = {
|
||||
'form': form
|
||||
}
|
||||
|
||||
|
||||
try:
|
||||
|
||||
errors_off = True
|
||||
@@ -24,59 +34,71 @@ def get_profile_new_route_page_html(request, data):
|
||||
if 'to_address_point_txt' in data:
|
||||
del data['to_address_point_txt']
|
||||
|
||||
|
||||
# if data['type_transport'] == 'avia':
|
||||
# transfer_location_choices = (
|
||||
# ('airport', _('В аэропорту')),
|
||||
# ('city', _('По городу')),
|
||||
# ('other', _('По договоренности'))
|
||||
# )
|
||||
#
|
||||
# cargo_type_choices = (
|
||||
# ('cargo', _('Груз')),
|
||||
# ('parcel', _('Бандероль')),
|
||||
# ('package', _('Посылка')),
|
||||
# ('letter', _('Письмо\Документ'))
|
||||
# )
|
||||
#
|
||||
#
|
||||
# else:
|
||||
# transfer_location_choices = (
|
||||
# ('city', _('По городу')),
|
||||
# ('other', _('По договоренности'))
|
||||
# )
|
||||
#
|
||||
# cargo_type_choices = (
|
||||
# ('passenger', _('Пассажир')),
|
||||
# ('cargo', _('Груз')),
|
||||
# ('parcel', _('Бандероль')),
|
||||
# ('package', _('Посылка')),
|
||||
# ('letter', _('Письмо\Документ'))
|
||||
# )
|
||||
|
||||
form = RouteForm(data)
|
||||
if not form.is_valid():
|
||||
pass
|
||||
form = RouteForm(initial=form.cleaned_data)
|
||||
|
||||
if 'type_transport' in data:
|
||||
if data['type_transport'] == 'avia':
|
||||
transfer_location_choices = (
|
||||
('airport', _('В аэропорту')),
|
||||
('city', _('По городу')),
|
||||
('other', _('По договоренности'))
|
||||
)
|
||||
form = routeForm_assign_choices_by_type_transport(form, data['type_transport'])
|
||||
|
||||
cargo_type_choices = (
|
||||
('passenger', _('Пассажир')),
|
||||
('cargo', _('Груз')),
|
||||
('parcel', _('Бандероль')),
|
||||
('package', _('Посылка')),
|
||||
('letter', _('Письмо\Документ'))
|
||||
)
|
||||
|
||||
|
||||
else:
|
||||
transfer_location_choices = (
|
||||
('city', _('По городу')),
|
||||
('other', _('По договоренности'))
|
||||
)
|
||||
|
||||
cargo_type_choices = (
|
||||
('cargo', _('Груз')),
|
||||
('parcel', _('Бандероль')),
|
||||
('package', _('Посылка')),
|
||||
('letter', _('Письмо\Документ'))
|
||||
)
|
||||
|
||||
form = RouteForm(data)
|
||||
if not form.is_valid():
|
||||
pass
|
||||
form = RouteForm(initial=form.cleaned_data)
|
||||
|
||||
form.fields['from_place'].choices = transfer_location_choices
|
||||
form.fields['to_place'].choices = transfer_location_choices
|
||||
form.fields['cargo_type'].choices = cargo_type_choices
|
||||
|
||||
form.base_fields['from_place'].choices = transfer_location_choices
|
||||
form.base_fields['to_place'].choices = transfer_location_choices
|
||||
form.base_fields['cargo_type'].choices = cargo_type_choices
|
||||
# form.fields['from_place'].choices = transfer_location_choices
|
||||
# form.fields['to_place'].choices = transfer_location_choices
|
||||
# form.fields['cargo_type'].choices = cargo_type_choices
|
||||
#
|
||||
# form.base_fields['from_place'].choices = transfer_location_choices
|
||||
# form.base_fields['to_place'].choices = transfer_location_choices
|
||||
# form.base_fields['cargo_type'].choices = cargo_type_choices
|
||||
|
||||
# form = CreateRouteForm(initial=data)
|
||||
|
||||
# if not form.is_valid():
|
||||
# pass
|
||||
|
||||
if 'owner_type' in data:
|
||||
form.initial['owner_type'] = data['owner_type']
|
||||
|
||||
if request.user and request.user.is_authenticated and request.user.user_profile and request.user.user_profile.phone:
|
||||
form.initial.update({'phone': request.user.user_profile.phone})
|
||||
|
||||
Dict = {
|
||||
'form': form,
|
||||
'errors_off': errors_off
|
||||
}
|
||||
|
||||
if 'owner_type' in data:
|
||||
Dict.update({'owner_type': data['owner_type']})
|
||||
|
||||
# print(form)
|
||||
except Exception as e:
|
||||
# form.errors.append({'__all__': f'Ошибка: {str(e)}'})
|
||||
@@ -138,18 +160,31 @@ def get_routes_Dict(user=None, data=None):
|
||||
res_Dict = {}
|
||||
|
||||
if data:
|
||||
|
||||
type_transport = None
|
||||
if 'type_transport' in data and data['type_transport']:
|
||||
items_list = data['type_transport'].split(',')
|
||||
kwargs.update({f'type_transport__in': items_list})
|
||||
|
||||
if len(items_list) == 1:
|
||||
type_transport = items_list[0]
|
||||
|
||||
|
||||
for key, val in data.items():
|
||||
if val:
|
||||
if key == 'weight':
|
||||
weight_list = val.split(';')
|
||||
if weight_list[0]:
|
||||
kwargs.update({f'{key}__gte': int(weight_list[0])})
|
||||
if weight_list[1]:
|
||||
kwargs.update({f'{key}__lte': int(weight_list[1])})
|
||||
if len(weight_list) > 1:
|
||||
if weight_list[0]:
|
||||
kwargs.update({f'{key}__gte': int(weight_list[0])})
|
||||
if weight_list[1]:
|
||||
kwargs.update({f'{key}__lte': int(weight_list[1])})
|
||||
else:
|
||||
kwargs.update({f'{key}__lte': int(weight_list[0])})
|
||||
|
||||
if key == 'type_transport':
|
||||
items_list = val.split(',')
|
||||
kwargs.update({f'{key}__in': items_list})
|
||||
# if key == 'type_transport':
|
||||
# items_list = val.split(',')
|
||||
# kwargs.update({f'{key}__in': items_list})
|
||||
|
||||
|
||||
if key in (
|
||||
@@ -169,19 +204,18 @@ def get_routes_Dict(user=None, data=None):
|
||||
kwargs.update({key: val})
|
||||
|
||||
if key == 'from_address_point':
|
||||
kwargs.update({f'from_city__id': val})
|
||||
city = get_city_by_type_transport_and_address_point(type_transport, val)
|
||||
kwargs.update({f'from_city': city})
|
||||
|
||||
res_Dict.update({
|
||||
'from_address_point_txt': get_country_n_city_str_by_type_transport_and_address_point(
|
||||
'road', val
|
||||
)
|
||||
'from_address_point_txt': city.get_country_n_city_str()
|
||||
})
|
||||
|
||||
if key == 'to_address_point':
|
||||
kwargs.update({f'to_city__id': val})
|
||||
city = get_city_by_type_transport_and_address_point(type_transport, val)
|
||||
kwargs.update({f'to_city': city})
|
||||
res_Dict.update({
|
||||
'to_address_point_txt': get_country_n_city_str_by_type_transport_and_address_point(
|
||||
'road', val
|
||||
)
|
||||
'to_address_point_txt': city.get_country_n_city_str()
|
||||
})
|
||||
|
||||
if key == 'from_el':
|
||||
@@ -189,7 +223,7 @@ def get_routes_Dict(user=None, data=None):
|
||||
if key == 'to_el':
|
||||
to_el = int(val)
|
||||
|
||||
routes = Route.objects.filter(**kwargs).order_by('departure_DT', 'arrival_DT', '-modifiedDT')
|
||||
routes = Route.objects.filter(**kwargs).order_by('-departure_DT', '-arrival_DT', '-modifiedDT')
|
||||
routes_count = routes.count()
|
||||
|
||||
if from_el and to_el:
|
||||
@@ -199,14 +233,17 @@ def get_routes_Dict(user=None, data=None):
|
||||
elif to_el:
|
||||
routes = routes[:to_el]
|
||||
else:
|
||||
to_el = 25
|
||||
to_el = elements_on_page
|
||||
routes = routes[:to_el]
|
||||
|
||||
last_block = False
|
||||
if not to_el or to_el >= routes_count:
|
||||
last_block = True
|
||||
|
||||
|
||||
if routes_count - to_el > elements_on_page:
|
||||
next_page_els_count = elements_on_page
|
||||
else:
|
||||
next_page_els_count = routes_count - to_el
|
||||
|
||||
try:
|
||||
|
||||
@@ -232,7 +269,8 @@ def get_routes_Dict(user=None, data=None):
|
||||
res_Dict.update({
|
||||
'routes': routes,
|
||||
'last_block': last_block,
|
||||
'last_el': to_el
|
||||
'last_el': to_el,
|
||||
'next_page_els_count': next_page_els_count
|
||||
})
|
||||
return res_Dict
|
||||
|
||||
|
||||
@@ -67,6 +67,8 @@ def edit_route_ajax(request):
|
||||
route = Route.objects.get(id=data['route_id'])
|
||||
|
||||
form = RouteForm(instance=route)
|
||||
form = routeForm_assign_choices_by_type_transport(form, route.type_transport)
|
||||
|
||||
route_address_points_Dict = route.get_address_points()
|
||||
form.initial.update({
|
||||
'from_address_point_txt': route_address_points_Dict['from_address_point_txt'],
|
||||
@@ -143,12 +145,15 @@ def find_routes_ajax(request):
|
||||
if 'errors' in routes_Dict:
|
||||
return JsonResponse(routes_Dict, status=400)
|
||||
|
||||
|
||||
html = render_to_string('blocks/b_search_routes.html', routes_Dict, request=request)
|
||||
if routes_Dict['routes']:
|
||||
html = render_to_string('blocks/b_search_routes.html', routes_Dict, request=request)
|
||||
else:
|
||||
html = render_to_string('templates_js_translate/not_found_find_routes.html', routes_Dict, request=request)
|
||||
|
||||
res_Dict = {
|
||||
'html': html,
|
||||
'last_block': routes_Dict['last_block']
|
||||
'last_block': routes_Dict['last_block'],
|
||||
'next_page_els_count': routes_Dict['next_page_els_count'],
|
||||
# 'form': RouteForm(initial=data)
|
||||
}
|
||||
|
||||
@@ -227,7 +232,7 @@ def create_or_change_route_ajax(request, route_id=None):
|
||||
return JsonResponse({'html': html}, status=400)
|
||||
|
||||
obj = form.save(commit=False)
|
||||
if 'owner_type' in data:
|
||||
if 'owner_type' in data and data['owner_type']:
|
||||
obj.owner_type = data['owner_type']
|
||||
|
||||
if obj.from_address_point:
|
||||
@@ -239,6 +244,8 @@ def create_or_change_route_ajax(request, route_id=None):
|
||||
obj.owner = request.user
|
||||
obj.save()
|
||||
|
||||
route_id = obj.id
|
||||
|
||||
routes_Dict = get_routes_Dict(request.user)
|
||||
|
||||
if 'errors' in routes_Dict:
|
||||
|
||||
0
RoutesApp/management/__init__.py
Normal file
0
RoutesApp/management/commands/__init__.py
Normal file
36
RoutesApp/management/commands/every_1hour_start.py
Normal file
@@ -0,0 +1,36 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from datetime import datetime
|
||||
from BaseModels.mailSender import techSendMail
|
||||
from GeneralApp.funcs_options import get_options_by_opt_types, get_mail_send_options
|
||||
|
||||
class Command(BaseCommand):
|
||||
|
||||
def handle(self, *args, **options):
|
||||
mail_sets = get_mail_send_options()
|
||||
|
||||
log = ''
|
||||
log_begin_DT = datetime.now()
|
||||
msg = str(log_begin_DT)
|
||||
print('-------------')
|
||||
print(msg)
|
||||
|
||||
try:
|
||||
from ...search_matches import search_matches
|
||||
msg = search_matches()
|
||||
if msg:
|
||||
print(msg)
|
||||
except Exception as e:
|
||||
msg = f'every_1hour_start search_matches fail = {str(e)}'
|
||||
print(msg)
|
||||
techSendMail(mail_sets, msg, title='every_1hour_start search_matches')
|
||||
|
||||
|
||||
|
||||
if msg:
|
||||
techSendMail(mail_sets, str(msg), title='every_1hour_start get_competitors_prices')
|
||||
|
||||
|
||||
|
||||
print(f'- processing time = {str(datetime.now() - log_begin_DT)} -')
|
||||
|
||||
|
||||
13
RoutesApp/management/commands/fix_code.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from datetime import datetime
|
||||
|
||||
class Command(BaseCommand):
|
||||
|
||||
def handle(self, *args, **options):
|
||||
|
||||
# from B2BApp.funcs import assign_contracts_for_orders_by_tmp_data
|
||||
# log = assign_contracts_for_orders_by_tmp_data()
|
||||
from GeneralApp.views import test_code
|
||||
test_code(None)
|
||||
|
||||
self.stdout.write(u'fix_code end')
|
||||
@@ -24,8 +24,8 @@ cargo_type_choices = (
|
||||
)
|
||||
|
||||
owner_type_choices = (
|
||||
('customer', 'Заказчик'),
|
||||
('mover', 'Перевозчик')
|
||||
('customer', _('Заказчик')),
|
||||
('mover', _('Перевозчик'))
|
||||
)
|
||||
|
||||
|
||||
@@ -75,14 +75,14 @@ class Route(BaseModel):
|
||||
ordering = ('name',)
|
||||
|
||||
def from_country_n_city_str(self):
|
||||
res = 'Неизвестно'
|
||||
res = _('Неизвестно')
|
||||
if self.from_city:
|
||||
res = self.from_city.get_country_n_city_str()
|
||||
|
||||
return res
|
||||
|
||||
def to_country_n_city_str(self):
|
||||
res = 'Неизвестно'
|
||||
res = _('Неизвестно')
|
||||
if self.to_city:
|
||||
res = self.to_city.get_country_n_city_str()
|
||||
|
||||
@@ -111,8 +111,8 @@ class Route(BaseModel):
|
||||
to_address_point_Dict = to_address_point_objs.values(
|
||||
'id', 'name', 'country__name')[0]
|
||||
|
||||
from_address_point_txt = f'{from_address_point_Dict["country__name"]} / {from_address_point_Dict["name"]}'
|
||||
to_address_point_txt = f'{to_address_point_Dict["country__name"]} / {to_address_point_Dict["name"]}'
|
||||
from_address_point_txt = f'{from_address_point_Dict["name"]} / {from_address_point_Dict["country__name"]}'
|
||||
to_address_point_txt = f'{to_address_point_Dict["name"]} / {to_address_point_Dict["country__name"]}'
|
||||
|
||||
return {
|
||||
'from_address_point_obj': from_address_point_objs[0],
|
||||
|
||||
145
RoutesApp/search_matches.py
Normal file
@@ -0,0 +1,145 @@
|
||||
from .models import *
|
||||
from datetime import datetime, timedelta
|
||||
from django.utils.translation import gettext as _
|
||||
from django.template.loader import render_to_string
|
||||
from GeneralApp.funcs_options import get_options_by_opt_types, get_mail_send_options
|
||||
from BaseModels.mailSender import admin_send_mail_by_SMTPlib, techSendMail
|
||||
|
||||
|
||||
|
||||
def get_Dict_for_send_msgs(kwargs, search_owner_type):
|
||||
print('get_Dict_for_send_msgs')
|
||||
|
||||
Dict = {
|
||||
'search_owner_type': search_owner_type
|
||||
}
|
||||
sets = get_options_by_opt_types(['domain', 'project_name'], only_vals=True)
|
||||
Dict.update(sets)
|
||||
|
||||
|
||||
Dict.update({'logo': f'{sets["domain"]}/static/img/svg/LogoMobile.svg', })
|
||||
|
||||
find_routes_page_url = f'{sets["domain"]}/routes/route_search_results/?'
|
||||
kwargs_list = [f'{key}={value}' for key, value in kwargs.items()]
|
||||
kwargs_list.append(f'owner_type={search_owner_type}')
|
||||
find_routes_page_url += f'{"&".join(kwargs_list)}'
|
||||
|
||||
Dict.update({'find_routes_page_url': find_routes_page_url})
|
||||
|
||||
return Dict
|
||||
|
||||
|
||||
|
||||
def send_push_message_for_found_matches_routes(route, data_Dict):
|
||||
print(f'send_push_message_for_found_matches_routes to route id = {route.id}')
|
||||
|
||||
if not route.owner.is_authenticated:
|
||||
return None
|
||||
|
||||
from PushMessages.views import send_push
|
||||
title = 'Мы нашли исполнителя по Вашему объявлению!'
|
||||
text = 'Для просмотра результата нажмите на кнопку ниже'
|
||||
send_push(route.owner, title, text, url=data_Dict['find_routes_page_url'], button_name=_('Перейти к найденному'))
|
||||
return None
|
||||
|
||||
|
||||
|
||||
def send_mail_found_matches_routes(route, data_Dict):
|
||||
print(f'send_mail_found_matches_routes to route id = {route.id}')
|
||||
|
||||
Dict = {
|
||||
'route': route,
|
||||
}
|
||||
Dict.update(data_Dict)
|
||||
|
||||
html = render_to_string('mail/m_found_matched_routes.html', Dict)
|
||||
|
||||
|
||||
mail_sets = get_mail_send_options()
|
||||
to = [route.owner.email, 'web@syncsystems.net']
|
||||
subject = _('Мы нашли исполнителя по Вашему объявлению!')
|
||||
res = admin_send_mail_by_SMTPlib(
|
||||
mail_sets,
|
||||
subject=subject,
|
||||
from_email=mail_sets['sender_email'], to=to,
|
||||
html_content=html
|
||||
)
|
||||
|
||||
return res
|
||||
|
||||
|
||||
def search_matches(for_routes=None):
|
||||
print('search_matches')
|
||||
|
||||
log = ''
|
||||
|
||||
try:
|
||||
if not for_routes:
|
||||
for_routes = Route.objects.filter(
|
||||
createDT__gte=datetime.now() - timedelta(hours=1),
|
||||
receive_msg_by_email=True
|
||||
)
|
||||
|
||||
check_fields = [
|
||||
'type_transport', 'departure_DT', 'arrival_DT', 'from_address_point', 'to_address_point',
|
||||
'from_place', 'to_place', 'cargo_type', 'weight'
|
||||
]
|
||||
|
||||
if for_routes:
|
||||
msg = f'last hour create routes count = {for_routes.count()}'
|
||||
else:
|
||||
msg = f'last hour not create routes'
|
||||
print(msg)
|
||||
|
||||
for route in for_routes:
|
||||
kwargs = {}
|
||||
params = {}
|
||||
|
||||
for field_name in check_fields:
|
||||
field_val = getattr(route, field_name, None)
|
||||
if field_val:
|
||||
if type(field_val) == datetime:
|
||||
params.update({f"{field_name}": f'{field_val.strftime("%d.%m.%Y")} - {field_val.strftime("%d.%m.%Y")}'})
|
||||
kwargs.update({f"{field_name}__date": field_val.date()})
|
||||
elif field_name == 'weight':
|
||||
# print(field_name)
|
||||
params.update({f"{field_name}": field_val})
|
||||
if route.owner_type == 'mover':
|
||||
kwargs.update({f"{field_name}__lte": field_val})
|
||||
else:
|
||||
kwargs.update({f"{field_name}__gte": field_val})
|
||||
else:
|
||||
kwargs.update({field_name: field_val})
|
||||
params.update({field_name: field_val})
|
||||
|
||||
found_routes = Route.objects.exclude(
|
||||
id=route.id,
|
||||
).exclude(
|
||||
owner=route.owner
|
||||
).exclude(
|
||||
owner_type=route.owner_type
|
||||
).filter(
|
||||
**kwargs
|
||||
# ).count(
|
||||
)
|
||||
|
||||
if found_routes:
|
||||
msg = f'found routes for send messages = {found_routes.count()}'
|
||||
|
||||
data_Dict = get_Dict_for_send_msgs(params, found_routes[0].owner_type)
|
||||
msg = send_push_message_for_found_matches_routes(route, data_Dict)
|
||||
if msg:
|
||||
log += msg
|
||||
msg = send_mail_found_matches_routes(route, data_Dict)
|
||||
if msg:
|
||||
log += msg
|
||||
|
||||
except Exception as e:
|
||||
msg = f'<br>\n! search_matches Error = {str(e)}'
|
||||
print(msg)
|
||||
log += msg
|
||||
|
||||
mail_sets = get_mail_send_options()
|
||||
techSendMail(mail_sets, log, title='search_matches fail')
|
||||
|
||||
return log
|
||||
@@ -32,7 +32,8 @@ def route_search_results_View(request):
|
||||
'show_filter_and_results': True,
|
||||
'owner_type': data['owner_type'],
|
||||
'last_el': routes_Dict['last_el'],
|
||||
'page_type': 'routes'
|
||||
'page_type': 'routes',
|
||||
'next_page_els_count': routes_Dict['next_page_els_count'],
|
||||
}
|
||||
if 'from_address_point_txt' in routes_Dict:
|
||||
data.update({'from_address_point_txt': routes_Dict['from_address_point_txt']})
|
||||
@@ -40,6 +41,20 @@ def route_search_results_View(request):
|
||||
data.update({'to_address_point_txt': routes_Dict['to_address_point_txt']})
|
||||
Dict.update({'route_form': RouteForm(initial=data)})
|
||||
|
||||
title = _('Результат поиска маршрутов')
|
||||
if 'from_address_point_txt' in data:
|
||||
title = f'{title} из {data["from_address_point_txt"]}'
|
||||
if 'to_address_point_txt' in data:
|
||||
title = f'{title} в {data["to_address_point_txt"]}'
|
||||
|
||||
Dict.update({
|
||||
'page': {
|
||||
'title': title,
|
||||
'description': title,
|
||||
'keywords': title,
|
||||
}
|
||||
})
|
||||
|
||||
t = loader.get_template('pages/p_results_find_route.html')
|
||||
return get_inter_http_respose(t, Dict, request)
|
||||
# return HttpResponse(t.render(Dict, request))
|
||||
|
||||
@@ -6,7 +6,7 @@ class Admin_Subscribe(Admin_Trans_BaseModel):
|
||||
fieldsets = (
|
||||
(None, {
|
||||
'classes': ['wide'],
|
||||
'fields': ('name',
|
||||
'fields': ('name', 'enable',
|
||||
('price'),
|
||||
'options',
|
||||
'period_name', 'period',
|
||||
@@ -18,12 +18,13 @@ class Admin_Subscribe(Admin_Trans_BaseModel):
|
||||
|
||||
list_display = [
|
||||
'id',
|
||||
'name', 'price',
|
||||
'name', 'enable', 'price',
|
||||
'period_name', 'period',
|
||||
'order', 'modifiedDT', 'createDT'
|
||||
]
|
||||
|
||||
list_display_links = ['id']
|
||||
list_editable = ['enable']
|
||||
|
||||
list_filter = ['modifiedDT', 'createDT']
|
||||
search_fields = ['name', 'period_name']
|
||||
@@ -37,16 +38,18 @@ class Admin_SubscribeOption(Admin_Trans_BaseModel):
|
||||
(None, {
|
||||
'classes': ['wide'],
|
||||
'fields': ('name',
|
||||
'order'
|
||||
'order',
|
||||
'enable'
|
||||
)
|
||||
}),
|
||||
)
|
||||
|
||||
list_display = [
|
||||
'id',
|
||||
'id', 'enable',
|
||||
'name',
|
||||
'order', 'modifiedDT', 'createDT'
|
||||
]
|
||||
list_editable = ['enable']
|
||||
|
||||
list_display_links = ['id']
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
# Generated by Django 4.2.2 on 2023-11-30 13:42
|
||||
|
||||
import colorfield.fields
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('SubscribesApp', '0002_alter_subscribeoption_options_subscribe_bg_color_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='subscribe',
|
||||
name='bg_color',
|
||||
field=colorfield.fields.ColorField(default='#FFFFFF', image_field=None, max_length=25, samples=None, verbose_name='Цвет фона'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='subscribe',
|
||||
name='text_color',
|
||||
field=colorfield.fields.ColorField(default='#000000', image_field=None, max_length=25, samples=None, verbose_name='Цвет текста'),
|
||||
),
|
||||
]
|
||||
7
SubscribesApp/serializers.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from rest_framework import serializers
|
||||
|
||||
|
||||
class SubscribersSerializer(serializers.Serializer):
|
||||
email = serializers.EmailField(error_messages={'invalid': 'Invalid email'})
|
||||
email_notification = serializers.BooleanField()
|
||||
auto_subscribe = serializers.BooleanField()
|
||||
9
SubscribesApp/urls.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from django.urls import path
|
||||
|
||||
from SubscribesApp.views import SubscribersView
|
||||
|
||||
urlpatterns = [
|
||||
|
||||
path('auto-subscribe/', SubscribersView.as_view(), name='auto_subscribe'),
|
||||
|
||||
]
|
||||
@@ -1,3 +1,43 @@
|
||||
from django.shortcuts import render
|
||||
from django.contrib.auth.models import User
|
||||
from django.http import JsonResponse
|
||||
from rest_framework import status
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.views import APIView
|
||||
|
||||
# Create your views here.
|
||||
from SubscribesApp.models import SubscribeForUser
|
||||
from SubscribesApp.serializers import SubscribersSerializer
|
||||
|
||||
|
||||
class SubscribersView(APIView):
|
||||
# permission_classes = [IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
serializer = SubscribersSerializer(data=request.data)
|
||||
|
||||
if serializer.is_valid():
|
||||
validated_data = serializer.validated_data
|
||||
email = validated_data['email']
|
||||
email_notification = validated_data['email_notification']
|
||||
auto_subscribe = validated_data['auto_subscribe']
|
||||
|
||||
user = User.objects.filter(email=email)
|
||||
|
||||
if user:
|
||||
|
||||
subscribe_for_user = SubscribeForUser.objects.filter(user_id=user[0].id)
|
||||
|
||||
if email_notification:
|
||||
subscribe_for_user.update(receive_finish_subscribe_msg=True)
|
||||
else:
|
||||
subscribe_for_user.update(receive_finish_subscribe_msg=False)
|
||||
|
||||
if auto_subscribe:
|
||||
subscribe_for_user.update(auto_continue=True)
|
||||
else:
|
||||
subscribe_for_user.update(auto_continue=False)
|
||||
|
||||
return JsonResponse({"message": "Subscriptions updated successfully"}, status=status.HTTP_200_OK)
|
||||
else:
|
||||
return JsonResponse({"message": "User not found"}, status=status.HTTP_404_NOT_FOUND)
|
||||
else:
|
||||
return JsonResponse(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
13
TWB/asgi.py
@@ -22,11 +22,14 @@ os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'TWB.settings')
|
||||
|
||||
application = ProtocolTypeRouter({
|
||||
'http': get_asgi_application(),
|
||||
"websocket": QueryAuthMiddleware(
|
||||
URLRouter(
|
||||
websocket_urlpatterns
|
||||
)
|
||||
),
|
||||
"websocket":
|
||||
# AllowedHostsOriginValidator(
|
||||
QueryAuthMiddleware(
|
||||
URLRouter(
|
||||
websocket_urlpatterns
|
||||
)
|
||||
# )
|
||||
),
|
||||
# 'websocket': AuthMiddlewareStack(
|
||||
# URLRouter(
|
||||
# websocket_urlpatterns
|
||||
|
||||
27
TWB/celery.py
Executable file
@@ -0,0 +1,27 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
import os
|
||||
|
||||
from celery import Celery
|
||||
from celery.schedules import crontab
|
||||
from django.conf import settings
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "TWB.settings")
|
||||
|
||||
app = Celery('bo', include=['TWB.tasks'])
|
||||
app.config_from_object('django.conf:settings', namespace='CELERY')
|
||||
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
|
||||
|
||||
app.conf.beat_schedule = {
|
||||
'update-currency-rates': {
|
||||
'task': 'TWB.tasks.check_auto_subscribe',
|
||||
'schedule': crontab(minute=0, hour='*/1'),
|
||||
},
|
||||
'subscription_expiration_check': {
|
||||
'task': 'TWB.tasks.subscription_expiration_check',
|
||||
'schedule': crontab(hour=0, minute=0),
|
||||
# 'schedule': crontab(minute='*', hour='*'),
|
||||
},
|
||||
}
|
||||
|
||||
app.conf.broker_url = settings.CELERY_BROKER_URL
|
||||
@@ -11,10 +11,13 @@ https://docs.djangoproject.com/en/4.2/ref/settings/
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
from decouple import config
|
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
||||
CSRF_TRUSTED_ORIGINS = ['https://tripwb.com']
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
|
||||
@@ -28,6 +31,50 @@ DEBUG = True
|
||||
ALLOWED_HOSTS = ["*"]
|
||||
|
||||
|
||||
WEBPUSH_SETTINGS = {
|
||||
"VAPID_PUBLIC_KEY": "BKS8byh3MucwCF2h06JY9oey1s1RYII09j-j3ehI3qTYhs965UHv0qNPl-jFjQBbIJCvjVXm9RW6t_oJJK8yMOk",
|
||||
"VAPID_PRIVATE_KEY": "f5NMgOntBtRqsyeKwEzloK-051ggMnZGF_GFimERY0w",
|
||||
"VAPID_ADMIN_EMAIL": "admin@tripwb.com"
|
||||
}
|
||||
|
||||
|
||||
SOCIALACCOUNT_LOGIN_ON_GET=True
|
||||
ACCOUNT_DEFAULT_HTTP_PROTOCOL='https'
|
||||
|
||||
ACCOUNT_EMAIL_REQUIRED = True
|
||||
ACCOUNT_USERNAME_REQUIRED = False
|
||||
ACCOUNT_AUTHENTICATION_METHOD = 'email'
|
||||
ACCOUNT_EMAIL_VERIFICATION = 'optional'
|
||||
LOGIN_REDIRECT_URL = '/profile/page/dashboard/'
|
||||
LOGIN_URL = '/profile/login/'
|
||||
|
||||
LOGOUT_REDIRECT_URL = '/profile/login/'
|
||||
|
||||
ACCOUNT_SIGNUP_REDIRECT_URL = '/profile/page/dashboard/'
|
||||
ACCOUNT_LOGOUT_ON_GET = True
|
||||
# SOCIALACCOUNT_ADAPTER = 'GeneralApp.allauth_funcs.MyAccountAdapter'
|
||||
ACCOUNT_ADAPTER = 'GeneralApp.allauth_funcs.MyAccountAdapter'
|
||||
|
||||
AUTHENTICATION_BACKENDS = [
|
||||
'django.contrib.auth.backends.ModelBackend',
|
||||
'allauth.account.auth_backends.AuthenticationBackend',
|
||||
]
|
||||
|
||||
|
||||
SOCIALACCOUNT_PROVIDERS = {
|
||||
'google': {
|
||||
'SCOPE': [
|
||||
'profile',
|
||||
'email',
|
||||
],
|
||||
'AUTH_PARAMS': {
|
||||
'access_type': 'online',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
# NOTIFICATION_KEY = 'BJLyGzmo8sLI3Qkc6pN2cz11frCXiJdewvgve7Yps-_fM1lY1LSnTQfQxYtAgQ_26nAji_rgeYC1DkLiTwxw0Mo'
|
||||
|
||||
# SESSION_COOKIE_HTTPONLY = False
|
||||
|
||||
# Application definition
|
||||
@@ -46,17 +93,27 @@ INSTALLED_APPS = [
|
||||
'django.contrib.staticfiles',
|
||||
'django.contrib.humanize',
|
||||
|
||||
'django.contrib.sites',
|
||||
|
||||
'colorfield',
|
||||
|
||||
'ckeditor',
|
||||
'ckeditor_uploader',
|
||||
|
||||
'webpush',
|
||||
|
||||
'allauth',
|
||||
'allauth.account',
|
||||
'allauth.socialaccount',
|
||||
'allauth.socialaccount.providers.google',
|
||||
|
||||
'GeneralApp',
|
||||
'AuthApp',
|
||||
'RoutesApp',
|
||||
'ReferenceDataApp',
|
||||
'ArticlesApp',
|
||||
'SubscribesApp',
|
||||
'PushMessages',
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
@@ -69,8 +126,14 @@ MIDDLEWARE = [
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
'AuthApp.middleware.ResponseInterceptionMiddleware',
|
||||
'TWB.tz_middelware.TimezoneMiddleware',
|
||||
# 'tz_detect.middleware.TimezoneMiddleware',
|
||||
|
||||
"allauth.account.middleware.AccountMiddleware",
|
||||
]
|
||||
|
||||
SITE_ID = 1
|
||||
|
||||
ROOT_URLCONF = 'TWB.urls'
|
||||
|
||||
TEMPLATES = [
|
||||
@@ -109,11 +172,8 @@ CHANNEL_LAYERS = {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
POSTGRES_DB = config('POSTGRES_DB')
|
||||
POSTGRES_USER = config('POSTGRES_USER')
|
||||
|
||||
|
||||
# Database
|
||||
@@ -122,8 +182,8 @@ CHANNEL_LAYERS = {
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.postgresql_psycopg2',
|
||||
'NAME': 'twbDB',
|
||||
'USER': 'test_user',
|
||||
'NAME': POSTGRES_DB,
|
||||
'USER': POSTGRES_USER,
|
||||
'PASSWORD': 'test_db_pass',
|
||||
'HOST': '127.0.0.1',
|
||||
'PORT': '5432',
|
||||
@@ -209,6 +269,7 @@ django.conf.locale.LANG_INFO = LANG_INFO
|
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||
|
||||
DATA_UPLOAD_MAX_MEMORY_SIZE = 4145728
|
||||
|
||||
CKEDITOR_BASEPATH = "/static/ckeditor/ckeditor/"
|
||||
CKEDITOR_UPLOAD_PATH = "uploads/"
|
||||
@@ -216,7 +277,9 @@ CKEDITOR_RESTRICT_BY_DATE = False
|
||||
CKEDITOR_RESTRICT_BY_USER = True
|
||||
CKEDITOR_BROWSE_SHOW_DIRS = True
|
||||
|
||||
CKEDITOR_IMAGE_BACKEND = "pillow"
|
||||
# CKEDITOR_IMAGE_BACKEND = 'ckeditor_uploader.backends.PillowBackend'
|
||||
# CKEDITOR_IMAGE_BACKEND = 'pillow'
|
||||
CKEDITOR_IMAGE_BACKEND = "BaseModels.PIL.pillow_backend.PillowBackend"
|
||||
|
||||
# CKEDITOR_BROWSE_SHOW_DIRS = True
|
||||
|
||||
@@ -231,6 +294,10 @@ CKEDITOR_CONFIGS = {
|
||||
'toolbar': 'Custom',
|
||||
'forcePasteAsPlainText': True,
|
||||
'allowedContent': True,
|
||||
|
||||
'filebrowserImageThumbWidth': 300,
|
||||
'filebrowserImageThumbHeight': 300,
|
||||
'filebrowserUploadUrl': '/ckeditor/upload/',
|
||||
# 'disallowedContent': 'img{width,height};img[width,height]',
|
||||
# 'extraPlugins': 'image2',
|
||||
|
||||
@@ -266,6 +333,16 @@ CKEDITOR_CONFIGS = {
|
||||
}
|
||||
}
|
||||
|
||||
CELERY_BROKER_URL = config('CELERY_BROKER_URL')
|
||||
CELERY_RESULT_BACKEND = config('CELERY_RESULT_BACKEND')
|
||||
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
||||
EMAIL_HOST = 'smtp.gmail.com'
|
||||
EMAIL_USE_TLS = True
|
||||
EMAIL_PORT = 587
|
||||
EMAIL_HOST_USER = config('EMAIL_HOST_USER')
|
||||
EMAIL_HOST_PASSWORD = config('EMAIL_HOST_PASSWORD')
|
||||
|
||||
|
||||
# CKEDITOR_OPTIONS = {
|
||||
# 'height': 291,
|
||||
|
||||
40
TWB/tasks.py
Normal file
@@ -0,0 +1,40 @@
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
from SubscribesApp.models import SubscribeForUser
|
||||
from TWB import settings
|
||||
from TWB.celery import app
|
||||
from django.core.mail import send_mail
|
||||
|
||||
|
||||
@app.task
|
||||
def check_auto_subscribe():
|
||||
current_time = datetime.now()
|
||||
subscribes = SubscribeForUser.objects.filter(auto_continue=True)
|
||||
if subscribes:
|
||||
for subscribe in subscribes:
|
||||
if subscribe.paid_period_to_DT and subscribe.paid_period_to_DT <= current_time + timedelta(hours=1):
|
||||
user_email = subscribe.user.email
|
||||
subject = 'Подписка продлена!'
|
||||
message = 'Ваша подписка успешно продлена!'
|
||||
send_mail(subject, message, settings.EMAIL_HOST_USER, [user_email], fail_silently=False)
|
||||
else:
|
||||
print('Нету подписок')
|
||||
|
||||
|
||||
@app.task
|
||||
def subscription_expiration_check():
|
||||
current_time = datetime.now()
|
||||
subscribes = SubscribeForUser.objects.filter(paid_period_to_DT__gte=current_time)
|
||||
if subscribes:
|
||||
for subscribe in subscribes:
|
||||
expiration_date = subscribe.paid_period_to_DT
|
||||
remaining_days = (expiration_date - current_time).days
|
||||
|
||||
if remaining_days <= 7:
|
||||
message = f'Ваша подписка заканчивается через {remaining_days} дня. Пожалуйста, продлите её.'
|
||||
|
||||
user_email = subscribe.user.email
|
||||
subject = 'Подписка истекает!'
|
||||
send_mail(subject, message, settings.EMAIL_HOST_USER, [user_email], fail_silently=False)
|
||||
else:
|
||||
print('Нету подписок')
|
||||
22
TWB/tz_middelware.py
Normal file
@@ -0,0 +1,22 @@
|
||||
import zoneinfo
|
||||
from django.utils import timezone
|
||||
from django.shortcuts import render
|
||||
|
||||
class TimezoneMiddleware:
|
||||
def __init__(self, get_response):
|
||||
self.get_response = get_response
|
||||
|
||||
def __call__(self, request):
|
||||
tz = request.COOKIES.get("user_tz")
|
||||
if tz:
|
||||
if request.user.is_authenticated:
|
||||
if not 'user_timezone' in request.user.user_profile.json_data or request.user.user_profile.json_data['user_timezone'] != tz:
|
||||
request.user.user_profile.json_data['user_timezone'] = tz
|
||||
request.user.user_profile.save(update_fields=['json_data'])
|
||||
|
||||
msg = f'user={str(request.user.id)} tz={str(tz)}'
|
||||
print(msg)
|
||||
timezone.activate(zoneinfo.ZoneInfo(tz))
|
||||
else:
|
||||
timezone.activate(zoneinfo.ZoneInfo("UTC"))
|
||||
return self.get_response(request)
|
||||
22
TWB/urls.py
@@ -1,18 +1,30 @@
|
||||
|
||||
from django.contrib import admin
|
||||
from django.urls import path, include
|
||||
from django.conf.urls.static import static
|
||||
from django.conf import settings
|
||||
from GeneralApp.views import Page404
|
||||
from AuthApp.views import login_View
|
||||
|
||||
handler404 = Page404
|
||||
|
||||
urlpatterns = [
|
||||
# path('admin/', admin.site.urls),
|
||||
path('ckeditor/', include('ckeditor_uploader.urls')),
|
||||
path('i18n/', include('django.conf.urls.i18n')),
|
||||
|
||||
# path('tz_detect/', include('tz_detect.urls')),
|
||||
|
||||
path('accounts/signup/', login_View, name='signup'),
|
||||
path('accounts/login/cancelled/', login_View),
|
||||
|
||||
path('accounts/', include('allauth.urls')),
|
||||
path('accounts/', include('allauth.socialaccount.urls')),
|
||||
|
||||
path('messages/', include('ChatServiceApp.urls')),
|
||||
|
||||
path('user_account/', include('AuthApp.js_urls')),
|
||||
|
||||
|
||||
|
||||
path('routes/', include('RoutesApp.js_urls')),
|
||||
|
||||
path('subscribes/', include('SubscribesApp.js_urls')),
|
||||
@@ -22,6 +34,12 @@ urlpatterns = [
|
||||
path('reference_data/', include('ReferenceDataApp.js_urls')),
|
||||
|
||||
path('', include('ArticlesApp.js_urls')),
|
||||
|
||||
path('test_404', Page404, name='page_404'),
|
||||
|
||||
path('', include('PushMessages.urls')),
|
||||
path('', include('SubscribesApp.urls')),
|
||||
|
||||
]
|
||||
|
||||
from django.conf.urls.i18n import i18n_patterns
|
||||
|
||||
8
env.sample
Normal file
@@ -0,0 +1,8 @@
|
||||
EMAIL_HOST_USER=
|
||||
EMAIL_HOST_PASSWORD=
|
||||
|
||||
POSTGRES_DB=
|
||||
POSTGRES_USER=
|
||||
|
||||
CELERY_BROKER_URL=
|
||||
CELERY_RESULT_BACKEND=
|
||||
@@ -580,9 +580,9 @@ msgstr ""
|
||||
#: .\templates\blocks\static_pages_blocks\b_partners.html:18
|
||||
msgid ""
|
||||
"Вы можете разместить объявление о перевозке посылки и перевозчики со всего "
|
||||
"мира откликнуться на ваше объявление или воспользовавшись поиском на сайте "
|
||||
"мира откликнутся на ваше объявление или воспользовавшись поиском на сайте "
|
||||
"найти перевозчика, который будет готов взять Вашу посылку и доставить в "
|
||||
"указанное место авто- или авива транспортом."
|
||||
"указанное место наземным или авиатранспортом."
|
||||
msgstr ""
|
||||
|
||||
#: .\templates\blocks\static_pages_blocks\b_about_service.html:22
|
||||
|
||||
@@ -2,7 +2,6 @@ Django==4.2.2
|
||||
django-ckeditor==6.5.1
|
||||
psycopg2-binary==2.9.6
|
||||
requests
|
||||
Pillow
|
||||
django-modeltranslation==0.18.10
|
||||
overpass
|
||||
geopy
|
||||
@@ -10,4 +9,9 @@ channels==4.0.0
|
||||
daphne==4.0.0
|
||||
channels-redis==4.1.0
|
||||
django-colorfield
|
||||
|
||||
django-webpush==0.3.5
|
||||
django-allauth==0.60.0
|
||||
pytz==2024.1
|
||||
celery==5.3.6
|
||||
djangorestframework==3.14.0
|
||||
python-decouple==3.8
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
from BaseModels.admin_utils import Admin_GenericBaseIconStackedInline, Admin_BaseIconModel
|
||||
from BaseModels.admin_utils import Admin_GenericBaseIconStackedInline, Admin_BaseIconModel, GenericStackedInline
|
||||
from copy import deepcopy
|
||||
|
||||
class AdminStacked_FAQitem(Admin_GenericBaseIconStackedInline):
|
||||
from GeneralApp.models import FAQitem
|
||||
model = FAQitem
|
||||
extra = 0
|
||||
fields = ['order', 'question', 'answer']
|
||||
|
||||
|
||||
class Admin_BaseModel(Admin_BaseIconModel):
|
||||
pass
|
||||
@@ -68,6 +64,47 @@ class Admin_BaseBlock(Admin_BaseIconModel):
|
||||
fieldsets = super(Admin_BaseBlock, self).get_fieldsets(request, obj)
|
||||
return fieldsets
|
||||
|
||||
|
||||
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',),
|
||||
}
|
||||
|
||||
from modeltranslation.admin import TranslationGenericStackedInline
|
||||
class AdminStacked_FAQitem(TranslationGenericStackedInline):
|
||||
from GeneralApp.models import FAQitem
|
||||
model = FAQitem
|
||||
extra = 0
|
||||
fields = ['order', 'question', 'answer']
|
||||
|
||||
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_BaseModelViewPage(Admin_BaseIconModel):
|
||||
pass
|
||||
# def get_fieldsets(self, request, obj=None):
|
||||
@@ -92,31 +129,14 @@ class Admin_BaseModelViewPage(Admin_BaseIconModel):
|
||||
# else:
|
||||
# return {}
|
||||
#
|
||||
# inlines = [AdminStacked_FAQitem]
|
||||
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):
|
||||
@@ -127,3 +147,4 @@ class Admin_Trans_BaseModel(Admin_BaseModel, AdminTranslationBase):
|
||||
|
||||
class Admin_Trans_BaseModelViewPage(Admin_BaseModelViewPage, AdminTranslationBase):
|
||||
pass
|
||||
|
||||
|
||||
@@ -6,11 +6,13 @@
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
|
||||
.disp-none{
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.text-align-center{
|
||||
text-align: -moz-center;
|
||||
text-align: -webkit-center;
|
||||
width: 100%;
|
||||
|
||||
@@ -42,7 +44,7 @@
|
||||
}
|
||||
|
||||
.block_overlay.n_profile{
|
||||
height: 100%;
|
||||
height: 105%;
|
||||
width: 100%;
|
||||
/*background: rgba(39, 53, 62, 0.7);*/
|
||||
backdrop-filter: blur(6px);
|
||||
@@ -56,6 +58,8 @@
|
||||
width: 100%;
|
||||
/*background: rgba(39, 53, 62, 0.7);*/
|
||||
backdrop-filter: blur(6px);
|
||||
-webkit-backdrop-filter: blur(6px);
|
||||
-moz-backdrop-filter: blur(6px);
|
||||
z-index: 100;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
@@ -219,6 +223,7 @@
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
float: left;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.message-sprt-inf{
|
||||
@@ -236,7 +241,7 @@
|
||||
height: 62px;
|
||||
width: 100%;
|
||||
filter: drop-shadow(-1px 4px 10px rgba(198, 199, 203, 0.20)) drop-shadow(0px -1px 10px rgba(198, 199, 203, 0.20));
|
||||
border-radius: 3px;
|
||||
border-radius: 15px;
|
||||
margin-bottom: 5px;
|
||||
padding: 20px;
|
||||
}
|
||||
@@ -258,7 +263,7 @@
|
||||
width: calc(100% - 40px);
|
||||
height: 20px;
|
||||
filter: drop-shadow(-1px 4px 10px rgba(198, 199, 203, 0.20)) drop-shadow(0px -1px 10px rgba(198, 199, 203, 0.20));
|
||||
border-radius: 3px;
|
||||
border-radius: 15px;
|
||||
margin-bottom: 5px;
|
||||
/*min-width: unset;*/
|
||||
/*max-width: unset;*/
|
||||
@@ -281,8 +286,11 @@
|
||||
/*max-width: calc(80% - 40px);*/
|
||||
resize: none;
|
||||
padding: 20px;
|
||||
width: 85%;
|
||||
width: calc(100% - 117px);
|
||||
float: left;
|
||||
border-radius: 15px 0 0 15px;
|
||||
border: solid #E6E6E6;
|
||||
border-width: 1px 0 1px 1px;
|
||||
|
||||
}
|
||||
|
||||
@@ -301,13 +309,17 @@
|
||||
/*top: 39px;*/
|
||||
/*left: 93%;*/
|
||||
height: calc(100% - 20px);
|
||||
width: calc(15% - 60px);
|
||||
width: 55px;
|
||||
padding-top: 20px;
|
||||
padding-right: 20px;
|
||||
min-height: 220px;
|
||||
float: right;
|
||||
background: #FFFFFF;
|
||||
text-align: right;
|
||||
border-radius: 0 15px 15px 0;
|
||||
border: solid #E6E6E6;
|
||||
border-width: 1px 1px 1px 0px;
|
||||
|
||||
/*display: inline-block;*/
|
||||
}
|
||||
|
||||
@@ -326,6 +338,7 @@
|
||||
color: #FFFFFF;
|
||||
border-radius: 10px;
|
||||
float: left;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.attach-file-btn{
|
||||
@@ -402,8 +415,8 @@
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
position: absolute;
|
||||
top: 38%;
|
||||
left: 52%;
|
||||
top: 40%;
|
||||
left: 45%;
|
||||
}
|
||||
|
||||
.loader_chat_f_sw_chats.support.show{
|
||||
@@ -411,8 +424,8 @@
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 52%;
|
||||
top: 38%;
|
||||
left: 47%;
|
||||
}
|
||||
|
||||
.loader_chat_f_sw_chats{
|
||||
@@ -422,22 +435,41 @@
|
||||
.container-messenger{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.container-messenger.margin{
|
||||
margin-top: 25px
|
||||
}
|
||||
|
||||
.block-chat{
|
||||
width: 66%;
|
||||
height: 88vh;
|
||||
width: 63%;
|
||||
height: calc(100vh - 120px);
|
||||
border-radius: 10px;
|
||||
border: 1px solid #E6E6E6;
|
||||
background: #ffffff;
|
||||
box-shadow: -1px 4px 10px 0 rgba(198, 199, 203, 0.20), 0 -1px 10px 0 rgba(198, 199, 203, 0.20);
|
||||
float: right;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.block_loader_chat{
|
||||
width: 63%;
|
||||
height: calc(100vh - 120px);
|
||||
border-radius: 10px;
|
||||
border: none;
|
||||
background: none;
|
||||
box-shadow: none;
|
||||
float: right;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.block-chat.support{
|
||||
height: 86vh;
|
||||
height: calc(100vh - 154px);
|
||||
}
|
||||
|
||||
.block_loader_chat.support{
|
||||
height: calc(100vh - 154px);
|
||||
}
|
||||
|
||||
.block-list-of-users{
|
||||
@@ -453,7 +485,8 @@
|
||||
}
|
||||
|
||||
.bottom_part_of_chats{
|
||||
height: calc(100% - 39px);
|
||||
height: 100%;
|
||||
padding-bottom: 39px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@@ -464,6 +497,8 @@
|
||||
width: calc(100% - 40px);
|
||||
height: 60px;
|
||||
padding: 10px 20px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.header-chat-left-part{
|
||||
@@ -507,14 +542,15 @@
|
||||
}
|
||||
|
||||
.container-messages{
|
||||
height: calc(100% - 175px);
|
||||
height: calc(100% - 224px);
|
||||
width: 100%;
|
||||
/* transform: rotate(180deg); */
|
||||
overflow-y: auto;
|
||||
/* transform: scaleY(-1); */
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
padding-top: 70px;
|
||||
padding-bottom: 63px;
|
||||
margin-top: 100px;
|
||||
}
|
||||
|
||||
|
||||
@@ -531,7 +567,7 @@
|
||||
border: 1px solid #E6E6E6;
|
||||
padding: 0 20px 0 20px;
|
||||
position: absolute;
|
||||
bottom: 43px;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.footer-chat.hide{
|
||||
@@ -539,12 +575,12 @@
|
||||
}
|
||||
|
||||
.left-part-block-enter-message{
|
||||
width: 80%;
|
||||
width: calc(80% - 74px);
|
||||
float: left;
|
||||
}
|
||||
|
||||
.right-part-block-enter-message{
|
||||
width: 20%;
|
||||
width: 74px;
|
||||
float: right;
|
||||
padding-top: 11px;
|
||||
text-align: right;
|
||||
@@ -571,7 +607,7 @@
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
margin-bottom: 0;
|
||||
bottom: 6px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.attach-file-btn-message.loader{
|
||||
top: 10px;
|
||||
@@ -586,6 +622,8 @@
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
margin-left: 5px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.loader_show_message.show{
|
||||
@@ -718,21 +756,31 @@
|
||||
/*messenger with support*/
|
||||
|
||||
.name_ticket{
|
||||
width: 100%;
|
||||
width: 63%;
|
||||
filter: drop-shadow(-1px 4px 10px rgba(198, 199, 203, 0.20)) drop-shadow(0px -1px 10px rgba(198, 199, 203, 0.20));
|
||||
height: 40px;
|
||||
background: #FFFFFF;
|
||||
/*padding: 20px;*/
|
||||
/* padding: 20px; */
|
||||
margin-bottom: 5px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
float: right;
|
||||
position: relative;
|
||||
|
||||
}
|
||||
.name_ticket.w_100{
|
||||
width: 100%;
|
||||
}
|
||||
.name_ticket > span{
|
||||
padding: 10px;
|
||||
font-size: 16px;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
text-wrap: nowrap;
|
||||
overflow: hidden;
|
||||
overflow-wrap: normal;
|
||||
width: calc(100% - 18px);
|
||||
}
|
||||
|
||||
.insert_users{
|
||||
@@ -797,6 +845,7 @@
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
object-fit: cover;
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.block_text_message{
|
||||
@@ -806,6 +855,7 @@
|
||||
|
||||
.block_text_message.left{
|
||||
float: left;
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.block_text_message.right{
|
||||
@@ -909,6 +959,7 @@
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
padding: 13px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.container_form_search_carrier > form{
|
||||
@@ -966,6 +1017,48 @@
|
||||
padding: 20px 15.2px;
|
||||
border-radius: 10px 0 0 10px;
|
||||
width: calc(100% - 95px);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.from_address_point_txt.find_route.w_100{
|
||||
border: 1px solid #E6E6E6;
|
||||
width: calc(100% - 35px);
|
||||
}
|
||||
|
||||
.to_address_point_txt.post_route.w_100{
|
||||
border: 1px solid #E6E6E6;
|
||||
width: calc(100% - 35px);
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
.from_address_point_txt.find_route.first.w_100{
|
||||
width: calc(100% - 35px);
|
||||
border-right: 2px solid #E6E6E6;
|
||||
}
|
||||
|
||||
.from_address_point_txt.post_route.first.w_100{
|
||||
width: calc(100% - 35px);
|
||||
border-right: 1px solid #E6E6E6;
|
||||
}
|
||||
|
||||
.to_address_point_txt.post_route.first.w_100{
|
||||
width: calc(100% - 35px);
|
||||
border-right: 1px solid #E6E6E6;
|
||||
}
|
||||
|
||||
.to_address_point_txt.post_route.first.w_100{
|
||||
width: calc(100% - 35px);
|
||||
border-right: 1px solid #E6E6E6;
|
||||
}
|
||||
|
||||
.to_address_point_txt.find_route.w_100{
|
||||
border: 1px solid #E6E6E6;
|
||||
width: calc(100% - 35px);
|
||||
}
|
||||
|
||||
.to_address_point_txt.find_route.first.w_100{
|
||||
width: calc(100% - 35px);
|
||||
border-right: 1px solid #E6E6E6;
|
||||
}
|
||||
|
||||
.to_address_point_txt.find_route{
|
||||
@@ -981,26 +1074,37 @@
|
||||
background-image: none !important;
|
||||
margin-top: 0;
|
||||
padding: 20px 15.2px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
|
||||
.input_list.find_route{
|
||||
width: 100%;
|
||||
/* display: block; */
|
||||
border-radius: 0 10px;
|
||||
top: 61px;
|
||||
z-index: 12;
|
||||
width: 90%;
|
||||
/*display: block;*/
|
||||
border-radius: 0 0 10px 10px;
|
||||
top: 62px;
|
||||
left: 9px;
|
||||
z-index: 10000;
|
||||
|
||||
}
|
||||
|
||||
.input_list.find_route.show{
|
||||
display: block;
|
||||
border: 2px solid #E6E6E6;
|
||||
border-top: hidden;
|
||||
|
||||
}
|
||||
|
||||
.container_inp_w_abr{
|
||||
height: 66%;
|
||||
width: 98%;
|
||||
width: 99%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.block-find-route{
|
||||
min-height: 695px;
|
||||
}
|
||||
|
||||
.cont-el-form-search-carrier > button{
|
||||
width: 99%;
|
||||
border-radius: 10px;
|
||||
@@ -1023,11 +1127,12 @@
|
||||
border: 1px solid #E6E6E6;
|
||||
display: block;
|
||||
height: 20px;
|
||||
width: 88%;
|
||||
width: calc(100% - 26px);
|
||||
padding: 20px 10px;
|
||||
background: url(/static/img/svg/Calendar.svg) white 50%;
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 2% bottom 45%;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
|
||||
@@ -1056,11 +1161,13 @@
|
||||
padding: 0;
|
||||
color: #272424;
|
||||
font-family: Inter;
|
||||
font-size: 16px;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
margin-top: 0;
|
||||
padding-left: 10px;
|
||||
cursor: pointer;
|
||||
|
||||
}
|
||||
|
||||
.cont-el-form-search-carrier.last > select:focus-visible{
|
||||
@@ -1071,12 +1178,21 @@
|
||||
.abbreviation_airport_in_search{
|
||||
display: inline-block;
|
||||
float: left;
|
||||
height: 97%;
|
||||
width: 60px;
|
||||
border-top: 1px solid #E6E6E6;
|
||||
border-right: 1px solid #E6E6E6;
|
||||
border-bottom: 1px solid #E6E6E6;
|
||||
border-left: 0;
|
||||
cursor: text;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.abbreviation_airport_in_search.post_route{
|
||||
float: right;
|
||||
}
|
||||
|
||||
.abbreviation_airport_in_search.hide{
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
@@ -1091,14 +1207,14 @@
|
||||
|
||||
.cont-el-form-search-carrier > label{
|
||||
color: #27242499;
|
||||
padding-bottom: 10px;
|
||||
padding-top: 10px;
|
||||
display: block;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.cont-el-form-search-carrier.last > label{
|
||||
opacity: 0;
|
||||
}
|
||||
/*.cont-el-form-search-carrier.last > label{*/
|
||||
/* opacity: 0;*/
|
||||
/*}*/
|
||||
|
||||
|
||||
.block-filters-find-route {
|
||||
@@ -1116,7 +1232,7 @@
|
||||
overflow-y: auto;
|
||||
}
|
||||
.block_w_paging.routes{
|
||||
width: 68%;
|
||||
width: 71%;
|
||||
float: right;
|
||||
}
|
||||
|
||||
@@ -1127,8 +1243,8 @@
|
||||
}
|
||||
|
||||
.not_found_routes{
|
||||
width: 98%;
|
||||
height: 250px;
|
||||
width: 96%;
|
||||
min-height: 250px;
|
||||
background: #FFFFFF;
|
||||
box-shadow: -1px 4px 10px 0 rgba(198, 199, 203, 0.20), 0 -1px 10px 0 rgba(198, 199, 203, 0.20);
|
||||
position: relative;
|
||||
@@ -1246,7 +1362,7 @@
|
||||
|
||||
.line_inf_about_moving{
|
||||
width: 100%;
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.container_inf_about_moving.second{
|
||||
@@ -1318,7 +1434,7 @@
|
||||
}
|
||||
|
||||
.inf_carrier_icon{
|
||||
width: 10%;
|
||||
width: 25px;
|
||||
}
|
||||
|
||||
.phones_carrier_span.active{
|
||||
@@ -1381,6 +1497,17 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
a.open_inf_carrier{
|
||||
display: block;
|
||||
width: 88%;
|
||||
}
|
||||
|
||||
.show_contact_wrapper {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.open_inf_carrier:hover{
|
||||
background: #FF613A;
|
||||
color: #FFFFFF;
|
||||
@@ -1431,7 +1558,13 @@
|
||||
font-weight: 500;
|
||||
font-size: 20px;
|
||||
color: #272424;
|
||||
padding-bottom: 10px;
|
||||
|
||||
margin-bottom: 10px;
|
||||
/*border: 2px solid #FF613A;*/
|
||||
|
||||
border-radius: 10px;
|
||||
padding: 7px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.name_carrier{
|
||||
@@ -1451,7 +1584,7 @@
|
||||
|
||||
.arrow_inf_about_moving{
|
||||
position: relative;
|
||||
top: 19px;
|
||||
top: 10px;
|
||||
left: 18px;
|
||||
}
|
||||
|
||||
@@ -1478,7 +1611,7 @@
|
||||
.container_subscribe{
|
||||
width: 25%;
|
||||
border-radius: 10px;
|
||||
padding: 2%;
|
||||
padding: 19px;
|
||||
box-shadow: -1px 4px 10px 0 rgba(198, 199, 203, 0.20), 0 -1px 10px 0 rgba(198, 199, 203, 0.20);
|
||||
margin-right: 2%;
|
||||
margin-left: 2%;
|
||||
@@ -1838,6 +1971,7 @@
|
||||
width: 100%;
|
||||
color: #272424;
|
||||
margin-bottom: 20px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.method_transport{
|
||||
@@ -1887,6 +2021,7 @@
|
||||
.select_form_filters_find_route{
|
||||
width: 100%;
|
||||
margin-top: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.select_form_filters_find_route:focus-visible{
|
||||
outline: none;
|
||||
@@ -1996,7 +2131,7 @@
|
||||
|
||||
.button_profile_header{
|
||||
height: 50px;
|
||||
width: 150px;
|
||||
width: 155px;
|
||||
background: #FF613A;
|
||||
color: #FFF;
|
||||
/* Heading 5 */
|
||||
@@ -2083,6 +2218,7 @@
|
||||
object-fit: cover;
|
||||
height: 110px;
|
||||
width: 110px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.upload_photo_container{
|
||||
@@ -2135,6 +2271,10 @@
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.input_f_profile.grey{
|
||||
background: #F8F8F8;
|
||||
}
|
||||
|
||||
.status_f_profile{
|
||||
width: calc(100% - 120px);
|
||||
padding-left: 10px;
|
||||
@@ -2173,7 +2313,7 @@
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
display: block;
|
||||
padding-bottom: 10px;
|
||||
padding-top: 15px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
@@ -2223,11 +2363,11 @@
|
||||
/*p_main news*/
|
||||
|
||||
.news_description{
|
||||
/*background: linear-gradient(45deg, #040404 33%, #c5c5c5 66%, #ffffff);*/
|
||||
/*-webkit-background-clip: text;*/
|
||||
/*-webkit-text-fill-color: transparent;*/
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
background: linear-gradient(180deg, #040404 46%, #ffffff 72%, #ffffff);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
.menu_buttons.right.close{
|
||||
@@ -2256,6 +2396,22 @@
|
||||
height: 695px;
|
||||
}
|
||||
|
||||
.cut_width_f_curtain.n_profile.right{
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.cut_width_f_curtain.n_profile.close{
|
||||
display: none;
|
||||
min-width: 1280px;
|
||||
}
|
||||
|
||||
.cut_width_f_curtain.n_profile.open{
|
||||
display: block;
|
||||
/*min-width: 1280px;*/
|
||||
right: calc((100vw - 1280px) / 2)
|
||||
}
|
||||
|
||||
|
||||
.cut_width_f_curtain.left{
|
||||
max-width: 1280px;
|
||||
text-align: -webkit-right;
|
||||
@@ -2267,6 +2423,27 @@
|
||||
height: 695px;
|
||||
}
|
||||
|
||||
.menu_buttons.left::-webkit-scrollbar-track{
|
||||
background-color: #F6F6F6;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.menu_buttons.left::-webkit-scrollbar-thumb{
|
||||
background-color: #989898;
|
||||
border-radius: 3px;
|
||||
width: 3px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.menu_buttons.left::-webkit-scrollbar{
|
||||
background-color:#FF613A;
|
||||
width: 4px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.menu_buttons{
|
||||
/*background: #FFFFFF;*/
|
||||
/*height: 100vh;*/
|
||||
@@ -2278,19 +2455,40 @@
|
||||
|
||||
}
|
||||
|
||||
.menu_buttons.curtain.left.close.chat{
|
||||
/*left: 0;/*/
|
||||
transition: 200ms;
|
||||
/* position: fixed; */
|
||||
padding-top: 10px;
|
||||
width: 320px;
|
||||
background: #FFFFFF;
|
||||
border-radius: 10px;
|
||||
max-height: calc(100vh - 125px);
|
||||
overflow: unset;
|
||||
left: -19px;
|
||||
top: 0;
|
||||
}
|
||||
.menu_buttons.curtain.left.close.chat .container_block_list_of_users {
|
||||
position: relative;
|
||||
left: 0;
|
||||
transition: 200ms;
|
||||
}
|
||||
.menu_profile::-webkit-scrollbar-track{
|
||||
background-color: #F6F6F6;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.menu_profile::-webkit-scrollbar-thumb{
|
||||
background-color: #989898;
|
||||
border-radius: 3px;
|
||||
width: 3px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.menu_profile::-webkit-scrollbar{
|
||||
background-color:#FF613A;
|
||||
width: 4px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
@@ -2333,9 +2531,15 @@
|
||||
width: 320px;
|
||||
top: 0;
|
||||
border-radius: 10px;
|
||||
padding-top: 8px;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.menu_buttons.right.open .menu_profile{
|
||||
padding-top: 30px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.menu_buttons.left.open{
|
||||
left: 0;
|
||||
transition: 200ms;
|
||||
@@ -2345,16 +2549,28 @@
|
||||
width: 33%;
|
||||
background: #FFFFFF;
|
||||
border-radius: 10px;
|
||||
max-height: 83vh;
|
||||
max-height: calc(100vh - 125px);
|
||||
|
||||
}
|
||||
|
||||
.support .menu_buttons.left.open{
|
||||
max-height: calc(100vh - 120px);
|
||||
|
||||
}
|
||||
|
||||
.support .menu_buttons.left.open.margin{
|
||||
margin-top: 49px;
|
||||
max-height: calc(100vh - 215px);
|
||||
}
|
||||
|
||||
|
||||
|
||||
.menu_buttons.left.open.filters{
|
||||
width: 294px;
|
||||
background: #FFFFFF;
|
||||
border-radius: 10px;
|
||||
max-height: 83vh;
|
||||
left: 0;
|
||||
left: 19px;
|
||||
padding: 13px;
|
||||
/* position: fixed; */
|
||||
float: left;
|
||||
@@ -2362,11 +2578,9 @@
|
||||
position: absolute;
|
||||
top: 293px;
|
||||
transition: 0ms;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.support .menu_buttons.left.open{
|
||||
margin-top: 49px;
|
||||
}
|
||||
|
||||
.handler_menu.left.close{
|
||||
background: #FF613A;
|
||||
@@ -2383,6 +2597,11 @@
|
||||
color: #000000;
|
||||
left: 272px;
|
||||
}
|
||||
.menu_buttons.left.open.first.filters .handler_menu{
|
||||
background: #FF613A;
|
||||
color: #FFFFFF;
|
||||
left: -49px;
|
||||
}
|
||||
.menu_buttons.right.open .handler_menu{
|
||||
background: #FFFFFF;
|
||||
color: #000000;
|
||||
@@ -2437,6 +2656,11 @@
|
||||
filter: brightness(0) saturate(100%) invert(100%) sepia(2%) saturate(0%) hue-rotate(162deg) brightness(104%) contrast(103%);
|
||||
padding-right: 10px;
|
||||
}
|
||||
.menu_buttons.close .text_f_curtain > img{
|
||||
transition: 200ms;
|
||||
transform: rotate(270deg);
|
||||
filter: brightness(0) saturate(100%) invert(100%) sepia(2%) saturate(0%) hue-rotate(162deg) brightness(104%) contrast(103%);
|
||||
}
|
||||
.menu_buttons.open .btns_f_curtain{
|
||||
transition: 200ms;
|
||||
transform: rotate(90deg);
|
||||
@@ -2444,6 +2668,28 @@
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.menu_buttons.open .text_f_curtain > img{
|
||||
transition: 200ms;
|
||||
transform: rotate(270deg);
|
||||
filter: brightness(0) saturate(100%) invert(0%) sepia(100%) saturate(21%) hue-rotate(344deg) brightness(105%) contrast(106%);
|
||||
}
|
||||
|
||||
.menu_buttons.left.open.first.filters .btns_f_curtain{
|
||||
transition: 200ms;
|
||||
transform: rotate(270deg);
|
||||
filter: brightness(0) saturate(100%) invert(100%) sepia(2%) saturate(0%) hue-rotate(162deg) brightness(104%) contrast(103%);
|
||||
padding-left: 10px;
|
||||
position: relative;
|
||||
top: 10px;
|
||||
}
|
||||
|
||||
.menu_buttons.left.open.first.filters .text_f_curtain > img{
|
||||
transition: 200ms;
|
||||
transform: rotate(270deg) translate(0, 0);
|
||||
filter: brightness(0) saturate(100%) invert(100%) sepia(2%) saturate(0%) hue-rotate(162deg) brightness(104%) contrast(103%);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.text_f_curtain{
|
||||
display: inline-block;
|
||||
}
|
||||
@@ -2451,12 +2697,13 @@
|
||||
.menu_profile{
|
||||
width: 320px;
|
||||
text-align: -webkit-center;
|
||||
padding: 14px 0;
|
||||
text-align: -moz-center;
|
||||
padding: 0;
|
||||
overflow-y: auto;
|
||||
height: calc(100vh - 120px);
|
||||
max-height: 667px;
|
||||
height: calc(100vh - 95px);
|
||||
max-height: 697px;
|
||||
background: #F8F8F8;
|
||||
direction: rtl;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.menu_profile.background{
|
||||
@@ -2481,10 +2728,19 @@
|
||||
/* direction: initial;*/
|
||||
/*}*/
|
||||
.menu_profile>div>a{
|
||||
font-size: 12px;
|
||||
/*font-size: 12px;*/
|
||||
line-height: 13px;
|
||||
}
|
||||
|
||||
.menu_profile>div>.logout{
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
.logout_span{
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
left: 42%;
|
||||
}
|
||||
/*left panel of users*/
|
||||
|
||||
.menu_buttons.left.close .container_block_list_of_users{
|
||||
@@ -2530,6 +2786,7 @@
|
||||
aspect-ratio: 4/3;
|
||||
height: 225px;
|
||||
object-fit: cover;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.cont_content_one_news{
|
||||
@@ -2544,13 +2801,16 @@
|
||||
.container_descript_one_news{
|
||||
width: 100%;
|
||||
overflow-wrap: break-word;
|
||||
background: linear-gradient(180deg, #040404 46%, #ffffff 72%, #ffffff);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
.container_name_one_news{
|
||||
width: 100%;
|
||||
overflow-wrap: break-word;
|
||||
font-weight: 600;
|
||||
padding-bottom: 20px;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
/* checkbox type transport*/
|
||||
@@ -2601,20 +2861,108 @@
|
||||
|
||||
}
|
||||
|
||||
.block_overlay.show.routes{
|
||||
display: none;
|
||||
}
|
||||
/*.block_overlay.show.routes{*/
|
||||
/* display: none;*/
|
||||
/*}*/
|
||||
|
||||
.menu_buttons.left.close.filters{
|
||||
width: 294px;
|
||||
background: #FFFFFF;
|
||||
border-radius: 10px;
|
||||
max-height: 83vh;
|
||||
left: 0;
|
||||
padding: 13px;
|
||||
transition: 200ms;
|
||||
/* position: fixed; */
|
||||
float: left;
|
||||
text-align: left;
|
||||
top: 0;
|
||||
left: 19px;
|
||||
}
|
||||
|
||||
.btn_a_anchor{
|
||||
border-radius: 10px;
|
||||
background: #E6E6E6;
|
||||
width: 20%;
|
||||
height: 60px;
|
||||
font-size: 18px;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
line-height: 26px;
|
||||
color: rgba(39, 36, 36, 0.60);
|
||||
margin-left: 5px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.btn_a_anchor.partners{
|
||||
background: #FF613A;
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
.text_in_btn_a_anchor{
|
||||
padding-top: 17px;
|
||||
}
|
||||
|
||||
.anchor{
|
||||
scroll-margin-top: 60px;
|
||||
}
|
||||
.anchor.about_service{
|
||||
scroll-margin-top: 150px;
|
||||
}
|
||||
/*login page*/
|
||||
.error_f_login{
|
||||
color: #f00;
|
||||
margin-bottom: 20px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/*b_profile_first_page*/
|
||||
|
||||
.title_b_first_page{
|
||||
margin-top: 70px;
|
||||
}
|
||||
|
||||
/* handler_curtain changed*/
|
||||
|
||||
.handler_curtain_left{
|
||||
display: none;
|
||||
}
|
||||
|
||||
/*cookie*/
|
||||
|
||||
.cookie_block{
|
||||
background: #000000;
|
||||
width: 951px;
|
||||
position: fixed;
|
||||
bottom: 5px;
|
||||
z-index: 100000000000000;
|
||||
box-sizing: border-box;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.cookie_block.show{
|
||||
display: block;
|
||||
}
|
||||
|
||||
.txt_cookie{
|
||||
color: #FFFFFF;
|
||||
font-size: 14px;
|
||||
}
|
||||
.a_cookie{
|
||||
color: #FFFFFF;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.container_content_cookie_block{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.cookie_btn{
|
||||
background: none;
|
||||
border: 2px solid white;
|
||||
color: #FFFFFF;
|
||||
height: 25px;
|
||||
width: 95px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 32 KiB |
BIN
static/img/png/banner_test.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
static/img/png/banner_test_3.png
Normal file
|
After Width: | Height: | Size: 59 KiB |
1
static/img/svg/burger.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M0 96C0 78.3 14.3 64 32 64H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32C14.3 128 0 113.7 0 96zM0 256c0-17.7 14.3-32 32-32H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32c-17.7 0-32-14.3-32-32zM448 416c0 17.7-14.3 32-32 32H32c-17.7 0-32-14.3-32-32s14.3-32 32-32H416c17.7 0 32 14.3 32 32z"/></svg>
|
||||
|
After Width: | Height: | Size: 527 B |
1
static/img/svg/filter.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M0 416c0 17.7 14.3 32 32 32l54.7 0c12.3 28.3 40.5 48 73.3 48s61-19.7 73.3-48L480 448c17.7 0 32-14.3 32-32s-14.3-32-32-32l-246.7 0c-12.3-28.3-40.5-48-73.3-48s-61 19.7-73.3 48L32 384c-17.7 0-32 14.3-32 32zm128 0a32 32 0 1 1 64 0 32 32 0 1 1 -64 0zM320 256a32 32 0 1 1 64 0 32 32 0 1 1 -64 0zm32-80c-32.8 0-61 19.7-73.3 48L32 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l246.7 0c12.3 28.3 40.5 48 73.3 48s61-19.7 73.3-48l54.7 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-54.7 0c-12.3-28.3-40.5-48-73.3-48zM192 128a32 32 0 1 1 0-64 32 32 0 1 1 0 64zm73.3-64C253 35.7 224.8 16 192 16s-61 19.7-73.3 48L32 64C14.3 64 0 78.3 0 96s14.3 32 32 32l86.7 0c12.3 28.3 40.5 48 73.3 48s61-19.7 73.3-48L480 128c17.7 0 32-14.3 32-32s-14.3-32-32-32L265.3 64z" stroke="#ffffff"/></svg>
|
||||
|
After Width: | Height: | Size: 992 B |
7
static/img/svg/gb.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icon-css-gb" viewBox="0 0 512 512">
|
||||
<path fill="#012169" d="M0 0h512v512H0z"/>
|
||||
<path fill="#FFF" d="M512 0v64L322 256l190 187v69h-67L254 324 68 512H0v-68l186-187L0 74V0h62l192 188L440 0z"/>
|
||||
<path fill="#C8102E" d="M184 324l11 34L42 512H0v-3l184-185zm124-12l54 8 150 147v45L308 312zM512 0L320 196l-4-44L466 0h46zM0 1l193 189-59-8L0 49V1z"/>
|
||||
<path fill="#FFF" d="M176 0v512h160V0H176zM0 176v160h512V176H0z"/>
|
||||
<path fill="#C8102E" d="M0 208v96h512v-96H0zM208 0v512h96V0h-96z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 541 B |
BIN
static/img/svg/group.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
1
static/img/svg/loader_white.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.0" width="32px" height="32px" viewBox="0 0 128 128" xml:space="preserve"><g><circle cx="16" cy="64" r="16" fill="#ffffff" fill-opacity="1"/><circle cx="16" cy="64" r="16" fill="#ffffff" fill-opacity="0.67" transform="rotate(45,64,64)"/><circle cx="16" cy="64" r="16" fill="#ffffff" fill-opacity="0.42" transform="rotate(90,64,64)"/><circle cx="16" cy="64" r="16" fill="#ffffff" fill-opacity="0.2" transform="rotate(135,64,64)"/><circle cx="16" cy="64" r="16" fill="#ffffff" fill-opacity="0.12" transform="rotate(180,64,64)"/><circle cx="16" cy="64" r="16" fill="#ffffff" fill-opacity="0.12" transform="rotate(225,64,64)"/><circle cx="16" cy="64" r="16" fill="#ffffff" fill-opacity="0.12" transform="rotate(270,64,64)"/><circle cx="16" cy="64" r="16" fill="#ffffff" fill-opacity="0.12" transform="rotate(315,64,64)"/><animateTransform attributeName="transform" type="rotate" values="0 64 64;315 64 64;270 64 64;225 64 64;180 64 64;135 64 64;90 64 64;45 64 64" calcMode="discrete" dur="720ms" repeatCount="indefinite"></animateTransform></g></svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
7
static/img/svg/ru.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icon-css-ru" viewBox="0 0 512 512">
|
||||
<g fill-rule="evenodd" stroke-width="1pt">
|
||||
<path fill="#fff" d="M0 0h512v512H0z"/>
|
||||
<path fill="#0039a6" d="M0 170.7h512V512H0z"/>
|
||||
<path fill="#d52b1e" d="M0 341.3h512V512H0z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 290 B |
BIN
static/img/svg/user_icon_standart.png
Normal file
|
After Width: | Height: | Size: 68 KiB |
1
static/img/svg/users-solid.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M144 0a80 80 0 1 1 0 160A80 80 0 1 1 144 0zM512 0a80 80 0 1 1 0 160A80 80 0 1 1 512 0zM0 298.7C0 239.8 47.8 192 106.7 192h42.7c15.9 0 31 3.5 44.6 9.7c-1.3 7.2-1.9 14.7-1.9 22.3c0 38.2 16.8 72.5 43.3 96c-.2 0-.4 0-.7 0H21.3C9.6 320 0 310.4 0 298.7zM405.3 320c-.2 0-.4 0-.7 0c26.6-23.5 43.3-57.8 43.3-96c0-7.6-.7-15-1.9-22.3c13.6-6.3 28.7-9.7 44.6-9.7h42.7C592.2 192 640 239.8 640 298.7c0 11.8-9.6 21.3-21.3 21.3H405.3zM224 224a96 96 0 1 1 192 0 96 96 0 1 1 -192 0zM128 485.3C128 411.7 187.7 352 261.3 352H378.7C452.3 352 512 411.7 512 485.3c0 14.7-11.9 26.7-26.7 26.7H154.7c-14.7 0-26.7-11.9-26.7-26.7z"/></svg>
|
||||
|
After Width: | Height: | Size: 849 B |
1
static/img/svg/users-solid_white.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M144 0a80 80 0 1 1 0 160A80 80 0 1 1 144 0zM512 0a80 80 0 1 1 0 160A80 80 0 1 1 512 0zM0 298.7C0 239.8 47.8 192 106.7 192h42.7c15.9 0 31 3.5 44.6 9.7c-1.3 7.2-1.9 14.7-1.9 22.3c0 38.2 16.8 72.5 43.3 96c-.2 0-.4 0-.7 0H21.3C9.6 320 0 310.4 0 298.7zM405.3 320c-.2 0-.4 0-.7 0c26.6-23.5 43.3-57.8 43.3-96c0-7.6-.7-15-1.9-22.3c13.6-6.3 28.7-9.7 44.6-9.7h42.7C592.2 192 640 239.8 640 298.7c0 11.8-9.6 21.3-21.3 21.3H405.3zM224 224a96 96 0 1 1 192 0 96 96 0 1 1 -192 0zM128 485.3C128 411.7 187.7 352 261.3 352H378.7C452.3 352 512 411.7 512 485.3c0 14.7-11.9 26.7-26.7 26.7H154.7c-14.7 0-26.7-11.9-26.7-26.7z"/></svg>
|
||||
|
After Width: | Height: | Size: 849 B |
@@ -3,6 +3,8 @@ function SendLoginForm(el){
|
||||
event.preventDefault()
|
||||
let form = el.form;
|
||||
let formData = new FormData(form);
|
||||
let msr = sessionStorage.getItem('mailingSubscribeRequired')
|
||||
formData.set('mailingSubscribeRequired',msr)
|
||||
|
||||
|
||||
|
||||
@@ -18,7 +20,10 @@ function SendLoginForm(el){
|
||||
data: formData,
|
||||
success: function(data){
|
||||
|
||||
location.href = '/profile/page/dashboard/'
|
||||
location.href = `/profile/page/dashboard/`
|
||||
window.sessionStorage.removeItem('mailingSubscribeRequired')
|
||||
window.sessionStorage.removeItem('email')
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||