594 Commits

Author SHA1 Message Date
Philip
15c9d589fe serializer 2024-03-05 20:06:38 +03:00
Philip
fa116c08c1 fix task 2024-03-05 13:47:36 +03:00
Philip
4f9129e718 sample 2024-02-28 14:10:20 +03:00
Philip
df45f3a704 not found 2024-02-25 13:41:26 +03:00
Philip
90ef093fca supscriptions 2024-02-24 19:54:57 +03:00
4331b26542 0.1.362 fix language bug redirect to main page 2024-02-22 18:54:15 +03:00
SDE
dd8a8ddd53 0.12.26 get_phone_valid_error change 2024-02-21 17:12:45 +03:00
SBD
abb0d488eb 14 2024-02-21 15:10:34 +03:00
SBD
be97b848d0 14 2024-02-21 14:56:25 +03:00
SBD
6bc112d689 13 2024-02-21 14:37:31 +03:00
SBD
dc534a0c51 12 2024-02-21 14:21:48 +03:00
SDE
e71ed05e6c 0.12.25 timezone in chat messages 2024-02-21 14:12:03 +03:00
SBD
2048ed6baf 11 2024-02-20 19:31:10 +03:00
SBD
c146bd6155 10 2024-02-20 18:57:17 +03:00
SBD
98665abf4d 9 2024-02-20 18:27:36 +03:00
SBD
9954140d3a 9 2024-02-20 17:43:08 +03:00
SBD
fafee63a64 7 2024-02-20 17:35:01 +03:00
c623d69767 0.1.361 comment red marker on mobile_header temp 2024-02-12 17:22:24 +03:00
670eb28bc0 0.1.360 add red marker on mobile_header temp 2024-02-12 17:17:21 +03:00
144ff286f6 0.1.359 add red marker on mobile_header temp 2024-02-12 17:12:44 +03:00
05f94de0b4 Merge remote-tracking branch 'origin/main' 2024-02-12 16:09:24 +03:00
c4650ce603 0.1.358 upd profile_button width 2024-02-12 16:09:13 +03:00
SDE
3971a8ee23 0.12.24 timezone in chat messages 2024-02-09 20:33:04 +03:00
SDE
a3ba6bc783 0.12.23 timezone in chat messages 2024-02-09 18:18:21 +03:00
SDE
b87df02714 0.12.22 timezone in chat messages 2024-02-09 18:01:11 +03:00
SDE
713695cf7d 0.12.21 timezone in chat messages 2024-02-09 17:00:28 +03:00
SDE
a25f30eda7 0.12.20 timezone in chat messages 2024-02-09 16:57:27 +03:00
SDE
eddb3a1858 0.12.19 timezone in chat messages 2024-02-09 15:12:10 +03:00
SDE
5a89200f1d Merge remote-tracking branch 'origin/main' 2024-02-08 14:51:27 +03:00
SDE
2f47a9e3db 0.12.18 registration mail to user 2024-02-08 14:51:19 +03:00
155b6272ec 0.1.357 upd mobile_styles.css for menu_profile 2024-02-08 14:20:50 +03:00
SDE
1479584bfc 0.12.17 change_avatar_confirm_ajax RequestDataTooBig 2024-02-05 23:02:11 +03:00
SDE
f86be5bd97 Merge remote-tracking branch 'origin/main' 2024-02-05 22:41:58 +03:00
SDE
c87a7095ad 0.12.16 change_avatar_confirm_ajax RequestDataTooBig 2024-02-05 22:41:50 +03:00
ac4df7a5f7 0.1.356 upd text_block 2024-02-05 14:34:15 +03:00
SDE
c48839ff8c 0.12.15 subscribe mailing 2024-02-02 18:50:51 +03:00
SDE
ea296e3f05 0.12.14 subscribe mailing 2024-02-02 18:15:51 +03:00
SDE
8124ed62fe 0.12.13 subscribe mailing 2024-02-02 18:08:28 +03:00
SDE
cc643d2641 0.12.12 subscribe mailing 2024-02-02 18:06:35 +03:00
SDE
6de42c5ba9 Merge remote-tracking branch 'origin/main' 2024-02-02 17:44:50 +03:00
SDE
36b7f4dee7 0.12.11 subscribe mailing 2024-02-02 17:44:43 +03:00
2328f09023 0.1.355 mailingSubscribeRequired functional UPD 2024-02-02 17:41:01 +03:00
60faeeace9 Merge remote-tracking branch 'origin/main' 2024-02-02 17:37:35 +03:00
abe53dd88b 0.1.354 mailingSubscribeRequired functional 2024-02-02 17:37:25 +03:00
SDE
c76a18c5ff Merge remote-tracking branch 'origin/main' 2024-02-02 15:51:45 +03:00
SDE
3725ce1882 0.12.10 routes order 2024-02-02 15:51:37 +03:00
6a69ff02b1 0.1.353 add font-display for lcp test 2024-02-02 15:04:30 +03:00
6ba41af305 0.1.352 small bug_fix 2024-02-02 12:50:59 +03:00
SDE
5815a08b55 0.12.9 subscribe mailing 2024-02-01 19:13:26 +03:00
SDE
7805161829 0.12.8 subscribe mailing 2024-02-01 19:07:48 +03:00
6fa31f3866 Merge remote-tracking branch 'origin/main' 2024-02-01 18:51:01 +03:00
0763faf224 0.1.351 upd footer 2024-02-01 18:50:28 +03:00
SDE
a3d3e12467 0.12.7 subscribe mailing 2024-02-01 18:43:16 +03:00
SDE
ab22a3ec88 0.12.6 subscribe mailing 2024-02-01 18:32:29 +03:00
SDE
9d0a059909 0.12.5 subscribe mailing 2024-02-01 18:24:02 +03:00
SDE
1011f112b2 0.12.4 subscribe mailing 2024-02-01 17:49:57 +03:00
SDE
d07ab2c71f Merge remote-tracking branch 'origin/main' 2024-02-01 17:46:55 +03:00
SDE
96bfef04a8 0.12.3 subscribe mailing 2024-02-01 17:46:44 +03:00
SBD
779dd7e93d 7 2024-02-01 15:06:05 +03:00
SBD
0abcb34829 7 2024-02-01 14:58:26 +03:00
SBD
33c028207a 6 2024-02-01 14:36:08 +03:00
SBD
64b3e40ed0 6 2024-02-01 14:14:35 +03:00
SBD
0023676b28 Merge remote-tracking branch 'origin/main' 2024-02-01 13:26:53 +03:00
SBD
b90039f21a 5 2024-02-01 13:26:42 +03:00
b5f24ebf2e 0.1.350 small upd for .css 2024-01-31 17:49:03 +03:00
SBD
f99a010e4a 5 2024-01-31 17:17:53 +03:00
SBD
a4944360a6 5 2024-01-31 17:13:15 +03:00
SBD
a2b5d81c98 5 2024-01-31 17:11:12 +03:00
SBD
13b7c2572d Merge remote-tracking branch 'origin/main' 2024-01-31 16:57:06 +03:00
SBD
47b12882ba 5 2024-01-31 16:56:57 +03:00
SDE
c008aa585b Merge remote-tracking branch 'origin/main' 2024-01-31 16:39:12 +03:00
SDE
406b5e8480 0.12.2 registration mail 2024-01-31 16:39:03 +03:00
SBD
584a196784 5 2024-01-31 15:20:50 +03:00
SBD
618f7751d1 5 2024-01-31 15:20:20 +03:00
SBD
faaea1129a 5 2024-01-31 15:11:39 +03:00
SBD
dd7afc28f7 5 2024-01-31 15:00:48 +03:00
SBD
9ecf5ce073 5 2024-01-31 14:55:04 +03:00
SBD
422373f00e 5 2024-01-31 14:46:18 +03:00
SBD
60636daeb8 Merge remote-tracking branch 'origin/main' 2024-01-31 14:40:19 +03:00
SBD
9d47f4c2bc 5 2024-01-31 14:40:11 +03:00
SDE
4d6dbddd28 Merge remote-tracking branch 'origin/main' 2024-01-31 14:37:49 +03:00
SDE
3f00ff39d2 0.12.1 fix form from and to place fields choices 2024-01-31 14:37:41 +03:00
SBD
bff6a81586 Merge remote-tracking branch 'origin/main' 2024-01-31 14:12:55 +03:00
SBD
9cb8036d3c 3 2024-01-31 14:12:44 +03:00
SDE
a43de1fa91 Merge remote-tracking branch 'origin/main' 2024-01-31 13:44:18 +03:00
SDE
93717bee2d 0.12.11 del mobile markers for response 2024-01-31 13:44:08 +03:00
SBD
8db1d6fdce 3 2024-01-31 13:41:47 +03:00
SBD
b41f8c7eca 3 2024-01-31 13:37:31 +03:00
SBD
c19405d32a Merge remote-tracking branch 'origin/main' 2024-01-31 13:24:02 +03:00
SBD
7b75c533a8 3 2024-01-31 13:23:50 +03:00
SDE
649dbab901 0.12.10 fix allauth google cancel 2024-01-26 19:02:17 +03:00
SDE
1a4498d19f 0.12.9 fix allauth google cancel 2024-01-26 19:00:47 +03:00
SDE
2786ef454d Merge remote-tracking branch 'origin/main' 2024-01-26 18:26:52 +03:00
SDE
961c0dd2a5 0.12.8 switch off push for static pages 2024-01-26 18:26:37 +03:00
SBD
0a0835d3a6 3 2024-01-26 18:20:25 +03:00
SBD
bc87d10d59 Merge remote-tracking branch 'origin/main' 2024-01-26 18:14:50 +03:00
SBD
792693848b 2 2024-01-26 18:14:41 +03:00
SDE
de229c5f78 0.12.7 chat fixes 2024-01-26 17:45:48 +03:00
SDE
03f9a836e6 0.12.6 chat fixes 2024-01-26 17:09:42 +03:00
SBD
91751574cc 1 2024-01-26 16:31:58 +03:00
d5453dada6 0.1.349 small upd 2024-01-26 14:37:50 +03:00
22adb18a39 Merge remote-tracking branch 'origin/main' 2024-01-26 13:59:36 +03:00
0a3c40dd5d 0.1.348 upd input_list for main page 2024-01-26 13:58:51 +03:00
SBD
b29825d62b correct titles 2024-01-26 13:29:05 +03:00
c9bda8aab2 Merge remote-tracking branch 'origin/main' 2024-01-26 13:06:30 +03:00
284a4b064a 0.1.347 update show_contact button behavior 2024-01-26 13:06:17 +03:00
SBD
6f20f53d75 ws changes 2024-01-26 12:47:46 +03:00
SDE
473a047af9 Merge remote-tracking branch 'origin/main' 2024-01-25 18:36:29 +03:00
SDE
481f9a881f 0.12.5 google auth fix 2024-01-25 18:36:15 +03:00
6ceedddbc1 0.1.346 add border for input_list. Change color and width for scroll-bar v2 2024-01-25 17:05:01 +03:00
bd9e0fad48 0.1.345 add border for input_list. Change color and width for scroll-bar 2024-01-25 16:50:36 +03:00
6b118d00b6 0.1.344 hide div with phone number 2024-01-25 15:39:15 +03:00
01e221196f 0.1.343 small bug fix with buttons style v.2 2024-01-25 14:57:26 +03:00
ccf016999b 0.1.342 small bug fix with buttons style 2024-01-25 14:51:49 +03:00
SBD
cb79e47796 Merge remote-tracking branch 'origin/main' 2024-01-23 18:05:57 +03:00
SBD
4076bd6065 ws changes 2024-01-23 18:05:45 +03:00
e54c258007 Merge remote-tracking branch 'origin/main' 2024-01-23 17:15:15 +03:00
c3b7401255 0.1.341 upd text for main page, customer/mover page. Add new png for main page 2024-01-23 17:15:04 +03:00
SDE
9af72d30f4 0.12.4 ws fix 2024-01-22 18:10:32 +03:00
SDE
dbe948ae5f Merge remote-tracking branch 'origin/main' 2024-01-22 18:09:04 +03:00
SDE
885d36a90c 0.12.3 ws fix 2024-01-22 18:08:55 +03:00
SBD
7acfbc0113 Merge remote-tracking branch 'origin/main' 2024-01-22 17:41:33 +03:00
SBD
43c5faf988 took wss 2024-01-22 17:41:17 +03:00
SDE
437142fba0 Merge remote-tracking branch 'origin/main' 2024-01-22 17:32:10 +03:00
SDE
acf7b702ee 0.12.2 ws fix 2024-01-22 17:32:03 +03:00
74ca1be884 Merge remote-tracking branch 'origin/main' 2024-01-19 13:18:30 +03:00
26b987d6ce 0.1.340 upd text and add href for customer button 2024-01-19 13:18:09 +03:00
SDE
3f7f1d88ed 0.12.1 addsense register 2024-01-18 20:13:52 +03:00
SDE
59225b1688 Merge remote-tracking branch 'origin/main' 2024-01-18 20:11:54 +03:00
SDE
108aee2c43 0.12.0 addsense register 2024-01-18 20:11:45 +03:00
9062ce32a1 Merge remote-tracking branch 'origin/main' 2024-01-18 14:09:46 +03:00
7c74a0f3fe 0.1.339 slice name/surname if it longer then 5 character 2024-01-18 14:08:48 +03:00
SDE
4fb3a12f47 0.11.22 push w link 2024-01-18 13:15:28 +03:00
SDE
59bc25f31c 0.11.21 push w link 2024-01-16 17:25:40 +03:00
SDE
87fbe7852c 0.11.20 push w link 2024-01-16 16:53:01 +03:00
SDE
793d283d97 0.11.19 Google Auth 2024-01-15 19:31:30 +03:00
SDE
651ae18345 0.11.18 Google Auth 2024-01-15 17:44:59 +03:00
SDE
67eb32968e 0.11.17 Google Auth 2024-01-15 17:43:18 +03:00
SDE
c6d41513c0 0.11.16 Google Auth 2024-01-15 17:27:48 +03:00
SDE
67ba698b60 0.11.15 Google Auth 2024-01-15 17:06:53 +03:00
SDE
15d1c00ac6 0.11.14 Google Auth 2024-01-15 16:56:18 +03:00
SDE
9e9a82ffc0 0.11.13 Google Auth 2024-01-15 16:51:38 +03:00
SDE
a0eb5210ab 0.11.12 Google Auth 2024-01-15 16:47:53 +03:00
SDE
3dacc0316e Merge remote-tracking branch 'origin/main' 2024-01-15 16:36:59 +03:00
SDE
e2c347c912 0.11.11 Google Auth 2024-01-15 16:36:51 +03:00
758f8b1f55 0.1.338 upd style for cards_item 2024-01-15 13:43:38 +03:00
SDE
b446a8f519 0.11.10 Google Auth 2024-01-13 21:24:58 +03:00
SDE
c8ba0dd770 0.11.9 Google Auth 2024-01-13 21:15:05 +03:00
SDE
f13a1329ca 0.11.8 Google Auth 2024-01-13 21:13:06 +03:00
SDE
4b3604098f 0.11.7 Google Auth 2024-01-13 21:12:04 +03:00
SDE
defbf6746f 0.11.6 Google Auth 2024-01-13 18:04:01 +03:00
SDE
bf3f26ec4f 0.11.5 Google Auth 2024-01-13 18:01:34 +03:00
SDE
76018333b0 0.11.4 Google Auth 2024-01-13 17:29:21 +03:00
SDE
e6e345b9fe 0.11.3 Google Auth 2024-01-13 17:27:32 +03:00
SDE
eafccabb66 0.11.2 Google Auth 2024-01-13 17:26:25 +03:00
SDE
f2e0628de1 0.11.1 Google Auth 2024-01-13 17:05:57 +03:00
SDE
2e1f3a10ab 0.11.0 Google Auth 2024-01-13 14:49:32 +03:00
bf18c96dbd 0.1.337 add google authorization button 2024-01-13 14:12:25 +03:00
23718a5f3f 0.1.336 upd cards_item for main page 2024-01-13 13:46:58 +03:00
c6a1d5bdcf Merge remote-tracking branch 'origin/main' 2024-01-12 17:42:00 +03:00
f75e94f706 0.1.335 upd cards_wrapper on main page 2024-01-12 17:41:48 +03:00
SBD
11c9bb6c23 took wss 2024-01-12 17:01:50 +03:00
SBD
b1ff9c47da Merge remote-tracking branch 'origin/main' 2024-01-12 16:49:47 +03:00
SBD
35c09dc70b check post csrf8 2024-01-12 16:49:38 +03:00
SDE
f0efae5987 0.10.7 fix 403 2024-01-12 16:44:51 +03:00
SDE
65120cd2d4 0.10.6 fix 403 2024-01-12 16:41:43 +03:00
SBD
231d062814 check post csrf7 2024-01-12 16:32:00 +03:00
SBD
615922a881 check post csrf6 2024-01-12 16:28:49 +03:00
SBD
61b2b824d5 check post csrf5 2024-01-12 16:21:11 +03:00
SBD
317445998a check post csrf4 2024-01-12 16:16:27 +03:00
SBD
4ad3813499 check post csrf3 2024-01-12 16:11:35 +03:00
SBD
9a88243323 Merge remote-tracking branch 'origin/main' 2024-01-12 15:58:42 +03:00
SBD
df0f32c71a check post csrf2 2024-01-12 15:58:34 +03:00
SDE
4ddd402442 0.10.5 fix 403 2024-01-12 15:55:09 +03:00
SBD
a05c4b3898 Merge remote-tracking branch 'origin/main' 2024-01-12 15:50:54 +03:00
SBD
a3ab0973c9 check post csrf1 2024-01-12 15:50:43 +03:00
SDE
0f801aa44b 0.10.4 monkey patching fix 403 2024-01-12 02:28:51 +03:00
SBD
7bc386bc44 Merge remote-tracking branch 'origin/main' 2024-01-11 19:37:48 +03:00
SBD
e148c60d70 add cookie 3 2024-01-11 19:37:39 +03:00
SDE
4667352ec4 0.10.3 fix websocet with ssl 2024-01-11 19:34:34 +03:00
SBD
e7cf694d88 add cookie 2 2024-01-11 19:31:14 +03:00
SBD
b2abb3046b add cookie 2024-01-11 19:10:30 +03:00
SDE
6c1011e59e 0.10.2 mail alert by new routes 2024-01-11 19:03:25 +03:00
ad909b98bf 0.1.334 save checked after reload in receive_msg_by_email 2024-01-11 15:27:14 +03:00
9d2e35246a 0.1.333 upd 404_page and create conditions for unfound routes 2024-01-11 15:14:45 +03:00
48dc573c0f 0.1.334 upd text for unfinded routes 2024-01-11 13:45:20 +03:00
SBD
e559660912 Merge remote-tracking branch 'origin/main' 2024-01-09 22:01:13 +03:00
SBD
aa3bec304a correct work curtain 2024-01-09 22:01:00 +03:00
c7bc22813f 0.1.333 upd 404_page and create conditions for unfound routes 2024-01-09 13:03:30 +03:00
SDE
46e73db10a 0.10.1 browser push messages 2024-01-08 15:08:46 +03:00
SDE
ad451c2ae0 0.10.0 browser push messages 2024-01-08 14:54:59 +03:00
SDE
0b5b557a35 0.9.0 404 prepare 2024-01-08 13:22:11 +03:00
SBD
fb9228c432 correct work curtain 2024-01-06 14:48:31 +03:00
SBD
fbcbe93042 correct work curtain 2024-01-06 14:37:34 +03:00
ca44deb077 0.0.332 upd text on main_page 2024-01-04 14:50:25 +03:00
61403bfac2 0.0.331 set white background-color for input_list 2024-01-03 13:20:25 +03:00
SBD
190efa4b74 mobile === false 2023-12-29 21:30:03 +05:00
SBD
ca06836b11 mobile === false 2023-12-29 21:06:08 +05:00
SBD
b31241872f mobile === false 2023-12-29 19:45:43 +05:00
SBD
f80e2844bf mobile === false 2023-12-29 12:49:13 +05:00
1dae86f0e7 0.0.330 add color for title in my_routes 2023-12-21 16:28:42 +03:00
0c146caeef 0.0.329 upd logic for from_to_country inputs in b_new_route 2023-12-20 14:18:31 +03:00
410733211b 0.0.328 fix bug in lalble b_new_route.html | upd style title for routes on main page | commented out the code in b_chats.html for i icon 2023-12-20 14:03:59 +03:00
14df8969c2 0.0.327 upd title on main page 2023-12-18 16:08:09 +03:00
SBD
4388414ac2 correct work icons right or left of the curtain 2023-12-17 08:42:50 +03:00
SBD
791ac8d436 correct work curtain at routes_find_routes 2023-12-17 08:39:47 +03:00
a3d6f498b1 0.0.326 upd change_profile 2023-12-15 16:56:14 +03:00
SDE
b8fdd61948 0.8.43 change profile validation 2023-12-15 16:12:34 +03:00
SDE
4437372d7c 0.8.42 change profile validation 2023-12-15 16:03:27 +03:00
SDE
f8d29d80b7 0.8.41 change profile validation 2023-12-15 15:56:51 +03:00
SDE
36fd9599af 0.8.40 change profile validation 2023-12-15 15:46:46 +03:00
65eccde487 0.0.326 upd change_profile 2023-12-15 15:44:23 +03:00
SDE
037b4cc562 0.8.39 change profile validation 2023-12-15 15:28:29 +03:00
SDE
9c971a6fa4 0.8.38 change profile validation 2023-12-15 15:11:35 +03:00
SBD
a3faa17754 Merge remote-tracking branch 'origin/main' 2023-12-13 17:59:25 +03:00
SBD
085f905125 correct work curtain at routes_find_routes 2023-12-13 17:57:00 +03:00
dc16ced786 0.0.325 hide scroll for mozilla 2023-12-12 17:06:05 +03:00
d5cba26098 0.0.324 2023-12-12 16:50:52 +03:00
001dd2cb87 0.0.323 2023-12-12 16:34:00 +03:00
16e860a29f 0.0.322 upd lable for b_new_route.html 2023-12-12 16:01:01 +03:00
SDE
6a5331d8eb 0.8.37 owner_type initial 2023-12-07 18:35:06 +03:00
aff0b0fe98 0.0.321 2023-12-07 16:54:57 +03:00
fd3612c370 0.0.320 2023-12-06 18:03:48 +03:00
d14a46d3d7 0.0.319 upd create_route, header_buttons alight 2023-12-06 15:51:55 +03:00
SBD
d7ace77de8 0.8.482 2023-12-05 22:17:49 +03:00
SBD
885e4722af 0.8.481 2023-12-05 21:11:36 +03:00
SBD
72ed6369d8 0.8.479 2023-12-05 20:24:07 +03:00
b23e440efd 0.0.318 work with datarangepicker.js 2023-12-05 20:16:44 +03:00
75ddb002fd Merge remote-tracking branch 'origin/main' 2023-12-05 18:52:58 +03:00
28a36335ce 0.0.317 locale for datarangepicker.js 2023-12-05 18:52:52 +03:00
SDE
fba225aa70 Merge remote-tracking branch 'origin/main' 2023-12-05 17:43:09 +03:00
SDE
af800ac84c 0.8.36 check dates when route create 2023-12-05 17:43:01 +03:00
87e90d7152 0.0.316 add new language flags 2023-12-05 16:58:32 +03:00
c25942a6ca 0.0.315 test with viewport 2023-12-05 15:24:46 +03:00
692419816f 0.0.314 test with viewport 2023-12-05 15:21:21 +03:00
3a109340fd 0.0.313 test with viewport 2023-12-05 14:59:44 +03:00
5925ecb975 0.0.312 test with viewport 2023-12-05 14:54:21 +03:00
325acd3580 0.0.311 add red color for changed input in from_to_addres_point 2023-12-05 14:38:25 +03:00
3ac85784a9 0.0.310 2023-12-05 13:48:41 +03:00
5c4e715970 Merge remote-tracking branch 'origin/main' 2023-12-05 13:39:38 +03:00
89b57feb4e 0.0.309 upd avatar for routes 2023-12-05 13:37:17 +03:00
SDE
fc194d3f85 0.8.35 order for city / country 2023-12-05 13:25:31 +03:00
SDE
12af0ea238 Merge remote-tracking branch 'origin/main' 2023-12-05 12:47:30 +03:00
SDE
6e758cf62e 0.8.34 fix route_search 2023-12-05 12:47:23 +03:00
f7783c070b Merge remote-tracking branch 'origin/main' 2023-12-05 12:45:26 +03:00
SBD
fb3cd30db4 0.8.478 2023-12-04 17:23:27 +03:00
ff949a8205 0.0.308 2023-12-03 21:02:13 +03:00
SBD
624653f581 Merge remote-tracking branch 'origin/main' 2023-12-03 20:57:56 +03:00
SBD
f3e5f02f07 0.8.477 2023-12-03 20:57:38 +03:00
d0792e9e84 Merge remote-tracking branch 'origin/main' 2023-12-03 20:56:38 +03:00
f752eb5d4a 0.0.307 clear errors for DT in create route. Change default select for main 2023-12-03 20:56:29 +03:00
SBD
f0861fde84 Merge remote-tracking branch 'origin/main' 2023-12-03 20:53:59 +03:00
SBD
4e7aa09c21 0.8.476 2023-12-03 20:53:48 +03:00
SDE
e68a0dc151 Merge remote-tracking branch 'origin/main' 2023-12-03 20:49:14 +03:00
SDE
fc37bea98a 0.8.33 tickets text 2023-12-03 20:49:07 +03:00
SBD
8a91e611ac Merge remote-tracking branch 'origin/main' 2023-12-03 20:43:24 +03:00
SBD
7208db6981 0.8.475 2023-12-03 20:43:13 +03:00
SDE
447a78cd3a 0.8.32 tickets text 2023-12-03 20:37:01 +03:00
SBD
95dff519b8 0.8.474 2023-12-03 20:36:20 +03:00
SBD
62aeebae95 0.8.473 2023-12-03 20:22:20 +03:00
SBD
c2e03728f8 0.8.472 2023-12-03 20:00:32 +03:00
SBD
a64fbab270 0.8.471 2023-12-03 19:59:15 +03:00
SBD
00ea16f631 0.8.470 2023-12-03 19:50:51 +03:00
SBD
e3aafcdfe9 0.8.469 2023-12-03 19:35:52 +03:00
SBD
421a3a2dab Merge remote-tracking branch 'origin/main' 2023-12-03 19:27:11 +03:00
SBD
61e4f7e450 0.8.468 2023-12-03 19:26:56 +03:00
SDE
3b52cab162 0.8.31 fix registration form 2023-12-03 19:07:49 +03:00
fe9be61772 Merge remote-tracking branch 'origin/main' 2023-12-03 18:59:00 +03:00
0818f880cc 0.0.306 upd registration error_msg 2023-12-03 18:58:54 +03:00
SBD
cca062efec Merge remote-tracking branch 'origin/main' 2023-12-03 18:33:34 +03:00
SBD
2eb7ac85d3 0.8.467 2023-12-03 18:33:23 +03:00
SDE
3469a3923c 0.8.30 fix registration form 2023-12-03 18:07:39 +03:00
SDE
20fb49b3e4 0.8.30 fix registration form 2023-12-03 17:47:29 +03:00
SDE
afe8feebc2 Merge remote-tracking branch 'origin/main' 2023-12-03 17:43:13 +03:00
SDE
ae6a68d85b 0.8.30 check password 2023-12-03 17:43:01 +03:00
SBD
d80c45acd5 0.8.466 2023-12-03 17:40:28 +03:00
3a9ac2c289 Merge remote-tracking branch 'origin/main' 2023-12-03 17:38:59 +03:00
2d68836724 0.0.305 set test_banners for news 2023-12-03 17:38:53 +03:00
SDE
0deb85b5a3 0.8.29 admin airport change city 2023-12-03 17:25:21 +03:00
SBD
7b38f6e3b3 Merge remote-tracking branch 'origin/main' 2023-12-03 17:21:23 +03:00
SBD
43f050f070 0.8.465 2023-12-03 17:21:12 +03:00
098b7c4fb5 Merge remote-tracking branch 'origin/main' 2023-12-03 17:15:32 +03:00
eae56199e0 0.0.304 rewrite news widget 2023-12-03 17:15:23 +03:00
SDE
71e8f0f465 Merge remote-tracking branch 'origin/main' 2023-12-03 17:12:49 +03:00
SBD
66d7183278 0.8.464 2023-12-03 17:12:35 +03:00
SDE
92b92f2d65 0.8.29 admin airport change city 2023-12-03 17:12:32 +03:00
SBD
d5ab7d82eb 0.8.463 2023-12-03 17:09:16 +03:00
SBD
1ebd9f9c0b Merge remote-tracking branch 'origin/main' 2023-12-03 16:53:30 +03:00
SBD
7fd2c60ddb 0.8.462 2023-12-03 16:53:23 +03:00
SDE
f068182557 0.8.28 switch off passanger in airport route 2023-12-03 16:37:24 +03:00
SBD
02945b0691 Merge remote-tracking branch 'origin/main' 2023-12-03 16:09:32 +03:00
SBD
21b959e6a3 0.8.461 2023-12-03 16:09:24 +03:00
SDE
747091c744 0.8.27 one article breadcrumbs 2023-12-03 15:39:52 +03:00
7b70052ff1 0.0.303 2023-12-03 15:26:08 +03:00
SBD
49fd26bc4c Merge remote-tracking branch 'origin/main' 2023-12-03 15:12:18 +03:00
SBD
77f365ef45 Merge remote-tracking branch 'origin/main' 2023-12-03 15:12:11 +03:00
SDE
6d34d46e38 0.8.26 one article breadcrumbs 2023-12-03 15:12:04 +03:00
SBD
970c2e0837 0.8.460 2023-12-03 15:11:33 +03:00
SDE
b87549d567 0.8.25 msgs admin list change 2023-12-03 15:06:47 +03:00
SBD
78abdb2fef 0.8.459 2023-12-03 14:46:34 +03:00
SBD
f73ebb08c9 Merge remote-tracking branch 'origin/main' 2023-12-03 14:39:16 +03:00
SBD
628e8eec09 0.8.458 2023-12-03 14:39:07 +03:00
66ddcaec5b Merge remote-tracking branch 'origin/main' 2023-12-03 14:38:29 +03:00
3901c82aae 0.0.302 clear ID of hide inputs in create/find routes 2023-12-03 14:38:23 +03:00
SBD
9f682b66a5 0.8.457 2023-12-03 14:24:15 +03:00
SBD
c74aff7b91 0.8.456 2023-12-03 13:52:49 +03:00
SBD
1be50b1277 Merge remote-tracking branch 'origin/main' 2023-12-03 13:34:01 +03:00
SDE
af00d1a54b 0.8.25 profile unredeaded messages 2023-12-03 13:32:21 +03:00
SBD
dd4ad82248 0.8.455 2023-12-03 13:18:49 +03:00
SBD
38c08cbced Merge remote-tracking branch 'origin/main' 2023-12-03 12:59:15 +03:00
SBD
ed2c74a280 0.8.454 2023-12-03 12:59:05 +03:00
SDE
90ab1bb6b4 Merge remote-tracking branch 'origin/main' 2023-12-03 12:55:22 +03:00
SDE
3e2220e5f2 0.8.24 articles main 3 elements 2023-12-03 12:55:10 +03:00
SBD
33e27620b1 0.8.453 2023-12-03 12:46:44 +03:00
SBD
fbdef2a1ec 0.8.452 2023-12-03 12:34:24 +03:00
SBD
1834639b50 0.8.451 2023-12-03 12:22:05 +03:00
f9606a3c88 0.0.301 initialization in com_of 2023-12-02 17:07:25 +03:00
SDE
c803d7abbb 0.8.23 fix png black bg 2023-12-02 16:26:53 +03:00
SDE
efd75817bc 0.8.22 admin options change 2023-12-02 16:09:56 +03:00
SDE
36fff15e2b 0.8.21 admin options change 2023-12-02 16:07:12 +03:00
SDE
7573bfb344 Merge remote-tracking branch 'origin/main' 2023-12-02 15:59:40 +03:00
SDE
0c33d638ba 0.8.21 fix problem ckeditor uploads images 2023-12-02 15:59:29 +03:00
SBD
7d3da34e22 0.8.450 2023-12-02 15:55:47 +03:00
SDE
0e2723a367 Merge remote-tracking branch 'origin/main' 2023-12-02 15:42:34 +03:00
SDE
b102c44031 0.8.20 fix problem ckeditor uploads images 2023-12-02 15:42:25 +03:00
SBD
4b480c35e5 Merge remote-tracking branch 'origin/main' 2023-12-02 15:32:00 +03:00
SBD
8e7bcd8fd8 0.8.449 2023-12-02 15:31:50 +03:00
SDE
c60c545031 0.8.19 enable for subscribe in admin 2023-12-02 15:12:23 +03:00
SDE
51d075f799 0.8.18 enable for subscribe in admin 2023-12-02 15:10:17 +03:00
SDE
db54ec1650 Merge remote-tracking branch 'origin/main' 2023-12-02 15:02:48 +03:00
SDE
14b362442f 0.8.18 change pillow version for ckeditor 2023-12-02 15:02:39 +03:00
SBD
fcfbeece87 0.8.448 2023-12-02 15:01:48 +03:00
SBD
aea501aedb 0.8.447 2023-12-02 14:58:16 +03:00
SBD
f1d175fe84 Merge remote-tracking branch 'origin/main' 2023-12-02 14:56:40 +03:00
SBD
0f432c4fd9 0.8.446 2023-12-02 14:56:30 +03:00
b53e19c439 0.0.301 initialization in com_of 2023-12-02 14:43:23 +03:00
SDE
bebd20abf0 Merge remote-tracking branch 'origin/main' 2023-12-02 14:06:05 +03:00
SDE
5dc2293212 0.8.17 admin switch off functional 2023-12-02 14:05:57 +03:00
37f480c01e Merge remote-tracking branch 'origin/main' 2023-12-02 14:05:19 +03:00
f16efa24b0 0.0.300 fix errors in console 2023-12-02 14:05:14 +03:00
SDE
e11d05eb02 Merge remote-tracking branch 'origin/main' 2023-12-02 13:55:34 +03:00
SDE
32cd45106d 0.8.16 admin switch off functional 2023-12-02 13:55:26 +03:00
7b95893b34 Merge remote-tracking branch 'origin/main' 2023-12-02 13:52:50 +03:00
b6769f6350 0.0.299 2023-12-02 13:52:43 +03:00
SDE
5650b2d6b9 Merge remote-tracking branch 'origin/main' 2023-12-02 13:46:02 +03:00
SDE
f0fe8edf80 0.8.15 fix options 2023-12-02 13:45:54 +03:00
b30df5b6ed 0.0.298 2023-12-02 13:44:07 +03:00
0ef26556a2 0.0.297 remove errors after typing in ALL fields 2023-12-02 00:19:15 +03:00
ea92feab27 0.0.296 remove errors after typing in fields 2023-12-02 00:06:17 +03:00
1720e156d2 0.0.295 fix disabled buttons in different forms 2023-12-01 21:34:57 +03:00
9ed06e741e 0.0.294 2023-12-01 17:09:56 +03:00
d39a3a78d0 0.0.293 add loader for buttons when form send 2023-12-01 17:06:09 +03:00
09dc2984f3 0.0.292 upd error messages for forms 2023-12-01 15:28:14 +03:00
SDE
660e3f8a99 0.8.14
processing forms
2023-12-01 12:51:30 +03:00
SDE
cc9797eb71 0.8.13
processing forms
2023-12-01 12:30:34 +03:00
6a8aa73e63 0.0.291 2023-12-01 12:16:52 +03:00
689495e410 0.0.290 2023-12-01 12:10:17 +03:00
415fad4f4e Merge remote-tracking branch 'origin/main' 2023-12-01 12:02:59 +03:00
396db7a439 0.0.289 2023-12-01 12:02:52 +03:00
SDE
61bea5639b 0.8.12
processing forms
2023-12-01 11:36:11 +03:00
SDE
c9d6812d11 0.8.11
processing forms
2023-12-01 11:32:52 +03:00
18dd435678 0.0.288 2023-12-01 11:24:32 +03:00
a7a4112312 0.0.287 2023-12-01 11:14:04 +03:00
cf8cb9a6a4 0.0.286 2023-12-01 10:55:47 +03:00
b31f1ddb0f Merge remote-tracking branch 'origin/main' 2023-12-01 10:53:17 +03:00
382ddd48e4 0.0.285 2023-12-01 10:53:08 +03:00
SDE
0b57fa9238 0.8.10
fix send_message_ajax
2023-12-01 02:10:42 +03:00
SDE
fe7721270b 0.8.9
fix ResponseInterceptionMiddleware
2023-12-01 02:07:17 +03:00
49b35abb0b 0.0.284 2023-12-01 01:57:00 +03:00
41dbb6bad7 0.0.284 add send form from footer 2023-12-01 01:13:49 +03:00
fde640e997 0.0.283 add success_msg for forms, clear forms 2023-12-01 00:34:42 +03:00
SBD
fd1f4ff9b1 Merge remote-tracking branch 'origin/main' 2023-11-30 18:11:33 +03:00
SBD
3a4c1b12a6 0.8.445 2023-11-30 18:11:18 +03:00
ce68dbee8a 0.0.282 2023-11-30 18:07:04 +03:00
SDE
1976a4c1dc 0.8.8
processing send messages by mail
2023-11-30 17:46:18 +03:00
0dc3419651 0.0.281 2023-11-30 17:43:25 +03:00
7769608e03 Merge remote-tracking branch 'origin/main' 2023-11-30 17:26:02 +03:00
9772d7670b 0.0.280 upd confirm_remove button 2023-11-30 17:25:56 +03:00
SDE
36e9edb51b 0.8.7
processing send messages by mail
2023-11-30 16:03:37 +03:00
6191980dc7 0.0.278 2023-11-30 15:01:22 +03:00
7179b67137 0.0.278 2023-11-30 14:56:25 +03:00
65362e34b8 Merge remote-tracking branch 'origin/main' 2023-11-30 14:43:46 +03:00
ec76d336f3 0.0.277 upd carrier_card 2023-11-30 14:43:39 +03:00
SBD
12d5e4546d 0.8.444 2023-11-30 14:42:50 +03:00
SBD
4a97b02010 0.8.443 2023-11-30 14:28:37 +03:00
SDE
aa492f6ca4 0.8.6
fix find routes
2023-11-30 14:24:50 +03:00
SBD
7547d2cb89 0.8.442 2023-11-30 14:22:01 +03:00
SBD
3febf729b6 0.8.441 2023-11-30 14:13:25 +03:00
SDE
fbfdec2380 0.8.5
create_or_change_route_ajax return route_id
2023-11-30 14:06:57 +03:00
SBD
fb665b409c 0.8.440 2023-11-30 14:04:30 +03:00
SBD
f86e76615d 0.8.439 2023-11-30 13:49:45 +03:00
SBD
7cfe3f699a Merge remote-tracking branch 'origin/main' 2023-11-30 13:43:18 +03:00
SBD
03ab2ae2cd 0.8.438 2023-11-30 13:43:07 +03:00
SDE
ad1016a427 0.8.4
mail request_offer_ajax
2023-11-30 13:19:47 +03:00
SDE
6fc40452d9 0.8.3
request_offer_ajax
2023-11-30 08:15:02 +03:00
SDE
de098bdf55 0.8.2
fix articles
2023-11-30 07:41:22 +03:00
dcfd66324e Merge remote-tracking branch 'origin/main' 2023-11-29 22:09:17 +03:00
ff962b9658 0.0.276 2023-11-29 22:09:12 +03:00
SBD
006ff44858 Merge remote-tracking branch 'origin/main' 2023-11-29 22:03:42 +03:00
SBD
f9fdcc5314 0.8.437 2023-11-29 22:03:31 +03:00
e49605dea6 0.0.275 add data-set for forms in advertisement and partners pages 2023-11-29 22:00:03 +03:00
e429f48320 0.0.274 2023-11-29 21:48:25 +03:00
43ef016751 0.0.273 2023-11-29 21:28:42 +03:00
SBD
4a59adc73f Merge remote-tracking branch 'origin/main' 2023-11-29 21:24:07 +03:00
SBD
2ebc28519e 0.8.436 2023-11-29 21:23:59 +03:00
SDE
23de94b8cd 0.8.1
options init
2023-11-29 20:51:36 +03:00
42cf20137b 0.0.272 2023-11-29 20:50:24 +03:00
d5bb15e695 Merge remote-tracking branch 'origin/main' 2023-11-29 20:39:58 +03:00
039985fe5f 0.0.271 2023-11-29 20:39:49 +03:00
SBD
d618c10e8b Merge remote-tracking branch 'origin/main' 2023-11-29 20:34:10 +03:00
SBD
069f2094f0 0.8.434 2023-11-29 20:34:01 +03:00
SDE
2b6bbba265 0.8.0
options init
2023-11-29 20:18:22 +03:00
f7e032a5bc Merge remote-tracking branch 'origin/main' 2023-11-29 20:11:56 +03:00
0d394fb6b7 0.0.270 2023-11-29 20:11:51 +03:00
SBD
9635a1dcf2 0.8.433 2023-11-29 20:06:33 +03:00
SBD
6ae3a88d7b Merge remote-tracking branch 'origin/main' 2023-11-29 20:05:45 +03:00
SBD
512499ab12 0.8.432 2023-11-29 20:05:37 +03:00
b8e3092fc4 0.0.269 2023-11-29 20:03:49 +03:00
4b9e5e5f34 Merge remote-tracking branch 'origin/main' 2023-11-29 19:44:26 +03:00
a7d9dfe79a 0.0.268 all child are replaced 2023-11-29 19:44:20 +03:00
SDE
cc503ec6d1 Merge remote-tracking branch 'origin/main' 2023-11-29 19:21:22 +03:00
SDE
7eb8edbe1f 0.7.96
fix articles page
2023-11-29 19:21:15 +03:00
SBD
1f4ccaec4a 0.8.431 2023-11-29 19:11:26 +03:00
SBD
66e0edebc5 0.8.430 2023-11-29 19:11:08 +03:00
SBD
ebdc84f7e1 0.8.429 2023-11-29 19:05:40 +03:00
SBD
cd1b8d4579 0.8.428 2023-11-29 19:04:57 +03:00
SBD
a733649521 Merge remote-tracking branch 'origin/main' 2023-11-29 18:28:41 +03:00
SBD
01d72c5f45 0.8.427 2023-11-29 18:28:31 +03:00
SDE
55681c7fb8 0.7.95
meta names
2023-11-29 18:15:12 +03:00
SDE
4a19726a99 Merge remote-tracking branch 'origin/main' 2023-11-29 18:04:18 +03:00
SDE
61f26299b8 0.7.94
meta names
2023-11-29 18:04:06 +03:00
SBD
8a6317da2b 0.8.426 2023-11-29 18:01:03 +03:00
SBD
1124149cf8 0.8.425 2023-11-29 17:56:45 +03:00
426071fe15 Merge remote-tracking branch 'origin/main' 2023-11-29 17:52:55 +03:00
c97aa44723 0.0.267 replace all child for class or id 2023-11-29 17:52:49 +03:00
SDE
de6bd9682e Merge remote-tracking branch 'origin/main' 2023-11-29 17:51:12 +03:00
SDE
16e7ea3109 0.7.93
meta names
2023-11-29 17:50:59 +03:00
41fa14351a Merge remote-tracking branch 'origin/main' 2023-11-29 17:43:19 +03:00
35f135a10b 0.0.266 replace all child for class or id 2023-11-29 17:43:13 +03:00
SBD
037abac188 Merge remote-tracking branch 'origin/main' 2023-11-29 17:39:04 +03:00
SBD
fecd32a254 0.8.424 2023-11-29 17:38:53 +03:00
446af5e438 0.0.265 2023-11-29 17:30:26 +03:00
SDE
71ecd65814 0.7.92
FAQ show from admin
2023-11-29 17:26:59 +03:00
SBD
3e101493dc Merge remote-tracking branch 'origin/main' 2023-11-29 16:55:35 +03:00
SBD
453d4b7349 0.8.423 2023-11-29 16:55:26 +03:00
40a8bc158a Merge remote-tracking branch 'origin/main' 2023-11-29 16:55:24 +03:00
2c711ed370 0.0.264 upd previous_next_news widget 2023-11-29 16:55:17 +03:00
SDE
fc1654dedb 0.7.91
routes paging
2023-11-29 16:52:20 +03:00
SDE
dfec56fef9 0.7.90
articles paging
2023-11-29 16:38:12 +03:00
SDE
942db49daf Merge remote-tracking branch 'origin/main' 2023-11-29 16:36:18 +03:00
SDE
d4562e7ca4 0.7.89
articles paging
2023-11-29 16:36:10 +03:00
SBD
3a0845fe2a 0.8.422 2023-11-29 16:34:30 +03:00
SBD
3740ac642f Merge remote-tracking branch 'origin/main' 2023-11-29 16:33:37 +03:00
SBD
c1ccf00302 0.8.421 2023-11-29 16:33:28 +03:00
SDE
4400a6b13f 0.7.88
articles paging
2023-11-29 16:33:21 +03:00
SDE
66fbf984e9 0.7.87
articles paging
2023-11-29 16:29:48 +03:00
SBD
30ebc6037a Merge remote-tracking branch 'origin/main' 2023-11-29 16:26:17 +03:00
SBD
ac60b08f2d 0.8.420 2023-11-29 16:26:00 +03:00
f32e127148 0.0.263 resize to mobile since 1180px 2023-11-29 16:18:13 +03:00
SBD
8e3b798bce 0.8.419 2023-11-29 15:58:18 +03:00
SBD
57dddf528b 0.8.418 2023-11-29 15:52:31 +03:00
SBD
35d5e05f00 Merge remote-tracking branch 'origin/main' 2023-11-29 15:51:58 +03:00
SBD
4ecc89a4e7 0.8.417 2023-11-29 15:51:50 +03:00
SDE
87bc1be15a 0.7.86
fix left curtain arrows
2023-11-29 15:46:33 +03:00
SDE
b1c599e71d Merge remote-tracking branch 'origin/main' 2023-11-29 15:44:05 +03:00
SDE
da3fb36a22 0.7.85
fix css error
2023-11-29 15:43:45 +03:00
SBD
ded7761c91 Merge remote-tracking branch 'origin/main' 2023-11-29 15:41:59 +03:00
SBD
d4de2ef739 0.8.416 2023-11-29 15:41:45 +03:00
SDE
7637f6fdd1 Merge remote-tracking branch 'origin/main' 2023-11-29 15:38:11 +03:00
SDE
f663954f03 0.7.84
fix left curtain icon
2023-11-29 15:38:04 +03:00
SBD
f2fd95b04e 0.8.415 2023-11-29 15:24:12 +03:00
SBD
3880b97cae 0.8.414 2023-11-29 15:22:33 +03:00
SBD
2fb00ee112 0.8.413 2023-11-29 15:14:20 +03:00
SBD
dc92877beb 0.8.412 2023-11-29 15:05:13 +03:00
SBD
d9103e62a7 0.8.411 2023-11-29 15:00:28 +03:00
e5a8c3cb8f 0.0.262 add switch on main page 2023-11-29 14:59:20 +03:00
97b00d94cf 0.0.261 style updates 2023-11-28 17:47:52 +03:00
SBD
381f0a8490 0.8.410 2023-11-28 15:29:42 +03:00
SBD
b8b3fd02fa 0.8.409 2023-11-28 15:25:31 +03:00
SBD
3b244f4de0 Merge remote-tracking branch 'origin/main' 2023-11-28 14:48:23 +03:00
SBD
c4d101275a 0.8.408 2023-11-28 14:48:14 +03:00
c9b21ded98 0.0.260 bug fix 2023-11-28 14:33:24 +03:00
SBD
f5115f82fb 0.8.407 2023-11-28 14:29:29 +03:00
SBD
d6a6b4f319 0.8.406 2023-11-27 18:28:44 +03:00
SBD
f3e418cf68 Merge remote-tracking branch 'origin/main' 2023-11-27 18:24:05 +03:00
SBD
a74a0c1f57 0.8.405 2023-11-27 18:23:51 +03:00
0f10e274e6 0.0.259 small upd for styles 2023-11-27 18:21:33 +03:00
SBD
57a419eeaa 0.8.404 2023-11-27 18:17:20 +03:00
SBD
aa18a3c542 0.8.403 2023-11-25 22:03:54 +03:00
SBD
dea8d064d4 0.8.402 2023-11-25 21:54:45 +03:00
SBD
d022fb231f Merge remote-tracking branch 'origin/main' 2023-11-25 21:49:33 +03:00
SBD
415784bf06 0.8.401 2023-11-25 21:49:24 +03:00
SDE
246974c1b8 0.7.83
fix ticket first msg
2023-11-25 18:10:38 +03:00
SDE
34d2fea31f 0.7.82
correct padding
2023-11-25 17:17:10 +03:00
SDE
0571de3dd0 0.7.82
loader correct
2023-11-25 17:14:17 +03:00
SBD
4e2d453ff1 0.8.400 2023-11-25 16:48:26 +03:00
SDE
f4ba38654b 0.7.81
curtain right rule for mobile into get params
2023-11-25 16:40:07 +03:00
SDE
7831973cdb 0.7.80
FAQ admin
2023-11-25 16:31:10 +03:00
SBD
4f2c7aeb2c 0.8.399 2023-11-25 15:37:37 +03:00
SBD
237666d96f 0.8.398 2023-11-25 15:34:54 +03:00
SBD
f6d0486a19 0.8.397 2023-11-25 15:26:30 +03:00
SBD
200a9c308c 0.8.396 2023-11-25 15:14:09 +03:00
SBD
28d3138c43 0.8.395 2023-11-25 14:07:03 +03:00
SBD
0d41c95e3d 0.8.394 2023-11-25 13:53:23 +03:00
SBD
e5ea92df3d 0.8.393 2023-11-25 13:21:53 +03:00
SBD
9f7550eaae 0.8.392 2023-11-25 13:14:55 +03:00
SBD
3e88458fce 0.8.391 2023-11-25 13:08:15 +03:00
SBD
a5cbf8c128 0.8.390 2023-11-25 12:58:06 +03:00
SBD
704b88320a Merge remote-tracking branch 'origin/main' 2023-11-25 12:48:50 +03:00
SBD
0aae04eca8 0.8.398 2023-11-25 12:48:15 +03:00
3f1cd5431f 0.0.258 small_upd for articles 2023-11-24 19:35:11 +03:00
SBD
5081b6ce3e 0.8.397 2023-11-24 17:36:54 +03:00
SBD
7e7fb437a6 0.8.396 2023-11-24 17:19:45 +03:00
SBD
addca29f0f 0.8.395 2023-11-24 17:13:25 +03:00
SBD
f1775237fb Merge remote-tracking branch 'origin/main' 2023-11-24 16:49:19 +03:00
SBD
f09ff3f7df 0.8.394 2023-11-24 16:48:38 +03:00
4259f84764 Merge remote-tracking branch 'origin/main' 2023-11-24 16:39:56 +03:00
707bbf1863 0.0.257 return form in create_new_route 2023-11-24 16:38:24 +03:00
SBD
a989f85b2b 0.8.393 2023-11-24 16:37:29 +03:00
SBD
b62396a907 Merge remote-tracking branch 'origin/main' 2023-11-24 16:34:21 +03:00
SBD
998c91c727 0.8.393 2023-11-24 16:34:13 +03:00
64b8e74612 Merge remote-tracking branch 'origin/main' 2023-11-24 16:09:47 +03:00
55eff16b9c 0.0.256 2023-11-24 16:09:38 +03:00
SBD
31857131be Merge remote-tracking branch 'origin/main' 2023-11-24 16:08:18 +03:00
SBD
77de950af8 0.8.392 2023-11-24 16:08:09 +03:00
176c84cf2d 0.0.255 2023-11-24 13:33:38 +03:00
15ea6a982c 0.0.254 upd filds in support 2023-11-23 16:55:45 +03:00
6230b77473 0.0.253 small rewrite for button with name in header 2023-11-23 01:10:46 +03:00
2f81a73078 0.0.252 add type_transport icons for finded routes 2023-11-22 16:33:16 +03:00
cf83ae059e Merge remote-tracking branch 'origin/main' 2023-11-22 16:31:01 +03:00
4418d4ad6f 0.0.250 fix bug with the same icons in the filter 2023-11-22 16:30:53 +03:00
SBD
239b6a0da1 0.8.391 2023-11-22 15:24:21 +03:00
SBD
cc02495459 Merge remote-tracking branch 'origin/main' 2023-11-22 15:22:26 +03:00
SBD
153d0380de 0.8.390 2023-11-22 15:21:49 +03:00
87fb930c63 0.0.250 fix bug with menu_profile 2023-11-22 14:39:31 +03:00
SBD
38a8cef3d9 0.8.388 2023-11-21 23:14:16 +03:00
SBD
6f7551abbf 0.8.387 2023-11-21 22:43:42 +03:00
SBD
64d6860e58 0.8.386 2023-11-21 22:22:02 +03:00
SBD
88e6c7eee8 0.8.385 2023-11-21 21:53:10 +03:00
SBD
75c5553852 0.8.384 2023-11-21 21:46:03 +03:00
SBD
9d1815c21f 0.8.383 2023-11-21 21:44:22 +03:00
SBD
c93cda4eaf 0.8.382 2023-11-21 20:53:14 +03:00
SBD
cce969d870 0.8.381 2023-11-21 20:30:07 +03:00
SBD
0b177d845c 0.8.380 2023-11-21 20:23:41 +03:00
SBD
42f288e0e4 0.8.379 2023-11-21 20:19:17 +03:00
3948c79891 0.0.249 add cursor pointer 2023-11-21 19:09:13 +03:00
c8a28de46a 0.0.248 add translate for placeholders 2023-11-21 18:49:50 +03:00
c660d8cb72 0.0.247 add translate for words with letter А 2023-11-21 18:29:02 +03:00
SDE
a2688c4a15 Merge remote-tracking branch 'origin/main' 2023-11-21 17:37:21 +03:00
SDE
9d2e9b7acd 0.7.80
FAQ admin
2023-11-21 17:37:12 +03:00
f37ed72b39 0.0.246 2023-11-21 13:41:11 +03:00
6fd3c11f06 0.0.245 small upd for w_carrier_card 2023-11-20 22:42:05 +03:00
414ffc703d 0.0.244 upd w_carrier_card.html and mobile_styles.css for this widget 2023-11-20 20:58:49 +03:00
f7a587b7a5 0.0.243 upd bug from 17:11 to 17:52 2023-11-20 15:20:40 +03:00
534defa36b 0.0.242 upd css for create route 2023-11-20 00:44:07 +03:00
1fbf846270 0.0.241 upd carrier-card 2023-11-20 00:21:12 +03:00
e6a1cd967e Merge remote-tracking branch 'origin/main' 2023-11-19 22:41:46 +03:00
c9adf1a785 0.0.240 2023-11-19 22:41:41 +03:00
SBD
8380b7e66e Merge remote-tracking branch 'origin/main' 2023-11-19 21:18:32 +03:00
SBD
e01c7e81f2 0.8.378 2023-11-19 21:18:23 +03:00
4751dd9079 Merge remote-tracking branch 'origin/main' 2023-11-19 20:03:32 +03:00
f82ae16e31 0.0.239 fix menu_profile, main search widget, benefit_img, header hide menu, header, title in cusmer page 2023-11-19 20:03:26 +03:00
SBD
8a00446b5c Merge remote-tracking branch 'origin/main' 2023-11-19 19:46:40 +03:00
SBD
39f37bcd23 0.8.377 2023-11-19 19:46:30 +03:00
c8e4df8150 0.0.238 bug fix - footer, faq, my_profile 2023-11-19 19:00:23 +03:00
1e9e2cb048 Merge remote-tracking branch 'origin/main' 2023-11-19 18:12:24 +03:00
06661cb187 0.0.237 2023-11-19 18:12:19 +03:00
SBD
fade021048 Merge remote-tracking branch 'origin/main' 2023-11-19 18:04:01 +03:00
SBD
9d90138847 0.8.376 2023-11-19 18:03:49 +03:00
b7a677d79d 0.0.236 bug fix tg 14:26 2023-11-19 17:45:10 +03:00
SBD
3660f5af6d 0.8.375 2023-11-19 17:07:08 +03:00
SBD
61e1c35f02 Merge remote-tracking branch 'origin/main' 2023-11-19 17:05:30 +03:00
SBD
89721ce797 0.8.374 2023-11-19 17:05:21 +03:00
55b4c0ac11 Merge remote-tracking branch 'origin/main' 2023-11-19 16:44:32 +03:00
70df8a53c8 0.0.235 add scroll to element in static pages 2023-11-19 16:44:26 +03:00
SBD
3311ab5b37 0.8.373 2023-11-19 15:49:39 +03:00
SBD
49ad367a70 0.8.372 2023-11-19 15:26:55 +03:00
SBD
cc3a5c4a4f 0.8.371 2023-11-19 15:09:39 +03:00
SBD
f7af979b7e 0.8.370 2023-11-19 14:58:02 +03:00
SBD
6f06f96a94 0.8.369 2023-11-19 14:52:52 +03:00
a3ef86ba37 0.0.234 small bug fix 2023-11-19 14:47:21 +03:00
SBD
d6da292d5f 0.8.368 2023-11-19 14:38:10 +03:00
SBD
ccb8c6585c 0.8.367 2023-11-19 14:20:59 +03:00
SBD
ea567008c6 0.8.366 2023-11-18 21:55:28 +03:00
SBD
6cbde10b11 Merge remote-tracking branch 'origin/main' 2023-11-18 18:39:43 +03:00
SBD
7e23776501 0.8.365 2023-11-18 18:39:25 +03:00
e6a91ebc72 Merge remote-tracking branch 'origin/main' 2023-11-18 18:38:58 +03:00
06a2e883fb 0.0.233 add margin for header and main_content 2023-11-18 18:38:53 +03:00
SBD
00b0e00fd3 Merge remote-tracking branch 'origin/main' 2023-11-18 18:38:20 +03:00
SBD
8086d5344e 0.8.364 2023-11-18 18:38:07 +03:00
ea76733305 Merge remote-tracking branch 'origin/main' 2023-11-18 18:36:05 +03:00
f0f8af48b3 0.0.232 add margin for header and main_content 2023-11-18 18:35:59 +03:00
SBD
9bc02c7752 Merge remote-tracking branch 'origin/main' 2023-11-18 18:29:38 +03:00
SBD
3067535fe0 0.8.363 2023-11-18 18:29:28 +03:00
174 changed files with 26141 additions and 2389 deletions

1
.gitignore vendored
View File

@@ -414,4 +414,5 @@ fabric.properties
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
celerybeat-schedule.db

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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 =_("Статьи")

View File

@@ -0,0 +1 @@
__author__ = 'SDE'

View 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

View File

@@ -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))

View File

@@ -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)

View File

@@ -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 уже существует"))

View File

@@ -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

View File

@@ -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')
]

View File

@@ -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}

View File

@@ -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)

View 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='Рассылка'),
),
]

View File

@@ -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:

View File

@@ -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'),

View File

@@ -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''

View 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)

View File

@@ -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:

View File

@@ -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

View File

@@ -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

View File

@@ -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'

View File

@@ -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)

View File

@@ -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')

View File

@@ -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 = []

View File

@@ -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": {

View File

@@ -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

View 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

View File

@@ -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'
]

View File

@@ -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)

View File

@@ -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}

View File

@@ -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 = _('Сообщение')

View File

@@ -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:

View File

@@ -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)

View 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

View File

@@ -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))

View 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)

View 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

View File

@@ -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='Значение'),
),
]

View File

@@ -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:

View File

@@ -154,3 +154,7 @@ def get_color_by_number(value, arg=None):
#
# return s

View File

@@ -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 = (

View File

@@ -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
View File

3
PushMessages/admin.py Normal file
View File

@@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

6
PushMessages/apps.py Normal file
View File

@@ -0,0 +1,6 @@
from django.apps import AppConfig
class PushmessagesConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'PushMessages'

View File

3
PushMessages/models.py Normal file
View File

@@ -0,0 +1,3 @@
from django.db import models
# Create your models here.

3
PushMessages/tests.py Normal file
View File

@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

16
PushMessages/urls.py Normal file
View 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
View 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
View File

@@ -0,0 +1,3 @@
celery -A TWB.celery:app worker -l info
celery -A TWB.celery:app beat -l info

View File

@@ -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

View File

@@ -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:

View File

@@ -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)

View File

@@ -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':

View File

@@ -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

View File

@@ -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:

View File

View 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)} -')

View 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')

View File

@@ -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
View 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

View File

@@ -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))

View File

@@ -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']

View File

@@ -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='Цвет текста'),
),
]

View 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
View 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'),
]

View File

@@ -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)

View File

@@ -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
View 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

View File

@@ -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
View 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
View 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)

View File

@@ -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
View File

@@ -0,0 +1,8 @@
EMAIL_HOST_USER=
EMAIL_HOST_PASSWORD=
POSTGRES_DB=
POSTGRES_USER=
CELERY_BROKER_URL=
CELERY_RESULT_BACKEND=

View File

@@ -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

View File

@@ -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

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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;
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

View 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

View 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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View 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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

View 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

View 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

View File

@@ -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')

Some files were not shown because too many files have changed in this diff Show More