937 Commits

Author SHA1 Message Date
f6f4bfa2ab reklama code insert 2025-03-21 17:53:06 +03:00
f625537b6f reklama code insert 2025-03-21 17:52:35 +03:00
794d5e810d reklama code insert 2025-03-21 16:58:12 +03:00
a5c0985093 reklama code insert 2025-03-21 16:54:43 +03:00
70b481480f reklama code insert 2025-03-21 16:53:40 +03:00
a37e009109 reklama code insert 2025-03-21 16:52:37 +03:00
191ceaca36 reklama code insert 2025-03-21 16:51:46 +03:00
53ec69d27c reklama code insert 2025-03-21 16:50:03 +03:00
26f29e4353 reklama code insert 2025-03-21 16:47:19 +03:00
e1f239d6ee reklama code insert 2025-03-21 16:44:30 +03:00
355abb1add yandex code insert 2025-03-21 16:40:27 +03:00
a3795dd267 tik tok code insert 2025-03-21 15:37:40 +03:00
90ffcd090c tik tok code insert 2025-03-21 15:37:05 +03:00
acb52aef73 Merge remote-tracking branch 'origin/dev' into dev 2025-03-11 10:59:50 +03:00
fa04e5275f google code insert 2025-03-11 10:59:39 +03:00
SBD
0288c05e2b correct registration js metrics 2025-03-05 15:03:41 +03:00
9c96d8c253 pixel code replace 2025-02-24 13:31:54 +03:00
SBD
423394a9d9 0.0.165 routes 2025-02-17 22:53:58 +03:00
SDE
3b0e1f6524 2.1.39 fix users_notify_by_result_search_matches 2025-02-17 18:22:23 +03:00
c57eec05c9 pixel code replace 2025-02-12 15:01:47 +03:00
197f910b82 pixel code replace 2025-02-12 15:00:30 +03:00
a940f2ff0d pixel code replace 2025-02-10 17:17:09 +03:00
66a1170221 pixel code replace 2025-02-10 14:59:53 +03:00
5f403710d1 pixel code replace 2025-02-09 01:07:16 +03:00
529fb3fc5d pixel code replace 2025-02-07 11:21:34 +03:00
cae627f0b0 facebook domain verification add 2025-02-03 00:49:56 +03:00
5ff75a4a80 facebook domain verification add 2025-02-03 00:32:03 +03:00
80deab3c42 facebook domain verification add 2025-02-03 00:12:08 +03:00
6030998018 facebook domain verification add 2025-01-29 09:45:18 +03:00
abaff023cd facebook domain verification add 2025-01-27 23:16:40 +03:00
4dbe424f84 meta pixel add 2025-01-24 18:05:48 +03:00
7488a9f8c8 telegram link fix 2025-01-17 14:52:56 +03:00
SDE
b759ce2d5a 2.1.23 fix send support mail 2025-01-16 15:28:06 +03:00
84c88ba406 telegram link fix 2024-12-13 16:41:40 +03:00
b2f7612452 TRI-303 correct texts mistakes 2024-12-11 14:54:56 +03:00
09769542f9 TRI-302 add yandex metrika and goals for buttons and urls for landings 2024-12-09 12:19:29 +03:00
a90d7c06a9 TRI-302 add yandex metrika for landings 2024-12-07 16:22:23 +03:00
SDE
4ce12a5428 1.8.11 fix stat landings 2024-12-05 14:02:24 +03:00
7ba65e73ae TRI-283: fix video2 2024-12-04 15:00:44 +03:00
4a58a47a8e TRI-283: fix video1 2024-12-04 10:02:23 +03:00
e8506e1b4e TRI-297 add facebook pixel 2024-12-03 23:33:09 +03:00
61805df66b TRI-297 add facebook pixel 2024-12-03 12:47:18 +03:00
e98d426324 TRI-297 add facebook pixel 2024-12-03 12:46:13 +03:00
6c062ce3c8 TRI-297 add facebook pixel 2024-12-03 12:43:29 +03:00
8f47d4fb65 TRI-283: reload images 2024-12-02 13:38:09 +03:00
63e507d0ff TRI-283: reload images + text edit 2024-11-29 13:39:44 +03:00
5a16466766 Merge remote-tracking branch 'origin/dev' into dev 2024-11-28 13:37:30 +03:00
4b0c923ec0 1.3.6 recovery password TRI-261 2024-11-28 13:37:14 +03:00
87f67aa24a TRI-283: fix nags 2024-11-28 07:47:48 +03:00
93e48f3cbc TRI-283: fix scroll 2024-11-27 16:23:28 +03:00
baadc67fcf Merge remote-tracking branch 'origin/dev' into dev 2024-11-27 16:14:00 +03:00
bc16aea3a4 1.3.5 registration TRI-265 2024-11-27 16:13:50 +03:00
8041e3eb4d TRI-283: edit fixed 2024-11-27 15:54:51 +03:00
3e4c0b2ab5 1.3.4 TRI-288 phone in my routes 2024-11-27 15:50:47 +03:00
960c9ba5b0 Merge remote-tracking branch 'origin/dev' into dev 2024-11-27 15:38:19 +03:00
3efec91d74 1.3.3 TRI-288 phone in my routes 2024-11-27 15:38:05 +03:00
9e48c72245 TRI-283: edit bg 2024-11-27 15:31:03 +03:00
4dac9a5eec TRI-283: edit sticky2 2024-11-27 15:09:34 +03:00
bf25c67f1e TRI-283: edit sticky 2024-11-27 15:04:29 +03:00
1245899c07 TRI-283: edit ыешслн 2024-11-27 15:02:24 +03:00
66f25b6937 TRI-283: edit img 2024-11-27 14:55:46 +03:00
2d44edf5ab TRI-283: edit some code 2024-11-27 14:41:38 +03:00
7062c756b6 TRI-283: edit customer 2024-11-27 12:24:21 +03:00
7c173c9195 TRI-283: edit mover 2024-11-27 12:06:11 +03:00
e070ab15ac TRI-283: edit 2 height btn, text, image 2024-11-27 10:15:51 +03:00
400498c6fa TRI-283: edit height btn, text, image 2024-11-27 10:14:03 +03:00
3c5331c2d3 TRI-283: edit images xs 2024-11-23 09:00:55 +03:00
800b7ba493 TRI-283: edit dropdown 2024-11-22 15:21:54 +03:00
bc2689d1cf TRI-283: edit logo 2024-11-22 13:55:53 +03:00
ce9be11c0a TRI-283: post btns 2024-11-22 12:44:54 +03:00
43ba192496 TRI-283: edit footer 2024-11-22 12:38:11 +03:00
ee410315ee TRI-283: edit btns 2024-11-22 12:20:27 +03:00
f3c78f0575 TRI-283: end editors pages 2024-11-22 08:59:49 +03:00
b98a4a5364 TRI-283: edits btns reg landing_page 2024-11-22 07:24:46 +03:00
68aad97e46 TRI-283: save for show p_customer_landing_page 2024-11-22 06:38:22 +03:00
8de6676b40 TRI-283: end p_mover_landing_page 2024-11-21 19:49:38 +03:00
7a345a6c80 TRI-283: edit chatterbox 2024-11-21 14:24:47 +03:00
e3adbeeea4 TRI-283: start 768> 2024-11-21 13:10:25 +03:00
b0db3534f2 TRI-283: add feader fixed 2024-11-20 22:55:34 +03:00
6f646264dc TRI-283: end 1280 2024-11-20 22:00:18 +03:00
d83940b47d TRI-283: end header + start adaptive 1400> 2024-11-20 01:38:34 +03:00
4996d02f71 TRI-283: end adaptive 1920 + start header 2024-11-19 00:25:47 +03:00
SDE
da6f47f439 1.8.9 p_customer_landing_page.html media_items 2024-11-18 15:46:07 +03:00
SDE
54fbc3f4b2 1.8.8 p_mover_landing_page.html media_items 2024-11-18 15:38:28 +03:00
SDE
6e2c54eccf 1.8.7 Billing migrations 2024-11-17 16:48:38 +03:00
89166100e3 TRI-283: start adaptive 1920 2024-11-16 20:03:47 +03:00
3d28a1ee86 TRI-283: end pade move 2024-11-16 18:28:26 +03:00
034d5faa0d TRI-283: add scss posterinvideo 2024-11-16 15:02:40 +03:00
f58038ab90 TRI-283: add benefits animate about 2024-11-15 21:07:29 +03:00
SDE
ad25cc67ec 1.8.6 search_matches fix weight params 2024-11-15 18:21:17 +03:00
SDE
384d1e8aec 1.8.5 search_matches fix weight params 2024-11-15 17:12:40 +03:00
SDE
b0a1007a76 1.8.4 media for landing 2024-11-15 16:21:40 +03:00
SDE
0419ba7847 1.8.3 media for landing 2024-11-15 16:05:07 +03:00
SDE
c52dbca9a1 1.8.2 media for landing 2024-11-15 15:14:50 +03:00
SDE
43153a9fdf Merge remote-tracking branch 'origin/dev' into dev 2024-11-15 13:55:04 +03:00
SDE
c23dd1ff4c 1.8.1 landing_customer 2024-11-15 13:54:53 +03:00
67d9528614 TRI-283: добавил и настроил видео 2024-11-15 13:48:11 +03:00
1151744247 TRI-283: вёрстка лендинга 2024-11-14 21:10:53 +03:00
9dd3fbe47d youtube link repair 2024-11-14 14:39:39 +03:00
f42e155f2b add some code 2024-11-13 23:49:01 +03:00
SDE
f5a084684a 1.8.0 landing_mover 2024-11-12 20:05:07 +03:00
SDE
b22adac365 1.7.19 get_my_routes_ajax log fail 2024-11-12 17:34:49 +03:00
SDE
a329720f1c 1.7.18 w_carrier_card.html fix route.highlight_end_DT 2024-11-12 16:04:12 +03:00
SDE
e03f4a015a 1.7.18 generate routes 2024-11-12 14:06:58 +03:00
SDE
94f677ae6f 1.7.17 get_routes_Dict send techmail if user undefined 2024-11-12 12:52:46 +03:00
SDE
8afdfc87c5 1.7.16 registration send mail test 2024-11-12 12:42:10 +03:00
cc3739f701 Merge remote-tracking branch 'origin/dev' into dev 2024-11-12 12:33:27 +03:00
dbee8dabb1 1.3.2 phone is not required TRI-249, TRI-265 2024-11-12 12:33:10 +03:00
SDE
cfb7acfddb 1.7.15 fix user_profile.js 1312 2024-11-12 12:15:52 +03:00
SDE
e14072e829 1.7.15 fix registration.js 71 2024-11-12 12:01:28 +03:00
SDE
f80f8d8c7e 1.7.14 route phone is not exists 2024-11-12 10:51:40 +03:00
SDE
e9b3dc1da9 1.7.13 route phone is not exists 2024-11-12 10:50:15 +03:00
63137188e5 instagram link repair 2024-11-11 07:38:36 +03:00
Rewardio
07031d693c TRI-265 adding checks to eliminate getting null at classList.add 2024-11-08 17:01:44 +03:00
SDE
531955bdc7 Merge remote-tracking branch 'origin/dev' into dev 2024-11-06 15:52:02 +03:00
SDE
2cfa314c3c 1.7.12 fix search_matches sendmail link 2024-11-06 15:51:54 +03:00
cfe37ec57d 1.3.1 counters in footer TRI-276 2024-11-01 14:58:11 +03:00
995733d6e3 TRI-275 disable googlesindicator script in head section 2024-10-25 13:04:25 +03:00
aec622831d TRI-275 disable googlesindicator script in head section 2024-10-25 13:03:17 +03:00
e8f092a88b TRI-275 disable googlesindicator script in head section 2024-10-24 10:39:15 +03:00
a1da574c04 TRI-274 replace password recovery text 2024-10-23 13:54:33 +03:00
08e28d14c9 TRI-274 replace password recovery text 2024-10-23 13:44:47 +03:00
cffd810184 TRI-274 replace password recovery text 2024-10-23 13:31:28 +03:00
SDE
774ee85f8d 1.7.11 Admin_Route add search_fields 2024-10-22 17:11:34 +03:00
SDE
a1c6db28a8 1.7.10 Admin_Route add search_fields 2024-10-22 17:06:29 +03:00
SDE
bcd0c8900d 1.7.9 fix html b_profile call to select_tab_profile 2024-10-21 14:15:57 +03:00
SDE
f3e3b608f1 1.7.8 fix js dublicates login section 2024-10-21 13:42:32 +03:00
SDE
a839114cdf 1.7.7 fix js dublicates login section 2024-10-21 13:24:08 +03:00
SDE
a315a52791 Merge remote-tracking branch 'origin/dev' into dev 2024-10-21 12:53:00 +03:00
SDE
fc0d9f07c0 1.7.6 fix get_profile_change_page_content_html 2024-10-21 12:52:51 +03:00
26b4b77271 TRI-262 replace invocation in subscription mail template 2024-10-18 00:46:08 +03:00
SDE
09cfe8938f Merge remote-tracking branch 'origin/dev' into dev 2024-10-17 17:58:05 +03:00
SDE
8989d13928 1.7.5 admin search for Admin_SubscribeForUser 2024-10-17 17:56:47 +03:00
a39c96cc61 TRI-260 replace placeholder login 2024-10-10 14:30:19 +03:00
db8beca609 TRI-260 replace placeholder login 2024-10-10 14:28:35 +03:00
94e7881aa0 fix tiktok link 2024-10-05 11:23:33 +03:00
e4a07e2c88 TRI-258 Replace logo in email templates 2024-10-02 13:36:32 +03:00
1414003e3f TRI-258 Replace logo in email templates 2024-10-02 13:30:56 +03:00
b9f4804d74 Merge pull request 'main' (#13) from main into dev
Reviewed-on: #13
2024-10-02 13:22:01 +03:00
e2b63f6706 Merge remote-tracking branch 'origin/dev' into dev 2024-09-24 15:05:13 +03:00
393f165095 1.3.0 get_routes in my_routes TRI-251 2024-09-24 15:05:01 +03:00
547e4e8f9f TRI-258 Replace logo in email templates 2024-09-24 02:28:59 +03:00
ffeab227c9 TRI-258 Replace logo in email templates 2024-09-23 23:35:51 +03:00
4452398773 TRI-258 Replace logo in email templates 2024-09-23 23:34:03 +03:00
454f4711f3 TRI-258 Replace logo in email templates 2024-09-23 23:31:52 +03:00
46c456af2c TRI-258 Replace logo in email templates 2024-09-23 23:29:26 +03:00
2f459e982a TRI-258 Replace logo in email templates 2024-09-23 23:25:40 +03:00
b8d934fa28 TRI-258 Replace logo in email templates 2024-09-23 23:22:14 +03:00
1107c01d5c TRI-258 Replace logo in email templates 2024-09-23 23:18:21 +03:00
b8ca85c20e TRI-258 Replace logo in email templates 2024-09-23 23:16:57 +03:00
a29cf29041 TRI-258 Replace logo in email templates 2024-09-23 23:13:55 +03:00
05bf1d59df TRI-258 Replace logo in email templates 2024-09-23 23:08:01 +03:00
2cf129d0b9 TRI-258 Replace logo in email templates 2024-09-23 23:03:01 +03:00
488cd72f2c 1.2.9 add favicon TRI-255 2024-09-23 23:01:07 +03:00
6fab07fd79 1.2.8 add favicon TRI-255 2024-09-23 16:32:23 +03:00
382b2d122c 1.2.7 comment popup TRI-257 2024-09-23 16:08:11 +03:00
b4beac26a7 1.2.6 password recovery TRI-108 2024-09-23 16:02:27 +03:00
SDE
86d78fdd06 1.7.4 password recovery 2024-09-20 20:41:42 +03:00
SDE
92ad985355 1.7.3 password recovery 2024-09-20 18:51:53 +03:00
SDE
eaf94f0ceb 1.7.2 password recovery 2024-09-20 18:43:37 +03:00
SDE
acee0ccec5 1.7.1 password recovery 2024-09-20 18:32:18 +03:00
fddea097d3 1.2.6 password recovery TRI-108 2024-09-20 18:16:00 +03:00
SDE
7dc25532a3 1.7.0 password recovery 2024-09-20 16:43:33 +03:00
SDE
19721cf5da Merge remote-tracking branch 'origin/dev' into dev 2024-09-10 13:51:14 +03:00
SDE
a6d9d1595a 1.6.19 generate routes w change date 2024-09-10 13:51:04 +03:00
5e0d5f4b91 TRI-254 Replace placeholder text for registration form 2024-09-09 23:49:40 +03:00
09a6de1544 TRI-254 Replace placeholder text for registration form 2024-09-09 23:42:13 +03:00
a20b502b70 TRI-254 Replace placeholder text for registration form 2024-09-09 23:40:15 +03:00
8bb8013f67 TRI-254 Replace placeholder text for registration form 2024-09-09 23:37:37 +03:00
94c7c54cc1 TRI-254 Replace placeholder text for registration form 2024-09-09 23:36:19 +03:00
c257d22618 TRI-254 Replace placeholder text for registration form 2024-09-09 23:34:14 +03:00
b57dbb75e8 TRI-254 Replace placeholder text for registration form 2024-09-09 23:30:22 +03:00
9781f33440 TRI-254 Replace placeholder text for registration form 2024-09-09 23:29:33 +03:00
45b4236748 TRI-254 Replace placeholder text for registration form 2024-09-09 23:23:33 +03:00
8b0c82c3ca TRI-254 Replace placeholder text for registration form 2024-09-09 23:21:46 +03:00
5518a99ee9 TRI-254 Replace placeholder text for registration form 2024-09-09 23:20:39 +03:00
63124a350e Replace Main text on main page 2024-09-09 23:16:25 +03:00
SDE
c7de08ca49 Merge remote-tracking branch 'origin/dev' into dev 2024-09-09 16:45:29 +03:00
SDE
41e4b23317 1.6.18 fix reset highlight after change route 2024-09-09 16:45:20 +03:00
b23f379db0 1.2.5 new init for calendar in create_route TRI-247 2024-09-05 11:26:50 +03:00
SDE
1faf9e0cc7 Merge remote-tracking branch 'origin/dev' into dev 2024-09-02 15:14:17 +03:00
SDE
90e1a87bf4 1.6.17 registration not required phone 2024-09-02 15:14:06 +03:00
9ec8d4189f Replace Main text on main page 2024-08-29 23:53:13 +03:00
8f08e360ef Replace Main text on main page 2024-08-29 23:52:18 +03:00
SDE
4371cd1a85 1.6.16 generate routes road 2024-08-26 17:55:49 +03:00
SDE
f6ba0ab1ad 1.6.15 split send mail to user and copy for dev 2024-08-23 15:19:33 +03:00
SDE
c60b9942f6 Merge remote-tracking branch 'origin/dev' into dev 2024-08-22 13:41:47 +03:00
SDE
85f6e69d63 1.6.14 generate routes 2024-08-22 13:41:34 +03:00
83aeab9341 1.2.4 upd meta_OpenGraph_Schema.html TRI-200 2024-08-20 13:27:29 +03:00
8a539a2868 1.2.2 limitation of color selection for 24 hours TRI-228 2024-08-20 12:18:52 +03:00
379db1cb39 Merge pull request '1.2.2 upd mover search card TRI-246' (#12) from dev into main
Reviewed-on: #12
2024-08-19 18:03:25 +03:00
e51b23cb91 1.2.2 upd mover search card TRI-246 2024-08-19 16:27:31 +03:00
e824a258ea Merge pull request 'dev' (#11) from dev into main
Reviewed-on: #11
2024-08-18 17:48:09 +03:00
SDE
526f035659 1.6.13 fix next package for my_routes 2024-08-13 15:03:20 +03:00
SDE
42c2843cab 1.6.12 fix next package for my_routes 2024-08-13 14:41:11 +03:00
SDE
a99ffcc9d2 1.6.11 fix next package for my_routes 2024-08-13 12:58:41 +03:00
40a2412b9b 1.2.2 add url check for my_route dynamic_loading_routes.js 2024-08-13 12:49:08 +03:00
cd2985a170 Merge pull request 'Add text if email in spam and translate it' (#10) from dev into main
Reviewed-on: #10
2024-08-09 23:50:40 +03:00
cb84352475 Add text if email in spam and translate it 2024-08-09 23:49:10 +03:00
a19b4fe212 Merge pull request 'dev' (#9) from dev into main
Reviewed-on: #9
2024-08-09 22:44:34 +03:00
SDE
f718df47c8 Merge remote-tracking branch 'origin/dev' into dev 2024-08-09 21:53:33 +03:00
SDE
7620f97042 1.6.10 adds for search timezone for cities 2024-08-09 21:53:25 +03:00
3bfb7d040d Merge pull request 'replace tb_base.html' (#8) from dev into main
Reviewed-on: #8
2024-08-09 21:08:58 +03:00
aea50ed806 replace tb_base.html 2024-08-09 21:08:02 +03:00
7dab17905b Merge pull request 'dev' (#7) from dev into main
Reviewed-on: #7
2024-08-09 18:55:31 +03:00
a3a3565189 add rightpaneluser from dev 2024-08-09 18:53:53 +03:00
3f82f42e1e add chatsocketfunctions from dev 2024-08-09 18:52:23 +03:00
0de00c5a34 add chatsocketfunctions from dev 2024-08-09 18:51:14 +03:00
0daee07086 add models.py from dev 2024-08-09 18:49:10 +03:00
2619539415 add django.po from dev 2024-08-09 18:46:00 +03:00
aa8bed6efb add tb_base from main 2024-08-09 18:42:48 +03:00
9b01d79955 1.0.25 password text in registration mail 2024-08-09 18:30:03 +03:00
17f21a25bb 1.0.26 translate 2024-08-09 18:29:41 +03:00
8c523e8c65 1.6.3 parsing timezones 2024-08-09 18:25:07 +03:00
d7956e24a6 1.6.2 parsing timezones 2024-08-09 18:23:52 +03:00
eaafbec1ea 1.6.1 parsing timezones 2024-08-09 18:23:29 +03:00
4ba5f6492f 1.6.0 parsing timezones 2024-08-09 18:21:12 +03:00
SDE
4355586afc Merge remote-tracking branch 'origin/dev' into dev 2024-08-09 14:33:52 +03:00
SDE
ed4dce4bf2 1.6.9 admin routes search by cities 2024-08-09 14:33:41 +03:00
a8c4d22b51 1.2.1 add Telegram icon 2024-08-08 08:52:08 +03:00
92f08b5174 1.1.60 add Meta Pixel Code 2024-08-06 21:22:24 +03:00
a7128908f4 1.1.59 upd the calendar initialization after receiving an error when submitting the form 2024-08-02 17:35:17 +03:00
d86a531495 1.1.58 add TikTok Pixel Code to registration.js 2024-08-02 15:55:28 +03:00
f894cec38b 1.1.57 add TikTok Pixel Code 2024-08-01 17:26:14 +03:00
0ef2f9aeb1 1.1.56 upd meta OG 2024-08-01 17:17:58 +03:00
312a706d00 1.1.55 fix function selectItemAddrPoint on main page 2024-08-01 17:06:05 +03:00
d1ad6cfa24 1.1.54 add readonly for departure/arrival input 2024-08-01 11:12:26 +03:00
2bc9aa7a1c 1.1.53 added a local time reference when editing route 2024-08-01 11:04:23 +03:00
3a497d09df 1.1.51 upd initialization for init_departure_DT() init_arrival_DT() 2024-08-01 10:44:18 +03:00
1301af9d84 1.1.51 upd the local time check of the selected city 2024-08-01 10:22:44 +03:00
SDE
822a029104 Merge remote-tracking branch 'origin/dev' into dev 2024-07-31 23:13:41 +03:00
SDE
257ae371f9 1.6.8 user admin add fields to list 2024-07-31 23:13:34 +03:00
ec1d52f694 1.1.50 add pagination for b_my_routes.html && upd conditional rendering for carrier card based on departure date 2024-07-31 16:13:28 +03:00
SDE
46c7b6327d Merge remote-tracking branch 'origin/dev' into dev 2024-07-31 12:02:22 +03:00
SDE
72d8ae6616 1.6.7 get_address_point_ajax add cur time for city 2024-07-31 12:02:13 +03:00
b905fab6c5 1.1.50 add pagination for b_my_routes.html && upd conditional rendering for carrier card based on departure date 2024-07-29 19:32:13 +03:00
3b10299249 1.1.49 add new gtag to MAIN branch 2024-07-29 14:43:19 +03:00
2098032d81 1.1.48 add new gtag to MAIN branch 2024-07-29 13:20:44 +03:00
d37b694d5a 1.1.47 add new gtag 2024-07-29 12:41:07 +03:00
345969fd61 1.1.46 upd poup url 2024-07-25 17:41:02 +03:00
632ff3c812 1.1.44 setTimeout for popup display 2024-07-25 17:19:45 +03:00
bb60f9d914 1.1.43 add popup display functionality with cookie-based visibility control 2024-07-25 16:55:35 +03:00
111a7eaff7 1.1.43 add popup display functionality with cookie-based visibility control 2024-07-25 16:55:13 +03:00
61161e6335 1.0.26 translate 2024-07-25 01:22:12 +03:00
327681d3db 1.0.26 translate 2024-07-25 01:17:57 +03:00
68c5bfe275 1.0.26 translate 2024-07-25 01:08:27 +03:00
10814e9e5f Merge remote-tracking branch 'origin/dev' into dev 2024-07-25 01:03:20 +03:00
617f90e1ac 1.0.26 translate 2024-07-25 01:03:05 +03:00
81af5990ae 1.1.42 Fix date formatting issue in template 2024-07-23 14:28:41 +03:00
92e9b1ce63 1.1.41 show/hide unanswered_msgs_count 2024-07-23 13:41:41 +03:00
87b21c5f55 1.1.40 show/hide unanswered_msgs_count 2024-07-18 12:53:04 +03:00
f61482ded6 1.1.39 show/hide unanswered_msgs_count 2024-07-18 12:05:54 +03:00
c999d994d6 1.1.38 show/hide unanswered_msgs_count 2024-07-18 11:42:29 +03:00
f609361ee9 1.1.37 show/hide unanswered_msgs_count 2024-07-17 15:24:42 +03:00
c3f116fbc3 1.1.36 show/hide unanswered_msgs_count 2024-07-17 13:58:21 +03:00
79059796c8 Merge remote-tracking branch 'origin/dev' into dev 2024-07-17 13:10:27 +03:00
61facdb5fb 1.1.35 refactor date comparison logic in Django template 2024-07-17 13:10:15 +03:00
SDE
b007c3ad23 1.6.6 parsing timezones 2024-07-16 15:53:12 +03:00
SDE
0b5e37281b 1.6.5 parsing timezones 2024-07-16 15:34:35 +03:00
SDE
6e5e82401b 1.6.4 parsing timezones 2024-07-16 15:19:40 +03:00
d419131eab 1.1.34 upd chat_counter 2024-07-16 15:10:43 +03:00
b8b3c19bfc 1.1.33 upd chat_socket 2024-07-16 09:47:58 +03:00
e95062c6eb Merge remote-tracking branch 'origin/main' 2024-07-16 09:34:37 +03:00
2f4c472a41 1.1.32 upd chat_socket 2024-07-16 09:34:13 +03:00
3f0f1d4408 1.0.25 password text in registration mail 2024-07-15 23:55:17 +03:00
f23ad1a33a 1.0.25 password text in registration mail 2024-07-15 23:40:42 +03:00
SDE
1486879a58 1.6.3 parsing timezones 2024-07-13 01:29:36 +03:00
SDE
3d6fb38937 1.6.2 parsing timezones 2024-07-12 21:07:07 +03:00
SDE
d981a83652 1.6.1 parsing timezones 2024-07-12 19:01:58 +03:00
SDE
3bfe64d57c Merge remote-tracking branch 'origin/dev' into dev 2024-07-12 18:54:24 +03:00
SDE
1ad58b05ef 1.6.0 parsing timezones 2024-07-12 18:54:14 +03:00
225a958cb4 1.0.24 robots 2024-07-10 17:58:30 +03:00
0ac8e906a2 1.0.24 robots 2024-07-10 17:56:29 +03:00
a42f3c7e71 1.0.24 robots 2024-07-10 17:38:02 +03:00
ddf8428884 Merge pull request 'dev в main' (#1) from dev into main
Reviewed-on: #1
2024-07-10 17:34:03 +03:00
807edecbf4 1.0.23 add tenge currency 2024-07-10 16:34:37 +03:00
6254b1dcda 1.0.23 add tenge currency 2024-07-10 16:21:35 +03:00
SDE
9df1bf2743 1.5.2 change currency pay 2024-07-10 16:20:48 +03:00
a678fb467d 1.0.22 robots.txt modify 2024-07-09 21:25:20 +03:00
SDE
c24b7107a7 Merge remote-tracking branch 'origin/main' 2024-07-09 16:59:23 +03:00
SDE
c0596871da 1.5.1 rosetta translate 2024-07-09 16:59:13 +03:00
f0ad2d654d 0.0.22 translate 2024-07-09 16:54:35 +03:00
SDE
c2ef76b69b 1.5.0 rosetta translate 2024-07-09 16:51:05 +03:00
SDE
96f58732ba 1.4.8 bank res log w full info 2024-07-09 16:19:55 +03:00
SDE
15340d254c 1.4.7 bank res log w full info 2024-07-09 16:17:00 +03:00
SDE
890986c5de 1.4.6 bank res log w full info 2024-07-09 16:12:33 +03:00
SDE
3d137aefad 1.4.5 move pay_system sets to settings 2024-07-09 16:09:01 +03:00
SDE
6c911dde43 1.4.4 move pay_system sets to settings 2024-07-09 16:07:16 +03:00
SDE
37981602dd 1.4.3 move pay_system sets to settings 2024-07-09 16:03:16 +03:00
SDE
d64d858f15 Merge remote-tracking branch 'origin/main' 2024-07-09 13:40:42 +03:00
SDE
f9906ea8fc 1.4.2 move pay_system url to settings 2024-07-09 13:40:32 +03:00
c660831146 1.1.31 upd chats markers 2024-07-04 14:42:27 +03:00
a8ba3f9a3a 1.1.30 upd chats markers 2024-07-04 13:49:42 +03:00
8439fc8736 1.1.29 upd tik tok url 2024-07-04 09:44:25 +03:00
04f7fbdbb2 1.1.29 upd msg counter 2024-07-03 21:54:40 +03:00
e2b205240e 1.1.28 upd msg counter and news 2024-07-03 18:24:35 +03:00
2695738ae3 1.1.27 hide .advertisement_block_news 2024-07-03 17:22:17 +03:00
5a3336a657 Merge remote-tracking branch 'origin/main' 2024-07-03 17:18:56 +03:00
b67b290279 1.1.26 upd msg counter and styles for news 2024-07-03 17:18:40 +03:00
f34664cbb3 0.0.19 add articles indexing 2024-07-02 20:48:03 +03:00
4919560500 0.0.19 add articles indexing 2024-07-02 19:07:47 +03:00
c2b6890311 1.1.24 upd msg counter 2024-07-02 15:30:34 +03:00
38c4f3426d 1.1.23 add h1 for all pages 2024-07-01 17:53:54 +03:00
2400c334a9 1.1.23 upd title and description 2024-07-01 16:52:08 +03:00
SDE
114675703b 1.4.1 sitemap 2024-06-29 16:46:37 +03:00
SDE
0be38ac466 1.4.0 sitemap 2024-06-29 16:34:36 +03:00
SDE
0e184f0b87 1.3.6 add unanswered_msgs_count to all responses 2024-06-29 14:44:19 +03:00
SDE
75258f1706 1.3.5 send_mail_for_user_subscribes_that_is_going_to_finish 2024-06-28 18:24:23 +03:00
SDE
ce591345d3 1.3.4 send_mail_for_user_subscribes_that_is_going_to_finish 2024-06-28 18:12:01 +03:00
SDE
0770009443 1.3.3 send_mail_for_user_subscribes_that_is_going_to_finish 2024-06-28 18:10:35 +03:00
SDE
bf39639acc 1.3.2 send_mail_for_user_subscribes_that_is_going_to_finish 2024-06-28 18:02:57 +03:00
SDE
947f46c5ff 1.3.1 receive_finish_subscribe_msg 2024-06-28 15:27:29 +03:00
651423ce90 1.1.22 fix function for checking the status of the switch finish_subscribe_msg 2024-06-28 15:24:58 +03:00
afb0ea0bed 1.1.21 add function for checking the status of the switch finish_subscribe_msg 2024-06-28 15:17:39 +03:00
SDE
e2b7b0d356 Merge remote-tracking branch 'origin/main' 2024-06-27 19:15:02 +03:00
SDE
c55d5c6676 1.3.0 receive_finish_subscribe_msg, find errors by tickets 2024-06-27 19:14:52 +03:00
eb60bcec56 1.1.20 upd css for .menu_profile right 2024-06-26 13:02:52 +03:00
62325eb9fa 1.1.19 upd css for block-chat 2024-06-26 12:32:53 +03:00
18aae945ae 1.1.18 fix height for container_inf_about_moving 2024-06-25 18:33:54 +03:00
4afe61546a 1.1.17 add YandexMetrika tag for create_routes, registration button in header/footer v2 2024-06-25 13:10:32 +03:00
b6a0fcdf07 1.1.17 add YandexMetrika tag for create_routes, registration button in header/footer v2 2024-06-21 15:41:19 +03:00
2fc153843f 1.1.16 add YandexMetrika tag for create_routes, registration button in header/footer 2024-06-21 14:54:30 +03:00
729f03ca47 1.1.15 add YandexMetrika tag for feedback form v4 2024-06-21 13:48:37 +03:00
96c0111428 1.1.14 add YandexMetrika tag for feedback form v3 2024-06-21 13:17:35 +03:00
d0ccbb494f 1.1.13 add YandexMetrika tag for feedback form v2 2024-06-20 17:10:20 +03:00
f8aa0162a5 1.1.12 add YandexMetrika tag for feedback form 2024-06-20 16:56:21 +03:00
2b94d3f851 1.1.12 add YandexMetrika tag for registration page 2024-06-20 16:00:23 +03:00
fddda1ef0a 1.1.11 fix height for cards in search 2024-06-20 14:28:42 +03:00
035634df67 0.0.18 add footer social networks 2024-06-18 11:57:13 +03:00
8267d99b4a 0.0.18 add footer social networks 2024-06-18 11:56:14 +03:00
854faf56f5 0.0.18 add footer social networks 2024-06-18 11:52:15 +03:00
4bbb3428c0 0.0.18 add footer social networks 2024-06-18 11:46:31 +03:00
7a40ca0986 0.0.18 add footer social networks 2024-06-18 11:44:49 +03:00
c93a15025b 0.0.18 add footer social networks 2024-06-18 11:43:38 +03:00
57a1c82db2 0.0.18 add social network icons 2024-06-18 11:39:40 +03:00
b6af2c7997 0.0.18 add social network icons 2024-06-18 11:37:35 +03:00
df7b3e1a8b 0.0.17 social network link added 2024-06-15 18:07:41 +03:00
b7a6163251 0.0.17 social network link added 2024-06-15 18:06:15 +03:00
9c39f9e07c 0.0.17 social network link added 2024-06-15 17:57:04 +03:00
d33eff4935 0.0.17 social network link added 2024-06-15 17:55:34 +03:00
11ea66f576 0.0.17 social network link added 2024-06-15 17:53:45 +03:00
d31f019afb 0.0.17 social network instagram link added 2024-06-15 17:42:55 +03:00
52361a6a16 0.0.17 social network instagram link added 2024-06-15 17:37:58 +03:00
e04ec83877 0.0.17 social network instagram link added 2024-06-15 17:35:46 +03:00
SDE
301f301868 1.2.7 reset rising_DT in past routes 2024-06-15 17:18:07 +03:00
SDE
b2cb5463ef Merge remote-tracking branch 'origin/main' 2024-06-15 17:15:05 +03:00
SDE
d2754db97a 1.2.6 reset rirsing_DT in past routes 2024-06-15 17:14:57 +03:00
568906b2df 0.0.16 twb-tripwb replace 2024-06-14 09:32:27 +03:00
fbae553657 1.1.10 fix webpush button footer 2024-06-12 23:33:24 +03:00
03ecd45316 1.1.9 fix webpush button footer 2024-06-12 22:45:36 +03:00
b8aba1d951 1.1.9 fix width for container-carrier 2024-06-12 15:38:28 +03:00
SDE
4d76569131 Merge remote-tracking branch 'origin/main' 2024-06-11 16:48:50 +03:00
SDE
f90d87a301 1.2.5 fix get_routes_Dict rising 2024-06-11 16:48:39 +03:00
fe6375b6f9 1.1.8 add registration message 2024-06-11 14:54:15 +03:00
SDE
a30156cc1c 1.2.5 add get_permission_for_highlight 2024-06-11 01:09:40 +03:00
SDE
f8a8aa7577 Merge remote-tracking branch 'origin/main' 2024-06-11 01:03:34 +03:00
SDE
b527d18a3c 1.2.4 add get_permission_for_highlight 2024-06-11 01:03:25 +03:00
fc6a864f7c 0.0.15 robots.txt add allow/disallow options 2024-06-10 23:37:54 +03:00
8eaff8ebbc 0.0.15 robots.txt add allow/disallow options 2024-06-10 23:35:37 +03:00
SDE
3a18688143 Merge remote-tracking branch 'origin/main' 2024-06-10 18:47:07 +03:00
SDE
0e40bae701 1.2.3 get_my_routes_ajax add remains_routes_count operations 2024-06-10 18:46:50 +03:00
7aa7e32fda 1.1.8 upd raise and highlight function in my_routes 2024-06-10 17:48:10 +03:00
SDE
1aced3d20b 1.2.2 get_my_routes_ajax add remains_routes_count operations 2024-06-10 16:58:59 +03:00
SDE
9566082283 Merge remote-tracking branch 'origin/main' 2024-06-10 16:56:43 +03:00
SDE
152c92bf65 1.2.1 get_my_routes_ajax add remains_routes_count operations 2024-06-10 16:56:19 +03:00
4622424b9b Merge remote-tracking branch 'origin/main' 2024-06-10 12:40:31 +03:00
ef8337582f 1.1.6 upd raise and highlight function in my_routes 2024-06-10 12:40:20 +03:00
SDE
133fa7ea5f Merge remote-tracking branch 'origin/main' 2024-06-09 16:37:20 +03:00
SDE
74e76fe6e7 1.2.0 confirm email after registration 2024-06-09 16:37:08 +03:00
2996e84433 1.1.5 fix show_contact if user is not authenticated 2024-06-06 14:25:25 +03:00
f8d1de5d30 1.1.4 update rising and highlight my_routes 2024-06-05 17:47:01 +03:00
d33278faff 1.1.3 update meta_names.html 2024-06-05 16:55:09 +03:00
22e40409d7 1.1.3 rising and highlight my_route counter 2024-06-05 16:48:12 +03:00
632cf0b9b4 1.1.3 change meta_names.html 2024-06-05 16:47:10 +03:00
a9ed3e0bef 0.0.14 add yandex and google verification meta 2024-06-05 15:06:46 +03:00
28b505310d 0.0.14 add yandex and google verification meta 2024-06-05 15:00:58 +03:00
c9aea0b778 1.1.3 rising and highlight my_route 2024-06-05 14:26:36 +03:00
e1694cdc9c 1.1.3 update dropdown-content lang 2024-06-05 14:22:19 +03:00
SDE
3a235b4f60 1.1.13 not send to pay system if subscribe price is null 2024-06-05 12:03:00 +03:00
SDE
90405f64de 1.1.12 funcs for raise and highlight routes 2024-06-04 22:28:43 +03:00
35073f77c8 1.1.3 rising and highlight my_route 2024-06-04 20:02:54 +03:00
5cd0146c8c 1.1.2 upd description for user_profile 2024-06-04 11:09:28 +03:00
SDE
ffabffb2ef 1.1.11 funcs for raise and highlight routes 2024-06-04 00:19:10 +03:00
bb1e3e9691 Merge remote-tracking branch 'origin/main' 2024-06-03 21:35:30 +03:00
d89730ffbf 1.1.1 highlighting and raising routes 2024-06-03 21:35:15 +03:00
431ab2f9b0 0.0.14 add yandex and google verification meta 2024-06-03 15:55:12 +03:00
c444055bd7 0.0.14 add yandex and google verification meta 2024-06-03 15:38:40 +03:00
a0dd229c12 0.0.14 add yandex and google verification meta 2024-06-03 15:25:11 +03:00
074e141a22 0.0.13 fix metrika 2024-06-03 15:04:39 +03:00
SDE
40951fdfcb 1.1.10 funcs for raise and highlight routes 2024-06-03 02:57:36 +03:00
SDE
e319a8af46 1.1.9 funcs for raise and highlight routes 2024-06-03 02:46:58 +03:00
SDE
a83ff0e080 1.1.8 change settings for ws 2024-06-03 02:01:26 +03:00
SDE
22ae4b1563 1.1.7 rising and select for routes by subscribe 2024-06-03 01:47:44 +03:00
SDE
23fe1c3647 1.1.6 rising and select for routes by subscribe 2024-06-03 01:45:04 +03:00
SDE
079a7d3925 1.1.5 rising and select for routes by subscribe 2024-06-02 17:10:56 +03:00
SDE
69373925cd 1.1.4 rising and select for routes by subscribe 2024-06-02 17:07:53 +03:00
SDE
dbfc39639b 1.1.3 autoextension and autofinish subscribes 2024-05-31 15:03:15 +03:00
11bbfd0e73 Merge remote-tracking branch 'origin/main' 2024-05-31 13:08:46 +03:00
0075b474d7 1.0.11 upd subscribe_current 2024-05-31 13:08:36 +03:00
SDE
99090a8a95 Merge remote-tracking branch 'origin/main' 2024-05-31 13:07:13 +03:00
SDE
0e5ed13794 1.1.2 fix dublicates subscribe_for_user 2024-05-31 13:07:00 +03:00
ffa6ba2c47 1.0.10 add description for news create_route_for_customer, create_route_for_mover 2024-05-31 12:43:46 +03:00
4ae8f09430 1.0.9 add title for news create_route_for_customer, create_route_for_mover 2024-05-31 11:40:16 +03:00
SDE
17024d7350 1.1.1 autosubscribe to null price subscribe 2024-05-29 12:25:27 +03:00
SDE
efec0754cd 1.1.0 autosubscribe to null price subscribe 2024-05-29 07:53:32 +03:00
5a893faa43 1.0.8 fix view bugs in my_routes, my_subscribe, main 2024-05-20 13:27:51 +03:00
5981f982f3 0.0.12 replace link to login page on carrier widget 2024-05-17 12:23:55 +03:00
fd81675ee9 1.0.7 upd view for error_message for subscribe 2024-05-10 18:48:51 +03:00
SDE
3575391d3f 1.0.12 subscribe buy routines 2024-05-10 15:34:56 +03:00
SDE
563a4fde3c 1.0.11 subscribe buy routines 2024-05-10 13:55:49 +03:00
SDE
148d182e5e 1.0.10 subscribe buy routines 2024-05-10 13:52:47 +03:00
SDE
aab8cf69fb 1.0.9 subscribe buy routines 2024-05-10 13:44:30 +03:00
3900cb1382 1.0.7 upd view for error_message for subscribe 2024-05-08 18:08:56 +03:00
d77fe01795 1.0.6 view for error_message for subscribe 2024-05-08 17:04:37 +03:00
47eb056f87 Merge remote-tracking branch 'origin/main' 2024-05-08 14:24:19 +03:00
14691d0ee4 1.0.5 add error_message for subscribe 2024-05-08 14:24:06 +03:00
SDE
d6487d81c9 1.0.7 push routines 2024-05-08 11:33:24 +03:00
SDE
2f421bb0ac 1.0.6 push routines 2024-05-08 11:23:01 +03:00
SDE
4b588eb6e4 1.0.5 subscribe page w dynamically load 2024-05-08 00:44:36 +03:00
SDE
3a911d928f 1.0.4 subscribe page w dynamically load 2024-05-07 18:51:17 +03:00
69c037b30d 1.0.4 upd select_tab_profile 2024-05-07 18:18:27 +03:00
SDE
c84e884a7c 1.0.3 subscribe page w dynamically load 2024-05-07 18:07:43 +03:00
0a38314003 1.0.3 upd select_tab_profile 2024-05-07 17:59:11 +03:00
2d86f36a91 1.0.2 upd select_tab_profile 2024-05-07 17:52:16 +03:00
a0eeb7b642 1.0.1 upd select_tab_profile 2024-05-07 17:40:07 +03:00
SDE
9eb5936690 1.0.2 subscribe page w dynamically load 2024-05-07 16:23:40 +03:00
SDE
cbe5271426 1.0.1 subscribe page w dynamically load 2024-05-07 15:28:47 +03:00
SDE
34827af5be 1.0.0 subscribe page w dynamically load 2024-05-07 15:23:45 +03:00
6ed5652f16 1.0.0 upd view for my_routes 2024-05-07 15:21:40 +03:00
SDE
8ed567496b 0.12.52 subscribe page w dynamically load 2024-05-07 15:01:13 +03:00
SDE
b374e7aeca 0.12.51 subscribe page w dynamically load 2024-05-07 14:21:52 +03:00
SDE
a0ee72bc81 0.12.50 subscribe page w dynamically load 2024-05-07 13:51:20 +03:00
SDE
e8e4bf466b 0.12.49 fix push messages 2024-05-07 11:43:58 +03:00
SDE
ec01d11426 0.12.48 fix push messages 2024-05-07 11:39:36 +03:00
SBD
c088d25033 14 2024-05-05 14:57:28 +03:00
SBD
e9f3cdbc59 14 2024-05-05 14:05:09 +03:00
SBD
72f754e89c 14 2024-05-05 13:45:45 +03:00
SDE
c365f3274a Merge remote-tracking branch 'origin/main' 2024-05-05 13:37:56 +03:00
SDE
f8caafb2a9 0.12.47 fix push messages 2024-05-05 13:37:39 +03:00
2d147d5f09 0.0.11 insert yandex and google counter 2024-04-27 11:26:50 +03:00
7c4b554aea 0.0.11 insert yandex and google counter 2024-04-27 11:23:09 +03:00
0091919b93 0.0.11 insert yandex and google counter 2024-04-27 11:21:17 +03:00
d46e5cc238 0.0.10 style bold for text in tarif plans 2024-04-25 17:22:14 +03:00
97116a2070 Merge remote-tracking branch 'origin/main' 2024-04-25 11:36:46 +03:00
27aaff4a4b 0.1.379 update carrier_card info in search 2024-04-25 11:36:36 +03:00
32c2fd4e6c 0.0.10 style bold for text in tarif plans 2024-04-25 11:09:50 +03:00
51b86323d8 0.0.10 style bold for text in tarif plans 2024-04-25 11:04:53 +03:00
f0bd3ce088 0.0.10 style bold for text in tarif plans 2024-04-25 10:57:24 +03:00
SDE
474bb9f02e Merge remote-tracking branch 'origin/main' 2024-04-24 14:11:40 +03:00
SDE
a2175f9110 0.12.46 fix validation dates for route in localization 2024-04-24 14:11:25 +03:00
aec0218787 0.1.378 update carrier_card info in search 2024-04-24 12:25:35 +03:00
567ee01619 0.1.377 hide img in carrier_card info in search 2024-04-23 20:57:35 +03:00
SDE
e4a929cfd6 0.12.45 favicon 2024-04-23 13:29:21 +03:00
SDE
27b0840704 0.12.44 favicon 2024-04-23 13:17:12 +03:00
SDE
525da42ae9 0.12.43 favicon 2024-04-23 12:55:14 +03:00
SDE
8d1199bc4f 0.12.42 favicon 2024-04-23 12:49:49 +03:00
SDE
dac8f602d8 0.12.41 favicon 2024-04-23 12:42:00 +03:00
SDE
26d04dfaa0 0.12.40 favicon 2024-04-23 12:36:49 +03:00
SDE
22306371a0 0.12.39 favicon 2024-04-23 12:33:15 +03:00
SDE
881f0cdbfa 0.12.39 favicon 2024-04-23 12:30:28 +03:00
SDE
314d342f5c Merge remote-tracking branch 'origin/main' 2024-04-23 10:18:00 +03:00
SDE
d627b6a780 0.12.38 fix static pages w subscribes 2024-04-23 10:17:49 +03:00
9528572f37 0.1.376 update carrier_card info in search 2024-04-22 13:59:55 +03:00
273caa5c5d 0.1.375 update carrier_card info in search 2024-04-22 12:40:00 +03:00
c9f04057a7 0.1.374 update carrier_card info in search 2024-04-22 11:10:10 +03:00
SBD
8599030ccb 14 2024-04-20 12:30:55 +03:00
SDE
3fe5970811 0.12.37 pays and subscribes 2024-04-20 12:26:12 +03:00
SDE
723229d595 0.12.36 pays and subscribes 2024-04-20 12:24:37 +03:00
SDE
bb319780b6 0.12.36 pays and subscribes 2024-04-20 12:15:55 +03:00
5c06aceb27 0.1.373 fix carrier_card in my_routes 2024-04-19 12:44:07 +03:00
27b4dd072e 0.1.372 fix maegin for curtain and for inf_carrier 2024-04-19 12:27:22 +03:00
SDE
2c1f70018e 0.12.36 fix webpush 2024-04-16 17:07:32 +03:00
SDE
698f4578fc 0.12.35 fix webpush 2024-04-15 17:19:12 +03:00
SDE
fd70e388a7 0.12.34 fix redirect to subscribe after login 2024-04-13 11:23:44 +03:00
SDE
07b06a4177 0.12.33 fix redirect to subscribe after login 2024-04-12 18:40:06 +03:00
SBD
10e8d477e5 14 2024-04-12 17:29:35 +03:00
7daadc816c 0.1.371 hide name_carrier if user not registered 2024-04-12 16:21:11 +03:00
89db74c782 0.1.370 upd compare with current_date 2024-04-12 15:52:10 +03:00
01f6136798 0.1.369 compare with current_date 2024-04-12 15:43:09 +03:00
SDE
1bb4aa04a6 0.12.33 m_found_matched_routes change 2024-04-12 14:39:45 +03:00
6b63f8b87e 0.0.9 style search field fix 2024-04-11 09:49:56 +03:00
cd6fde962b 0.0.8 promotion block bottom_block_static commented 2024-04-09 09:49:27 +03:00
SDE
607a0f8245 0.12.32 fix switch langs 2024-04-08 18:08:05 +03:00
SBD
ad1db581a7 14 2024-04-08 17:32:14 +03:00
SBD
ca5b0039a1 14 2024-04-08 17:24:19 +03:00
214ee3bd58 0.0.7 text fix 2024-04-08 10:53:27 +03:00
b1f2cc2376 0.0.7 text fix 2024-04-08 10:48:45 +03:00
f1f523209b 0.0.7 text fix 2024-04-08 10:41:43 +03:00
9c23fd02fe 0.0.7 text fix 2024-04-08 10:39:31 +03:00
eee30b50db 0.0.7 text fix 2024-04-08 10:35:41 +03:00
6ba35ccd96 0.0.7 text fix 2024-04-08 10:22:59 +03:00
5916d5d038 0.0.7 text fix 2024-04-08 10:04:40 +03:00
3eb0b499c6 0.0.6 header menu item translate 2024-04-04 23:56:52 +03:00
SDE
c2d021a516 0.12.31 fix switch langs 2024-04-04 23:16:26 +03:00
SDE
46fdda269f 0.12.30 fix login_required 2024-04-04 22:45:20 +03:00
SDE
536a1e967e 0.12.29 fix trans 2024-04-04 15:21:36 +03:00
SDE
ac4fcb634d Merge remote-tracking branch 'origin/main' 2024-04-04 11:26:57 +03:00
SDE
d92fe4c22c 0.12.28 fix trans 2024-04-04 11:26:50 +03:00
3d49100656 0.0.5 fix footer logo 2024-04-04 09:50:51 +03:00
9841524ec0 0.0.5 fix footer logo 2024-04-04 09:44:24 +03:00
0fe8cb1bfb 0.0.5 fix unsubscribe text decoration 2024-04-03 13:17:55 +03:00
910b211840 0.1.368 centered the logo in the footer 2024-04-03 11:33:47 +03:00
4f7d6d05bd Merge remote-tracking branch 'origin/main' 2024-04-03 11:29:15 +03:00
b8feec88a7 0.1.367 add text in subscribe block 2024-04-03 11:29:04 +03:00
6043e1f5a7 0.0.4 fix text for contact page 2024-04-03 10:38:14 +03:00
SDE
4981bdcaa6 Merge remote-tracking branch 'origin/main' 2024-04-02 16:06:56 +03:00
SDE
c29cc25581 0.12.28 localization routines 2024-04-02 16:06:45 +03:00
0ce03ca73f Merge remote-tracking branch 'origin/main' 2024-04-02 14:14:45 +03:00
80a226a302 0.1.366 add text in subscribe block 2024-04-02 14:14:29 +03:00
0d41bd40e5 0.0.4 fix text for about page 2024-04-02 13:48:11 +03:00
d2fe96a599 0.0.4 center footer logo 2024-04-02 13:06:42 +03:00
d0d41a4d2b 0.0.3 replace footer logo max-width desktop 2024-04-02 10:44:46 +03:00
5e7a153d6d 0.0.3 replace footer logo max-width desktop 2024-04-02 10:40:04 +03:00
55d414c1d0 0.0.3 replace footer logo max-width desktop 2024-04-02 10:37:45 +03:00
ac6a440151 0.0.3 replace footer logo max-width desktop 2024-04-02 10:32:58 +03:00
ff48ca83e2 0.0.2 replace footer logo max-width 2024-04-02 10:27:09 +03:00
358577745f 0.0.2 replace Logo in footer 2024-04-02 10:14:45 +03:00
087a913a48 0.0.2 replace word in contact form about service 2024-04-02 09:42:13 +03:00
a9dedb7869 0.0.1 replace twb to tripwithbonus on main page 2024-04-02 09:31:58 +03:00
SDE
92e3d76b7e 0.12.27 fix auth 2024-03-27 12:59:38 +03:00
2da7195dd0 0.1.365 add img 2024-03-15 15:38:42 +03:00
18f7fedbc2 0.1.365 add img 2024-03-15 15:37:10 +03:00
aa93813ba5 0.1.364 add new logo fix old css 2024-03-15 15:35:58 +03:00
def3d770ed 0.1.363 add new logo 2024-03-08 16:07:51 +03:00
6b8bcb8ebb 0.1.363 fix misspell 2024-03-07 19:47:50 +03:00
SBD
ff5afe518a 14 2024-03-06 18:22:48 +03:00
SBD
6f42251f5f Merge remote-tracking branch 'origin/main' 2024-03-06 18:11:58 +03:00
SBD
06917078ae 14 2024-03-06 18:11:46 +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
369 changed files with 40925 additions and 2916 deletions

4
.gitignore vendored
View File

@@ -415,3 +415,7 @@ fabric.properties
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
# packages for node
package.json
package-lock.json

View File

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

@@ -21,6 +21,9 @@ def get_articles_block_ajax(request):
if request.method != 'POST':
raise Http404
from GeneralApp.funcs import get_and_set_lang
lang = get_and_set_lang(request)
try:
data = request.POST.dict()
@@ -42,6 +45,9 @@ def get_articles_block_ajax(request):
# 'form': RouteForm(initial=data)
}
from GeneralApp.funcs import get_add_to_ajax_response_Dict
res_Dict.update(get_add_to_ajax_response_Dict(request.user))
return JsonResponse(res_Dict)
except Exception as e:

View File

@@ -19,7 +19,7 @@ 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=_("Пользовательская страница")

View File

@@ -6,7 +6,7 @@ from datetime import datetime, date
from django.http import Http404, HttpResponse
from django.template import loader
from .funcs import *
from GeneralApp.funcs import get_inter_http_respose
from GeneralApp.funcs import get_inter_http_response
from django.utils.translation import gettext_lazy as _
# from django.contrib.auth.decorators import login_required
@@ -18,7 +18,7 @@ from django.utils.translation import gettext_lazy as _
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)
@@ -28,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
@@ -82,14 +85,14 @@ def ArticlesPageView(request, year=None):
Dict = get_articles(art_kwargs=kwargs)
Dict.update({
'page': {
'title': _('Страница списка новостей'),
'description': _('Все новости сайта tripwb.com'),
'title': _('Новости сервиса доставки посылок | TripWB'),
'description': _('Обновления, полезные статьи и свежие новости от TripWB ✓ Актуальные новости в мире доставок по всему СНГ ➡️ Следите за нашими новостями'),
'keywords': _('Все новости сайта tripwb.com'),
}
})
t = loader.get_template('pages/p_articles.html')
return get_inter_http_respose(t, Dict, request)
return get_inter_http_response(t, Dict, request)
# return HttpResponse(t.render(Dict, request))
@@ -122,7 +125,7 @@ def UserPageView(request, page_url):
t = loader.get_template('pages/p_user_page.html')
return get_inter_http_respose(t, Dict, request)
return get_inter_http_response(t, Dict, request)
# return HttpResponse(t.render(Dict, request))
@@ -152,5 +155,5 @@ def ArticlesOnePageView(request, art_url):
t = loader.get_template('pages/p_article.html')
return get_inter_http_respose(t, Dict, request)
return get_inter_http_response(t, Dict, request)
# return HttpResponse(t.render(Dict, request))

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,65 @@ class Admin_User(UserAdmin):
save_on_top = True
list_display = ['id', 'last_name', 'first_name', 'email', 'is_staff',
'is_active']
list_display = ['id', 'last_name', 'first_name', 'mailing_on', 'email', 'is_staff',
'is_active', 'date_joined', 'last_login']
list_editable = ['is_staff', 'is_active']
list_display_links = ['first_name', 'last_name', 'email']
search_fields = ['first_name', 'last_name', 'email']
readonly_fields = ['date_joined', 'last_login']
list_filter = ['user_profile__mailing_on', 'is_staff', 'is_active', 'date_joined', 'last_login']
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

@@ -26,25 +26,64 @@ class RegistrationForm(forms.Form):
email = forms.EmailField()
password = forms.CharField(widget=forms.PasswordInput())
confirm_password = forms.CharField(widget=forms.PasswordInput())
tel = forms.CharField()
tel = forms.CharField(required=False)
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,27 @@
from django.http import QueryDict
from django.template.loader import render_to_string
from SubscribesApp.funcs import check_option_in_cur_user_subscribe
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)
@@ -13,20 +32,23 @@ def get_profile_page_content_html(request, page_name, data):
if page_name == 'chat':
from ChatServiceApp.funcs import get_chat_page_content_html
return get_chat_page_content_html(request, data)
elif page_name == 'create_route_for_customer':
elif (page_name == 'create_route_for_customer' and
check_option_in_cur_user_subscribe(request.user, 'размещение заявок')):
from RoutesApp.funcs import get_profile_new_route_page_html
return get_profile_new_route_page_html(request, {})
elif page_name == 'create_route_for_mover':
return get_profile_new_route_page_html(request, {'owner_type': 'customer'})
elif (page_name == 'create_route_for_mover' and
check_option_in_cur_user_subscribe(request.user, 'размещение заявок')):
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)
elif page_name == 'support':
return get_profile_support_page_content_html(request, data)
elif page_name == 'my_subscribe':
from SubscribesApp.funcs import get_profile_subscribe_page_content_html
return get_profile_subscribe_page_content_html(request)
from SubscribesApp.funcs import get_profile_subscribe_page_content_Dict
res = get_profile_subscribe_page_content_Dict(request, check_orders_required=True)
return res['html']
elif page_name == 'change_profile':
return get_profile_change_page_content_html(request)
elif page_name == 'dashboard':
@@ -35,7 +57,7 @@ def get_profile_page_content_html(request, page_name, data):
return None
def get_profile_change_page_content_html(request):
def get_profile_change_page_content_html(request, data=None):
init_Dict = {
'firstname': request.user.first_name,
@@ -45,6 +67,25 @@ def get_profile_change_page_content_html(request):
'country': request.user.user_profile.country,
'city': request.user.user_profile.city,
}
if data:
if type(data) == QueryDict:
data = data.dict()
init_Dict.update(data)
# if 'firstname' in data:
# init_Dict.update({'first_name': data['firstname']})
# if 'lastname' in data:
# init_Dict.update({'last_name': data['lastname']})
# if 'email' in data:
# init_Dict.update({'email': data['email']})
# init_Dict.update({'username': data['email']})
# if 'country' in data:
# init_Dict.update({'country': data['country']})
# if 'city' in data:
# init_Dict.update({'city': data['city']})
# if 'tel' in data:
# init_Dict.update({'tel': data['tel']})
from .forms import RegistrationForm
form = RegistrationForm(initial=init_Dict)
@@ -73,5 +114,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

@@ -23,8 +23,15 @@ urlpatterns = [
path('support_tickets/', support_tickets_ajax, name='support_tickets_ajax'),
path('password_recovery/', password_recovery_ajax, name='password_recovery_ajax'),
path('password_recovery_confirm/', password_recovery_confirm_ajax, name='password_recovery_confirm_ajax'),
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,9 +16,11 @@ 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
from GeneralApp.funcs import get_and_set_lang
# @login_required(login_url='/profile/login/')
# @login_required()#login_url='/profile/login/')
# def subscribe_ajax(request):
# if request.method != 'POST':
# raise Http404
@@ -29,11 +31,332 @@ import base64
# html = render_to_string('blocks/profile/b_subscribe.html', Dict, request=request)
# return JsonResponse({'html': html}, status=200)
@login_required(login_url='/profile/login/')
def password_recovery_confirm_ajax(request):
if request.method != 'POST':
raise Http404
if not 'pass' in request.POST or not 'pass_confirm' in request.POST or not 'user_id' in request.POST:
raise Http404
lang = get_and_set_lang(request)
try:
if not request.POST['pass'] or request.POST['pass'] != request.POST['pass_confirm']:
return JsonResponse({
'status': 'error',
'error': _('Пароли не совпадают')
}, status=400)
user = User.objects.get(id=request.POST['user_id'])
user.set_password(request.POST['pass'])
user.user_profile.authMailCode = None
user.user_profile.save(update_fields=['authMailCode'])
user.is_active = True
user.save()
return JsonResponse({
'status': 'success',
'message': _('Пароль был успешно изменен')
})
except Exception as e:
return JsonResponse({
'status': 'error',
'error': str(e)
}, status=400)
def password_recovery_ajax(request):
if request.method != 'POST':
raise Http404
lang = get_and_set_lang(request)
try:
email = request.POST['email']
try:
user = User.objects.get(email=email)
except User.DoesNotExist:
msg = _('Пользователь с указанным email не зарегистрирован на сайте')
return JsonResponse({
'status': 'error',
'error': msg
}, status=400)
user.user_profile.authMailCode = uuid1().hex
user.user_profile.save(update_fields=['authMailCode'])
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 = _('Изменение пароля учетной записи на сайте tripwb.com')
mail_txt = _('Вы получили это письмо потому что '
'был произведен запрос на изменение пароля '
'для данного email на сайте tripwb.com.<br>'
'<br>'
'Если Вы не выполняли запрос - просто проигнорируйте это письмо.<br><br>'
'Если же это были Вы и Вам требуется изменить пароль от учетной записи - '
'перейдите по ссылке, указанной ниже.<br><br>')
link = sets["domain"] + f'/profile/reset_password/{str(user.id)}/{user.user_profile.authMailCode}/'
link_str = f'<a href="{link}">ИЗМЕНИТЬ ПАРОЛЬ</a><br><br>'
sign_txt = _('Спасибо за то, что вы с нами!<br>'
'С уважением,<br>'
'Команда Trip With Bonus.<br>')
Dict = {
'logo': f'{sets["domain"]}/static/img/svg/LogoMobile.svg',
'project_name': sets['project_name'],
'message_title': subject,
'message_text': f'<p style="padding-left: 20px; line-height: 30px;">'
f'{mail_txt}'
f'{link_str}'
f'{sign_txt}'
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 = [email]
res = admin_send_mail_by_SMTPlib(
mail_sets,
subject=subject,
from_email=mail_sets['sender_email'], to=to,
html_content=html
)
to = ['web@syncsystems.net']
res = admin_send_mail_by_SMTPlib(
mail_sets,
subject=subject,
from_email=mail_sets['sender_email'], to=to,
html_content=html
)
return JsonResponse({
'status': 'sended',
'message': _('На email') + ' ' + email + ' '
+ _('отправлено письмо с инструкциями для восстановления пароля. Если не пришло письмо, проверьте папку СПАМ')
})
except Exception as e:
return JsonResponse({
'status': 'error',
'error': str(e)
}, status=400)
def mailing_subscribe_ajax(request):
if request.method != 'POST':
raise Http404
lang = get_and_set_lang(request)
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'])
from GeneralApp.funcs import get_add_to_ajax_response_Dict
res_Dict = {
'status': 'sended',
'del_form': True,
'html': _('Подписка на рассылку для адреса ') + user.email + _(' одобрена')
}
res_Dict.update(get_add_to_ajax_response_Dict(request.user))
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"
from GeneralApp.funcs import get_add_to_ajax_response_Dict
res_Dict = {
'status': 'sended',
'redirect_url': redirect_url,
'email': email
}
res_Dict.update(get_add_to_ajax_response_Dict(request.user))
return JsonResponse(res_Dict)
except Exception as e:
return JsonResponse({
'status': 'error',
'html': str(e)
}, status=400)
def send_message_ajax(request):
if request.method != 'POST':
raise Http404
lang = get_and_set_lang(request)
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()
opts = get_options_by_opt_types('support_email', only_vals=True)
if opts and 'support_email' in opts:
to = [opts['support_email']]
else:
to = [mail_sets['sender_email']]
res = admin_send_mail_by_SMTPlib(
mail_sets,
subject=subject,
from_email=mail_sets['sender_email'], to=to,
html_content=html
)
to = ['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)
from GeneralApp.funcs import get_add_to_ajax_response_Dict
res_Dict = {
'status': 'sended',
'html': html
}
res_Dict.update(get_add_to_ajax_response_Dict(request.user))
return JsonResponse(res_Dict)
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':
raise Http404
lang = get_and_set_lang(request)
from ChatServiceApp.funcs import get_chat_receivers_for_user, get_msgs_for_chat_w_users
receivers, unread_msgs_count = get_chat_receivers_for_user(request.user)
@@ -54,27 +377,40 @@ 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)
@login_required(login_url='/profile/login/')
from GeneralApp.funcs import get_add_to_ajax_response_Dict
res_Dict = {'html': html}
res_Dict.update(get_add_to_ajax_response_Dict(request.user))
return JsonResponse(res_Dict)
@login_required()#login_url='/profile/login/')
def support_tickets_ajax(request):
if request.method != 'POST':
raise Http404
lang = get_and_set_lang(request)
html = get_profile_support_page_content_html(request)
return JsonResponse({'html': html}, status=200)
from GeneralApp.funcs import get_add_to_ajax_response_Dict
res_Dict = {'html': html}
res_Dict.update(get_add_to_ajax_response_Dict(request.user))
return JsonResponse(res_Dict)
@login_required(login_url='/profile/login/')
@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
lang = get_and_set_lang(request)
try:
file_data = json.loads(request.body)
@@ -83,26 +419,47 @@ 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})
res_Dict = {'url': request.user.user_profile.avatar.url}
from GeneralApp.funcs import get_add_to_ajax_response_Dict
res_Dict.update(get_add_to_ajax_response_Dict(request.user))
return JsonResponse(res_Dict)
@login_required(login_url='/profile/login/')
@login_required()#login_url='/profile/login/')
def change_profile_confirm_ajax(request):
if request.method != 'POST':
raise Http404
lang = get_and_set_lang(request)
data = request.POST
if not data:
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)
@@ -149,15 +506,20 @@ def change_profile_confirm_ajax(request):
if data_for_save:
user_profiles.update(**data_for_save)
html = get_profile_change_page_content_html(request)
return JsonResponse({'html': html}, status=200)
html = get_profile_change_page_content_html(request, data)
from GeneralApp.funcs import get_add_to_ajax_response_Dict
res_Dict = {'html': html}
res_Dict.update(get_add_to_ajax_response_Dict(request.user))
return JsonResponse(res_Dict)
@login_required(login_url='/profile/login/')
@login_required()#login_url='/profile/login/')
def dashboard_ajax(request):
if request.method != 'POST':
raise Http404
lang = get_and_set_lang(request)
try:
from .funcs import get_dashboard_page_content_html
@@ -171,26 +533,32 @@ def dashboard_ajax(request):
return JsonResponse({'html': html}, status=200)
@login_required(login_url='/profile/login/')
@login_required()#login_url='/profile/login/')
def change_profile_ajax(request):
if request.method != 'POST':
raise Http404
lang = get_and_set_lang(request)
html = get_profile_change_page_content_html(request)
return JsonResponse({'html': html}, status=200)
@login_required(login_url='/profile/login/')
@login_required()#login_url='/profile/login/')
def my_routes_ajax(request):
if request.method != 'POST':
raise Http404
lang = get_and_set_lang(request)
Dict = {
}
html = render_to_string('blocks/profile/b_my_routes.html', Dict, request=request)
return JsonResponse({'html': html}, status=200)
res_Dict = {'html': html}
from GeneralApp.funcs import get_add_to_ajax_response_Dict
res_Dict.update(get_add_to_ajax_response_Dict(request.user))
return JsonResponse(res_Dict)
@@ -200,6 +568,8 @@ def login_ajax(request):
if request.method != 'POST':
raise Http404
lang = get_and_set_lang(request)
try:
data = request.POST
@@ -215,6 +585,9 @@ 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': {
@@ -225,11 +598,16 @@ def login_ajax(request):
html = render_to_string('forms/f_login.html', Dict, request=request)
return JsonResponse({'html': html}, status=400)
if not 'HTTP_REFERER' in request.META or not '/?next=/' in request.META['HTTP_REFERER']:
redirect_url = reverse('profile_page', args=['dashboard'])
else:
redirect_url = request.META['HTTP_REFERER'].split('/?next=')[1]
res_Dict = {
'redirect_url': reverse('profile_page', args=['dashboard'])
'redirect_url': redirect_url
}
from GeneralApp.funcs import get_add_to_ajax_response_Dict
res_Dict.update(get_add_to_ajax_response_Dict(request.user))
return JsonResponse(res_Dict)
except Exception as e:
@@ -244,10 +622,60 @@ def login_ajax(request):
return JsonResponse({'html': html}, status=400)
def send_check_email_after_registration(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'],
'domain': sets['domain'],
'message_title': subject,
}
Dict.update(data_Dict)
html = render_to_string('mail/m_confirm_email.html', Dict)
from BaseModels.mailSender import admin_send_mail_by_SMTPlib
mail_sets = get_mail_send_options()
to = [user.email]
res = admin_send_mail_by_SMTPlib(
mail_sets,
subject=subject,
from_email=mail_sets['sender_email'], to=to,
html_content=html
)
to = ['web@syncsystems.net', 'sa@a3-global.com', 'sysadmin.hax@gmail.com']
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
from GeneralApp.funcs import get_and_set_lang
lang = get_and_set_lang(request)
try:
data = request.POST
@@ -259,28 +687,43 @@ 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)
# if 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']
user.is_active = False
user.save()
user.user_profile.phone = form.data['tel']
user.user_profile.authMailCode = uuid1().hex
user.user_profile.save()
res_Dict = {
'redirect_url': reverse('profile_page', args=['dashboard'])
mail_Dict = {
'user': user,
}
res = send_check_email_after_registration(mail_Dict, user)
print(str(res))
# res = send_registration_mail(mail_Dict, user)
res_Dict = {
# 'redirect_url': reverse('profile_page', args=['dashboard'])
}
from GeneralApp.funcs import get_add_to_ajax_response_Dict
res_Dict.update(get_add_to_ajax_response_Dict(request.user))
return JsonResponse(res_Dict)
except Exception as e:

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

@@ -16,7 +16,6 @@ from datetime import datetime
def user_name_str(self):
return f'{self.last_name} {self.first_name}'
User.add_to_class("__str__", user_name_str)
@@ -51,6 +50,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 +81,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 +107,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

@@ -8,6 +8,9 @@ from django.contrib.auth import views
urlpatterns = [
path('registration/', registration_View, name='registration_page'),
path('reset_password/<int:user_id>/<str:token>/',
recovery_password_page_View, name='recovery_password_page'),
# path('', user_profile_View, name='user_profile'),
# path('page/chat/<int:user_id>/', chat_w_user_View, name='chat_w_user'),
# path('page/chat/', chat_w_user_View, name='chat_w_user_wo_user_id'),
@@ -21,6 +24,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'),
@@ -44,9 +49,9 @@ urlpatterns = [
#
# # -----------------------
#
# url(r'^check_user_registration_and_activate/(?P<user_id>[\d+]*)/(?P<authCode>[0-9a-z\+\-\_]+)$',
# check_user_registration_and_activate,
# name='check_user_registration_and_activate'),
path('check_user_registration_and_activate/<int:user_id>/<str:authMailCode>/',
check_user_registration_and_activate,
name='check_user_registration_and_activate'),
#
# # url(r'^user/password/reset/$',
# # 'django.contrib.auth.views.password_reset',

View File

@@ -5,7 +5,8 @@ from django.shortcuts import render
from uuid import uuid1
from AuthApp.models import *
from django.contrib import auth
from django.http import HttpResponse, Http404
from django.urls import reverse
from django.http import HttpResponse, Http404, HttpResponseRedirect
from django.template import loader, RequestContext
from django.contrib.auth.decorators import login_required
from BaseModels.mailSender import techSendMail
@@ -13,14 +14,80 @@ from django.utils.translation import gettext as _
from datetime import datetime
from django.contrib.auth.decorators import login_required
from .funcs import *
from GeneralApp.funcs import get_inter_http_respose
from GeneralApp.funcs import get_inter_http_response
from GeneralApp.funcs import get_and_set_lang
def send_registration_mail(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,
'user': user
}
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]
res = admin_send_mail_by_SMTPlib(
mail_sets,
subject=subject,
from_email=mail_sets['sender_email'], to=to,
html_content=html
)
to = ['web@syncsystems.net', 'sa@a3-global.com', 'sysadmin.hax@gmail.com']
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 check_user_registration_and_activate(request, user_id, authMailCode):
try:
user = User.objects.get(
id=user_id,
is_active=False,
user_profile__authMailCode=authMailCode
)
user.is_active = True
user.save(update_fields=['is_active'])
res = send_registration_mail(user)
return HttpResponseRedirect(reverse('login_profile'))
except User.DoesNotExist:
user = None
raise Http404
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 get_inter_http_response(t, Dict, request)
# return HttpResponse(t.render(Dict, request))
@@ -36,35 +103,47 @@ def registration_View(request):
# return HttpResponse(t.render(Dict, request))
@login_required(login_url='/profile/login/')
@login_required()#login_url='/profile/login/')
def profile_page_View(request, page_name, id=None):
lang = get_and_set_lang(request)
page_html = get_profile_page_content_html(request, page_name, id)
if not page_html:
raise Http404
Dict = {
'page_html': get_profile_page_content_html(request, page_name, id),
'page_html': page_html,
'page_name': page_name,
'page_type': 'profile'
}
title = f"{_('Личный кабинет пользователя')} {request.user.first_name} {request.user.last_name}"
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']
Dict.update({
'page': {
'title': title,
'description': title,
'keywords': title,
}
})
# title = _('Личный кабинет пользователя') + ' ' + 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
})
# 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 get_inter_http_response(t, Dict, request)
# return HttpResponse(t.render(Dict, request))
# @login_required(login_url='/profile/login/')
# @login_required()#login_url='/profile/login/')
# def chat_w_user_View(request, user_id=None):
# from ChatServiceApp.funcs import get_chat_page_content_Dict
#
@@ -93,7 +172,7 @@ def profile_page_View(request, page_name, id=None):
# t = loader.get_template('pages/profile/p_user_profile.html')
# return HttpResponse(t.render(Dict, request))
@login_required(login_url='/profile/login/')
@login_required()#login_url='/profile/login/')
def user_profile_View(request):
Dict = {}
@@ -102,7 +181,7 @@ def user_profile_View(request):
# request.COOKIES['user_id'] = request.user.id
t = loader.get_template('pages/profile/p_user_profile.html')
response = get_inter_http_respose(t, Dict, request)
response = get_inter_http_response(t, Dict, request)
# response = HttpResponse(t.render(Dict, request))
response.set_cookie('user_id', request.user.id)
return response
@@ -117,10 +196,17 @@ 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)
return get_inter_http_response(t, Dict, request)
# return HttpResponse(t.render(Dict, request))
@@ -192,12 +278,19 @@ def decode_get_param(data):
def recovery_password_user(request, uidb64=None, token=None):
from django.contrib.auth.views import PasswordResetConfirmView
def recovery_password_page_View(request, user_id, token):
try:
user = User.objects.get(id=user_id, user_profile__authMailCode=token)
except User.DoesNotExist:
raise Http404
return PasswordResetConfirmView(request=request, uidb64=uidb64, token=token
)
Dict = {
'user': user
}
t = loader.get_template('pages/profile/p_password_recovery.html')
response = get_inter_http_response(t, Dict, request)
return response
@@ -205,7 +298,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

@@ -37,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',
@@ -64,7 +64,7 @@ def get_base_fieldsets():
)
}),
(u'Партнерские ссылки', {
(_('Партнерские ссылки'), {
'classes': ['wide', 'collapse'],
'fields': (
'link_left_promo_show',

View File

@@ -18,7 +18,7 @@ from django.contrib.contenttypes.fields import GenericRelation
# add_introspection_rules([], ["^tinymce\.models\.HTMLField"])
class BaseModel(models.Model):
name = models.TextField(verbose_name=_('Название'),
name = models.TextField(verbose_name=_("Название"),
help_text=_('Название'), null=True, blank=True)
name_plural = models.TextField(verbose_name=_('Название (множественное число)'),
null=True, blank=True)
@@ -29,12 +29,31 @@ class BaseModel(models.Model):
json_data = models.JSONField(verbose_name=_('Дополнительные данные'), default=dict, blank=True)
media_items = GenericRelation('GeneralApp.MediaItem', related_query_name='grel_%(class)s_for_media_item')
def __str__(self):
if self.name:
return self.name
else:
return str(self.id)
def get_media_items(self, exclude_kwargs=None):
if not exclude_kwargs:
exclude_kwargs = {}
return self.media_items.exclude(
**exclude_kwargs
).filter(
enable=True
).order_by('order')
def get_video_items(self):
exclude_kwargs = {'video': None}
return self.get_media_items(exclude_kwargs=exclude_kwargs)
def get_picture_items(self):
exclude_kwargs = {'picture': None}
return self.get_media_items(exclude_kwargs=exclude_kwargs)
def pop_node_by_name(self, node_name):
if not self.json_data or not node_name in self.json_data:
return None
@@ -108,10 +127,23 @@ class BaseModelViewPage(BaseModel):
FAQ_title = models.CharField(max_length=250, verbose_name=_(u'FAQ Заголовок'), null=True, blank=True)
FAQ_items = GenericRelation('GeneralApp.FAQitem', related_query_name='grel_%(class)s_for_faq_item')
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')

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

@@ -82,26 +82,18 @@ 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 = 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)
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)
except Exception as e:
msg = 'admin_send_mail_by_SMTPlib error = {0}'.format(str(e))
@@ -111,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
@@ -153,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)
@@ -229,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")
@@ -241,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')
@@ -296,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

@@ -0,0 +1,113 @@
import json
from django.conf import settings
import requests
from requests_pkcs12 import get,post
# для песочницы
# pkcs12_filename = 'dvldigitalprojects.p12'
# pkcs12_password = 'QNlhRStcY7mB'
# api_pass = 'aPqSRVZhxFjjSqbB'
# для прода
# pkcs12_filename = 'dvldigitalprojects.p12'
# pkcs12_password = 'fzSBm6WISje7'
# api_pass = 't9g2+bZSvxNxCu+t'
def get_domain_url():
return settings.PAY_SYSTEM_URL #'https://sandboxapi.paymtech.kz/'
def get_kwargs_for_request():
return {
'headers': {
'content-type': 'application/json',
},
'auth': ('dvldigitalprojects', settings.API_PASS),
'pkcs12_filename': settings.PKCS12_FILENAME,
'pkcs12_password': settings.PKCS12_PASS
}
def ping():
url = f'{get_domain_url()}ping'
data = {}
try:
msg = f'GET {url}'
print(msg)
res = get(
url,
**get_kwargs_for_request()
)
msg = f'answer received = {str(res)}'
print(msg)
except Exception as e:
msg = f'Exception GET {url} = {str(e)} ({str(res)})'
print(msg)
res = None
return False
return True
def get_order_status(bank_order_id):
url = f'{get_domain_url()}orders/{str(bank_order_id)}'
res = None
data = {
'expand': [
'card', 'client', 'location', 'custom_fields',
'issuer', 'secure3d', 'operations', 'cashflow'
]
}
try:
msg = f'GET {url}'
print(msg)
res = get(
url,
data=json.dumps(data),
**get_kwargs_for_request()
)
msg = f'get_order_status answer received = {str(res)}'
print(msg)
except Exception as e:
msg = f'Exception get_order_status GET {url} = {str(e)} ({str(res)})'
print(msg)
res = None
return res
def create_order(data):
url = f'{get_domain_url()}orders/create'
res = None
try:
msg = f'POST {url}'
print(msg)
res = post(
url,
data=json.dumps(data),
**get_kwargs_for_request()
)
msg = f'create_order answer received = {str(res.text)}'
# if res:# and res.status_code > 300:
# msg += f' > ({str(res.text)})'
print(msg)
except Exception as e:
msg = f'Exception create_order POST {url} = {str(e)} ({str(res)})'
if res:
msg += f' > ({str(res.text)})'
print(msg)
res = None
return res

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

0
BillingApp/__init__.py Normal file
View File

39
BillingApp/admin.py Normal file
View File

@@ -0,0 +1,39 @@
from sets.admin import *
from .models import *
from django.contrib import admin
class Admin_SubscribeOrder(Admin_BaseModel):
fieldsets = (
(None, {
'classes': ['wide'],
'fields': (
('user', 'subscribe', 'subscribe_for_user'),
('enable', 'order'),
('sum', 'currency'),
('status', 'last_operation_status'),
('bank_order_id', 'pay_page'),
'json_data',
)
}),
)
list_display = [
'id', 'enable',
'user', 'subscribe', 'subscribe_for_user',
'bank_order_id',
'sum', 'currency',
'status', 'last_operation_status',
'order', 'modifiedDT', 'createDT'
]
list_display_links = ['id', 'user', 'subscribe']
list_editable = ['enable']
readonly_fields = ['subscribe_for_user', 'sum', 'currency', 'modifiedDT', 'createDT']
list_filter = ['enable', 'status', 'modifiedDT', 'createDT']
search_fields = ['id', 'last_operation_status', 'status']
# filter_horizontal = ['options']
admin.site.register(SubscribeOrder, Admin_SubscribeOrder)

6
BillingApp/apps.py Normal file
View File

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

101
BillingApp/funcs.py Normal file
View File

@@ -0,0 +1,101 @@
from datetime import datetime, timedelta
from .models import *
import json
def get_order_status(order):
from BaseModels.pay_systems.DVL_Group_kaz.api.funcs import get_order_status
res_status = None
if not order or not order.bank_order_id:
return order
try:
res_data = get_order_status(order.bank_order_id)
res = json.loads(res_data.text)
res = res['orders'][0]
order.json_data['status'] = res
order.status = res['status']
# if res['amount'] == res['amount_charged'] and res['status'] == 'charged':
order.save()
# return order.status
except Exception as e:
msg = f'Exception get_order_status = {str(e)}'
if order:
msg = f'Exception get_order_status (data = {str(order.id)}) = {str(e)}'
print(msg)
return order
def get_orders_for_user(user):
orders = SubscribeOrder.objects.filter(
enable=True,
user=user,
subscribe_for_user=None,
createDT__gt=datetime.now() - timedelta(hours=1)
).order_by('subscribe', '-createDT').distinct('subscribe')
SubscribeOrder.objects.filter(
user=user
).exclude(
id__in=orders.values_list('id', flat=True)
).update(enable=False)
return orders
def create_subscribe_order(data):
order = None
try:
order = SubscribeOrder.objects.create(**data)
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)
from BaseModels.pay_systems.DVL_Group_kaz.api.funcs import create_order
data = {
'currency': data['currency'],
'amount': data['sum'],
'description': f'Заказ {order.id} на подписку '
f'{data["subscribe"].name} '
f'для пользователя {data["user"].username}',
'options': {
'force3d': 1,
'auto_charge': 1,
'return_url': f'{sets["domain"]}/profile/page/my_subscribe/'
}
}
res_data = create_order(data)
order.pay_page = res_data.headers.get('location')
res = json.loads(res_data.text)
res = res['orders'][0]
order.json_data['create_order'] = res
order.modifiedDT = datetime.strptime(res['updated'], '%Y-%m-%d %H:%M:%S')
order.status = res['status']
order.bank_order_id = res['id']
if 'segment' in res:
order.segment = res['segment']
if 'merchant_order_id' in res:
order.merchant_order_id = res['merchant_order_id']
order.save()
except Exception as e:
msg = f'Exception create_subscribe_order (data = {str(data)}) = {str(e)}'
print(msg)
return order

View File

@@ -0,0 +1,42 @@
# Generated by Django 4.2.2 on 2024-04-19 16:24
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('SubscribesApp', '0003_alter_subscribe_bg_color_alter_subscribe_text_color'),
]
operations = [
migrations.CreateModel(
name='SubscribeOrder',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.TextField(blank=True, help_text='Название', null=True, verbose_name='Название')),
('name_plural', models.TextField(blank=True, null=True, verbose_name='Название (множественное число)')),
('order', models.IntegerField(blank=True, null=True, verbose_name='Очередность отображения')),
('createDT', models.DateTimeField(auto_now_add=True, verbose_name='Дата и время создания')),
('modifiedDT', models.DateTimeField(blank=True, null=True, verbose_name='Дата и время последнего изменения')),
('enable', models.BooleanField(db_index=True, default=True, verbose_name='Включено')),
('json_data', models.JSONField(blank=True, default=dict, verbose_name='Дополнительные данные')),
('sum', models.PositiveSmallIntegerField(verbose_name='Сумма')),
('currency', models.CharField(max_length=3, verbose_name='Валюта')),
('segment', models.CharField(verbose_name='ID Сегмента')),
('merchant_order_id', models.CharField(verbose_name='merchant_order_id')),
('bank_order_id', models.CharField(verbose_name='ID заказа в банке')),
('status', models.CharField(verbose_name='Статус заказа в банке')),
('subscribe', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='subscribe_orders_for_subscribe', to='SubscribesApp.subscribe', verbose_name='Подписка')),
('subscribe_for_user', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='subscribe_orders_for_user_subscribe', to='SubscribesApp.subscribeforuser', verbose_name='Подписка пользователя')),
('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='subscribe_orders_for_user', to='SubscribesApp.subscribe', verbose_name='Пользователь')),
],
options={
'verbose_name': 'Заказ на подписку',
'verbose_name_plural': 'Заказы на подписки',
},
),
]

View File

@@ -0,0 +1,21 @@
# Generated by Django 4.2.2 on 2024-04-19 16:29
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('BillingApp', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='subscribeorder',
name='user',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='subscribe_orders_for_user', to=settings.AUTH_USER_MODEL, verbose_name='Пользователь'),
),
]

View File

@@ -0,0 +1,43 @@
# Generated by Django 4.2.2 on 2024-04-19 16:36
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('BillingApp', '0002_alter_subscribeorder_user'),
]
operations = [
migrations.AddField(
model_name='subscribeorder',
name='pay_page',
field=models.URLField(blank=True, default=None, null=True, verbose_name='Ссылка на страницу оплаты'),
),
migrations.AlterField(
model_name='subscribeorder',
name='bank_order_id',
field=models.CharField(default='', verbose_name='ID заказа в банке'),
),
migrations.AlterField(
model_name='subscribeorder',
name='merchant_order_id',
field=models.CharField(default='', verbose_name='merchant_order_id'),
),
migrations.AlterField(
model_name='subscribeorder',
name='segment',
field=models.CharField(default='', verbose_name='ID Сегмента'),
),
migrations.AlterField(
model_name='subscribeorder',
name='status',
field=models.CharField(default='', verbose_name='Статус заказа в банке'),
),
migrations.AlterField(
model_name='subscribeorder',
name='sum',
field=models.PositiveSmallIntegerField(default=0, verbose_name='Сумма'),
),
]

View File

@@ -0,0 +1,38 @@
# Generated by Django 4.2.2 on 2024-04-19 16:47
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('BillingApp', '0003_subscribeorder_pay_page_and_more'),
]
operations = [
migrations.AlterField(
model_name='subscribeorder',
name='bank_order_id',
field=models.CharField(default=None, null=True, verbose_name='ID заказа в банке'),
),
migrations.AlterField(
model_name='subscribeorder',
name='currency',
field=models.CharField(default='USD', max_length=3, verbose_name='Валюта'),
),
migrations.AlterField(
model_name='subscribeorder',
name='merchant_order_id',
field=models.CharField(default=None, null=True, verbose_name='merchant_order_id'),
),
migrations.AlterField(
model_name='subscribeorder',
name='segment',
field=models.CharField(default=None, null=True, verbose_name='ID Сегмента'),
),
migrations.AlterField(
model_name='subscribeorder',
name='status',
field=models.CharField(default=None, null=True, verbose_name='Статус заказа в банке'),
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 4.2.2 on 2024-04-19 17:57
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('BillingApp', '0004_alter_subscribeorder_bank_order_id_and_more'),
]
operations = [
migrations.AddField(
model_name='subscribeorder',
name='last_operation_status',
field=models.CharField(default=None, null=True, verbose_name='Статус последней операции'),
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 4.2.2 on 2024-07-12 17:23
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('BillingApp', '0005_subscribeorder_last_operation_status'),
]
operations = [
migrations.AlterField(
model_name='subscribeorder',
name='currency',
field=models.CharField(default='KZT', max_length=3, verbose_name='Валюта'),
),
]

View File

75
BillingApp/models.py Normal file
View File

@@ -0,0 +1,75 @@
from django.db import models
from BaseModels.base_models import BaseModel
from SubscribesApp.models import Subscribe, SubscribeForUser
from AuthApp.models import User
from django.utils.translation import gettext as _
class SubscribeOrder(BaseModel):
subscribe = models.ForeignKey(
Subscribe, verbose_name=_('Подписка'),
on_delete=models.SET_NULL, blank=True, null=True,
related_name='subscribe_orders_for_subscribe'
)
user = models.ForeignKey(
User, verbose_name=_('Пользователь'),
on_delete=models.SET_NULL, blank=True, null=True,
related_name='subscribe_orders_for_user'
)
subscribe_for_user = models.OneToOneField(
SubscribeForUser, verbose_name=_('Подписка пользователя'),
on_delete=models.SET_NULL, blank=True, null=True,
related_name='subscribe_orders_for_user_subscribe'
)
sum = models.PositiveSmallIntegerField(verbose_name=_('Сумма'), default=0)
currency = models.CharField(verbose_name=_('Валюта'), max_length=3, default='KZT')
segment = models.CharField(verbose_name=_('ID Сегмента'), null=True, default=None)
merchant_order_id = models.CharField(verbose_name=_('merchant_order_id'), null=True, default=None)
bank_order_id = models.CharField(verbose_name=_('ID заказа в банке'), null=True, default=None)
status = models.CharField(verbose_name=_('Статус заказа в банке'), null=True, default=None)
last_operation_status = models.CharField(verbose_name=_('Статус последней операции'), null=True, default=None)
pay_page = models.URLField(verbose_name=_('Ссылка на страницу оплаты'), null=True, blank=True, default=None)
class Meta:
verbose_name = _('Заказ на подписку')
verbose_name_plural = _('Заказы на подписки')
def activate_subscribe_for_user(self):
from datetime import datetime, timedelta
kwargs = {
'user': self.user,
'subscribe': self.subscribe,
'last_paid_DT': datetime.now(),
'receive_finish_subscribe_msg': True,
# 'enable': True,
}
from SubscribesApp.funcs import create_subscribe_by_data
subscribe_for_user = create_subscribe_by_data(kwargs)
self.subscribe_for_user = subscribe_for_user
self.enable = False
self.save()
subscribe_for_user.activate(
paid_period_from_DT=datetime.now(),
paid_period_to_DT=datetime.now() + timedelta(hours=self.subscribe.period)
)
return self
def __str__(self):
res = 'Заказ'
if self.subscribe:
res += f' на подписку {self.subscribe.name}'
if self.user:
res += f' для {self.user.username}'
if not res:
res += f' {str(self.id)}'
return res

3
BillingApp/tests.py Normal file
View File

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

3
BillingApp/views.py Normal file
View File

@@ -0,0 +1,3 @@
from django.shortcuts import render
# Create your views here.

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,16 @@ 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):
if not user or not user.is_authenticated:
return 0
msgs = Message.objects.filter(receiver=user, status='sended', group=None)
return msgs.count()
def get_update_chat_Dict(data):
@@ -45,11 +57,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 +115,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 +291,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 +311,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

@@ -18,12 +18,15 @@ from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync
@login_required(login_url='/profile/login/')
@login_required()#login_url='/profile/login/')
def get_file_from_msg_ajax(request):
if request.method != 'POST':
raise Http404
from GeneralApp.funcs import get_and_set_lang
lang = get_and_set_lang(request)
try:
data = json.loads(request.body)
@@ -35,7 +38,9 @@ def get_file_from_msg_ajax(request):
res_Dict = file
break
return JsonResponse(res_Dict, status=200)
from GeneralApp.funcs import get_add_to_ajax_response_Dict
res_Dict.update(get_add_to_ajax_response_Dict(request.user))
return JsonResponse(res_Dict)
except Exception as e:
msg = f'get_file_from_msg_ajax Error = {str(e)}'
@@ -43,23 +48,29 @@ def get_file_from_msg_ajax(request):
@login_required(login_url='/profile/login/')
@login_required()#login_url='/profile/login/')
def show_chat_w_user_ajax(request):
if request.method != 'POST':
raise Http404
from GeneralApp.funcs import get_and_set_lang
lang = get_and_set_lang(request)
try:
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'
html = render_to_string(tpl_name, Dict, request=request)
return JsonResponse({'html': html}, status=200)
res_Dict = {'html': html}
from GeneralApp.funcs import get_add_to_ajax_response_Dict
res_Dict.update(get_add_to_ajax_response_Dict(request.user))
return JsonResponse(res_Dict)
except Exception as e:
msg = f'show_chat_w_user_ajax Error = {str(e)}'
@@ -73,6 +84,9 @@ def update_chat_ajax2(request):
if request.method != 'POST':
raise Http404
from GeneralApp.funcs import get_and_set_lang
lang = get_and_set_lang(request)
res_Dict = {}
msgs = []
Dict = {}
@@ -99,7 +113,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 +137,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({
@@ -146,7 +161,9 @@ def update_chat_ajax2(request):
res_Dict.update({
'required_beep': required_beep,
})
return JsonResponse(res_Dict, status=200)
from GeneralApp.funcs import get_add_to_ajax_response_Dict
res_Dict.update(get_add_to_ajax_response_Dict(request.user))
return JsonResponse(res_Dict)
except Exception as e:
msg = f'update_chat_ajax2 Error = {str(e)}'
@@ -161,6 +178,9 @@ def update_chat_ajax(request):
if request.method != 'POST':
raise Http404
from GeneralApp.funcs import get_and_set_lang
lang = get_and_set_lang(request)
res_Dict = {}
msgs = []
Dict = {}
@@ -190,6 +210,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 +222,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 +243,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({
@@ -249,14 +274,17 @@ def update_chat_ajax(request):
res_Dict.update({
'required_beep': required_beep,
})
return JsonResponse(res_Dict, status=200)
from GeneralApp.funcs import get_add_to_ajax_response_Dict
res_Dict.update(get_add_to_ajax_response_Dict(request.user))
return JsonResponse(res_Dict)
except Exception as e:
msg = f'update_chat_ajax Error = {str(e)}'
return JsonResponse({'error': msg}, status=400)
# @login_required(login_url='/profile/login/')
# @login_required()#login_url='/profile/login/')
# def send_msg_ajax(request):
# from AuthApp.models import User
#
@@ -368,12 +396,15 @@ def update_chat_ajax(request):
@login_required(login_url='/profile/login/')
@login_required()#login_url='/profile/login/')
def support_show_chat_by_ticket_ajax(request):
if request.method != 'POST':
raise Http404
from GeneralApp.funcs import get_and_set_lang
lang = get_and_set_lang(request)
try:
data = json.loads(request.body)
@@ -404,44 +435,62 @@ def support_show_chat_by_ticket_ajax(request):
'cur_receiver': cur_receiver,
'new_msg_allow': new_msg_allow,
'staff': request.user.is_staff,
'mobile': data['mobile']
# '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)
res_Dict = {'html': html}
from GeneralApp.funcs import get_add_to_ajax_response_Dict
res_Dict.update(get_add_to_ajax_response_Dict(request.user))
return JsonResponse(res_Dict)
except Exception as e:
msg = f'support_show_chat_by_ticket_ajax Error = {str(e)}'
return JsonResponse({'error': msg}, status=400)
@login_required(login_url='/profile/login/')
@login_required()#login_url='/profile/login/')
def support_create_ticket_form_ajax(request):
from ChatServiceApp.forms import TicketForm
if request.method != 'POST':
raise Http404
from GeneralApp.funcs import get_and_set_lang
lang = get_and_set_lang(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)
return JsonResponse({'html': html}, status=200)
res_Dict = {'html': html}
from GeneralApp.funcs import get_add_to_ajax_response_Dict
res_Dict.update(get_add_to_ajax_response_Dict(request.user))
return JsonResponse(res_Dict)
@login_required(login_url='/profile/login/')
@login_required()#login_url='/profile/login/')
def create_ticket_ajax(request):
from ChatServiceApp.forms import TicketForm
if request.method != 'POST':
raise Http404
from GeneralApp.funcs import get_and_set_lang
lang = get_and_set_lang(request)
try:
data = request.POST
@@ -450,6 +499,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)
@@ -490,19 +541,25 @@ 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 = {
'html': html
}
from GeneralApp.funcs import get_add_to_ajax_response_Dict
res_Dict.update(get_add_to_ajax_response_Dict(request.user))
return JsonResponse(res_Dict)
except Exception as e:
msg = f'{_("ошибка в запросе")} = {str(e)}'
errors_Dict = {
'errors': {
'all__': f'{_("ошибка в запросе")} = {str(e)}'
'all__': msg
}
}
Dict = {'form': errors_Dict}

View File

@@ -38,6 +38,18 @@ class MsgGroup(BaseModel):
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 = _('Тикеты')

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,9 @@
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,7 +17,7 @@ class Admin_StaticPage(Admin_Trans_BaseModelViewPage):
'order',
)
}),
('Настройки', {
(_('Настройки'), {
'classes': ['wide', 'collapse'],
'fields': (
'FAQ_title',
@@ -46,51 +49,66 @@ class Admin_StaticPage(Admin_Trans_BaseModelViewPage):
if request.user.is_superuser:
return True
if obj.url in ('main', 'spec_technics', 'works'):
if not obj or obj.url in ('main', 'works'):
return False
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,91 @@
from django.http import HttpResponse, Http404, FileResponse
from django.conf import settings
def get_and_set_lang(request):
from django.utils.translation import activate, get_language
lang = None
cur_url_list = request.path.split('/')
if len(cur_url_list) > 1 and cur_url_list[1] in settings.MODELTRANSLATION_LANGUAGES:
lang = cur_url_list[1]
if not lang:
referer_url = request.META.get('HTTP_REFERER')
if referer_url:
url_list = referer_url.split('//')
if len(url_list) > 1:
url_list = url_list[1].split('/')
if len(url_list) > 1 and url_list[1] in settings.MODELTRANSLATION_LANGUAGES:
lang = url_list[1]
if not lang:
lang = get_language()
if not lang:
lang = 'en'
activate(lang)
return lang
def get_add_to_ajax_response_Dict(user):
context_Dict = {}
from ChatServiceApp.funcs import get_unanswered_msgs_count_for_user
context_Dict.update({
'unanswered_msgs_count': get_unanswered_msgs_count_for_user(user)
})
return context_Dict
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}
def get_inter_http_respose(template_obj, context_Dict, request):
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_response(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)
from ChatServiceApp.funcs import get_unanswered_msgs_count_for_user
context_Dict.update({
'unanswered_msgs_count': get_unanswered_msgs_count_for_user(request.user)
})
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

@@ -1,7 +1,66 @@
from .models import *
from django.utils.translation import gettext as _
def init():
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_names = options.values_list('name', flat=True)
#
# if not 'mail_server_url':
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

View File

@@ -0,0 +1,48 @@
from django.core.management.base import BaseCommand
from datetime import datetime
from BaseModels.mailSender import techSendMail
from ...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 RoutesApp.search_matches import search_matches
msg = search_matches()
if msg:
print(msg)
log += f'\n{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 datetime.now().hour == 19:
try:
from SubscribesApp.reports import send_mail_for_user_subscribes_that_is_going_to_finish
msg = send_mail_for_user_subscribes_that_is_going_to_finish()
if msg:
print(msg)
log += f'\n{msg}'
except Exception as e:
msg = f'send_mail_for_user_subscribes_that_is_going_to_finish search_matches fail = {str(e)}'
print(msg)
techSendMail(mail_sets, msg, title='every_1hour_start send_mail_for_user_subscribes_that_is_going_to_finish')
if log:
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,31 @@
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 SubscribesApp.funcs import finish_user_subscribes, extension_free_subscribes
extension_free_subscribes()
finish_user_subscribes()
except Exception as e:
msg = f'every_day_start fail = {str(e)}'
print(msg)
techSendMail(mail_sets, msg, title='every_day_start fail')
# 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,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

@@ -0,0 +1,41 @@
# Generated by Django 4.2.2 on 2024-11-15 14:50
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('contenttypes', '0002_remove_content_type_name'),
('GeneralApp', '0005_option_name_en_option_name_ru_option_prefix_en_and_more'),
]
operations = [
migrations.CreateModel(
name='MediaItem',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.TextField(blank=True, help_text='Название', null=True, verbose_name='Название')),
('name_ru', models.TextField(blank=True, help_text='Название', null=True, verbose_name='Название')),
('name_en', models.TextField(blank=True, help_text='Название', null=True, verbose_name='Название')),
('name_plural', models.TextField(blank=True, null=True, verbose_name='Название (множественное число)')),
('order', models.IntegerField(blank=True, null=True, verbose_name='Очередность отображения')),
('createDT', models.DateTimeField(auto_now_add=True, verbose_name='Дата и время создания')),
('modifiedDT', models.DateTimeField(blank=True, null=True, verbose_name='Дата и время последнего изменения')),
('enable', models.BooleanField(db_index=True, default=True, verbose_name='Включено')),
('json_data', models.JSONField(blank=True, default=dict, verbose_name='Дополнительные данные')),
('object_id', models.PositiveIntegerField()),
('picture', models.ImageField(blank=True, null=True, upload_to='media/', verbose_name='Фото')),
('video', models.FileField(blank=True, null=True, upload_to='media/video/', verbose_name='Видео')),
('comment', models.TextField(blank=True, null=True, verbose_name='Комментарий')),
('comment_ru', models.TextField(blank=True, null=True, verbose_name='Комментарий')),
('comment_en', models.TextField(blank=True, null=True, verbose_name='Комментарий')),
('content_type', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='contenttypes.contenttype')),
],
options={
'verbose_name': 'Медиа элемент',
'verbose_name_plural': 'Медиа элементы',
},
),
]

View File

@@ -0,0 +1,23 @@
# Generated by Django 4.2.2 on 2024-11-15 15:58
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('GeneralApp', '0006_mediaitem'),
]
operations = [
migrations.AlterField(
model_name='mediaitem',
name='picture',
field=models.ImageField(blank=True, null=True, upload_to='uploads/', verbose_name='Фото'),
),
migrations.AlterField(
model_name='mediaitem',
name='video',
field=models.FileField(blank=True, null=True, upload_to='uploads/video/', verbose_name='Видео'),
),
]

View File

@@ -0,0 +1,23 @@
# Generated by Django 4.2.2 on 2024-11-15 15:59
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('GeneralApp', '0007_alter_mediaitem_picture_alter_mediaitem_video'),
]
operations = [
migrations.AlterField(
model_name='mediaitem',
name='picture',
field=models.ImageField(blank=True, null=True, upload_to='media_items/photo/', verbose_name='Фото'),
),
migrations.AlterField(
model_name='mediaitem',
name='video',
field=models.FileField(blank=True, null=True, upload_to='media_items/video/', verbose_name='Видео'),
),
]

View File

@@ -3,6 +3,26 @@ from BaseModels.base_models import BaseModelViewPage, BaseModel
from django.utils.translation import gettext_lazy as _
# from ckeditor.fields import RichTextField
from ckeditor_uploader.fields import RichTextUploadingField
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey
class MediaItem(BaseModel):
content_type = models.ForeignKey(ContentType, on_delete=models.SET_NULL, null=True)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
picture = models.ImageField(upload_to='media_items/photo/', verbose_name=_('Фото'), null=True, blank=True)
video = models.FileField(upload_to='media_items/video/', verbose_name=_('Видео'), null=True, blank=True)
comment = models.TextField(verbose_name=_('Комментарий'), null=True, blank=True)
class Meta:
verbose_name = _('Медиа элемент')
verbose_name_plural = _('Медиа элементы')
class StaticPage(BaseModelViewPage):
promo_header = models.BooleanField(verbose_name=_('Промо-хэдер'), default=False)
@@ -29,9 +49,6 @@ class Option(BaseModel):
class FAQitem(BaseModel):
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey
content_type = models.ForeignKey(ContentType, on_delete=models.SET_NULL, null=True)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')

View File

@@ -78,7 +78,7 @@ def del_amp_symbols(value):
@stringfilter
def del_lang_from_path(value):
path_list = value.split('/')
path = '/' + '/'.join(path_list[2:])
path = '/' + '/'.join(path_list[4:])
# for i in path_list[1:]:
# path.join(i + '/')

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 = (
@@ -21,3 +27,9 @@ class FAQitem_TranslationOptions(TranslationOptions):
)
translator.register(FAQitem, FAQitem_TranslationOptions)
class MediaItem_TranslationOptions(TranslationOptions):
fields = (
'name', 'comment',
)
translator.register(MediaItem, MediaItem_TranslationOptions)

View File

@@ -6,6 +6,11 @@ from .views import *
urlpatterns = [
path('', MainPage, name='main'),
path('mover_landing_page/', LandingMoverPage, name='mover_landing_page'),
path('customer_landing_page/', LandingCustomerPage, name='customer_landing_page'),
path('page/<str:url>/', StaticPageView, name='static_page'),
path('test_code', test_code, name='test_code'),
path('generate_routes/<int:routes_count>/', generate_routes, name='generate_routes'),
]

View File

@@ -1,50 +1,215 @@
import json
from django.http import HttpResponse, Http404, FileResponse
from django.http import HttpResponse, Http404, FileResponse, HttpResponseRedirect
from django.template import loader, RequestContext
from django.contrib.auth.decorators import login_required
from .models import *
from django.conf import settings
from .funcs import get_inter_http_respose
from .funcs import get_inter_http_response
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
from datetime import datetime, timedelta
from django.urls import reverse
def generate_routes(request, routes_count):
if (not request.user
or not request.user.is_active
or not request.user.is_authenticated
or not request.user.is_staff
):
raise Http404
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()
res = None
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_air = Airport.objects.get(iata_code='MSQ')
to_air = Airport.objects.get(iata_code='SVO')
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
routes = [
Route(
type_transport='road',
departure_DT=datetime.now() + timedelta(days=7),
arrival_DT=datetime.now() + timedelta(days=8),
from_address_point=to_air.city.id,
to_address_point=from_air.city.id,
from_city=to_air.city,
to_city=from_air.city,
weight=item,
phone='0987654321',
owner=request.user
) for item in range(routes_count)
]
if required_save:
route.save()
Route.objects.bulk_create(routes)
if res:
if type(res) == str:
return HttpResponse(res)
else:
return res
return HttpResponse('finished')
def test_code(request):
if (not request.user
or not request.user.is_active
or not request.user.is_authenticated
or not request.user.is_staff
):
raise Http404
res = ''
from RoutesApp.search_matches import search_matches
from RoutesApp.models import Route
search_matches(Route.objects.filter(id=17158))
# from RoutesApp.funcs import get_city_by_type_transport_and_address_point
# from RoutesApp.models import Route
# from ReferenceDataApp.models import Airport, City
#
# res = None
#
# from_air = Airport.objects.get(iata_code='MSQ')
# to_air = Airport.objects.get(iata_code='SVO')
#
# routes = [
# Route(
# type_transport='road',
# departure_DT=datetime.now() + timedelta(days=7),
# arrival_DT=datetime.now() + timedelta(days=8),
# from_address_point=to_air.city.id,
# to_address_point=from_air.city.id,
# from_city=to_air.city,
# to_city=from_air.city,
# weight=item,
# phone='0987654321',
# owner=request.user
# ) for item in range(100)
# ]
# routes = [
# Route(
# type_transport='avia',
# departure_DT=datetime(year=2024, month=9, day=1),
# arrival_DT=datetime(year=2024, month=9, day=3),
# from_address_point = from_air.id,
# to_address_point = to_air.id,
# from_city = from_air.city,
# to_city = to_air.city,
# weight = item,
# phone = '1234567890',
# owner = request.user
# ) for item in range(1000)
# ]
#
# Route.objects.bulk_create(routes)
# from RoutesApp.search_matches import search_matches
# routes = Route.objects.filter()[:10]
# msg = search_matches(routes)
# from ReferenceDataApp.funcs import parse_data
# parse_data()
# from SubscribesApp.reports import send_mail_for_user_subscribes_that_is_going_to_finish
# send_mail_for_user_subscribes_that_is_going_to_finish()
if res:
if type(res) == str:
return HttpResponse(res)
else:
return res
return HttpResponse('finished')
def Page404(request, exeption=None):
Dict = {}
t = loader.get_template('404.html')
try:
res = get_inter_http_response(t, Dict, request)
return HttpResponse(res, status=404)
except Exception as e:
return HttpResponse(str(e))
def LandingMoverPage(request):
from .init_options import init_options
init_options()
print(f'LOCALE_PATHS = {str(settings.LOCALE_PATHS)}')
page, is_created = StaticPage.objects.get_or_create(url='landing_mover')
Dict = {
'page': page,
}
breadcrumbs_Dict = {
}
Dict.update({'breadcrumbs': breadcrumbs_Dict})
t = loader.get_template('pages/p_mover_landing_page.html')
return get_inter_http_response(t, Dict, request)
def LandingCustomerPage(request):
from .init_options import init_options
init_options()
print(f'LOCALE_PATHS = {str(settings.LOCALE_PATHS)}')
page, is_created = StaticPage.objects.get_or_create(url='landing_customer')
Dict = {
'page': page,
}
breadcrumbs_Dict = {
}
Dict.update({'breadcrumbs': breadcrumbs_Dict})
t = loader.get_template('pages/p_customer_landing_page.html')
return get_inter_http_response(t, Dict, request)
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,
@@ -54,19 +219,21 @@ def MainPage(request):
'owner_type': 'mover'
}
breadcrumbs_Dict = {
}
Dict.update({'breadcrumbs': breadcrumbs_Dict})
t = loader.get_template('pages/p_main.html')
return get_inter_http_respose(t, Dict, request)
return get_inter_http_response(t, Dict, request)
# return HttpResponse(t.render(Dict, request))
def StaticPageView(request, url):
from RoutesApp.forms import RouteForm
from SubscribesApp.funcs import get_subsribes_w_options
from SubscribesApp.funcs import get_subscribes_w_options
Dict = {}
@@ -82,13 +249,19 @@ def StaticPageView(request, url):
'route_form': RouteForm(),
'owner_type': 'mover'
})
elif url in ['landing_customer', 'landing_mover']:
raise Http404
# return HttpResponseRedirect(reverse('customer_landing_page'))
# elif url == 'landing_mover':
# return HttpResponseRedirect(reverse('mover_landing_page'))
# elif url == 'works':
# return WorksPage(request)
elif url in ['main']:
raise Http404
if url in ['for_movers', 'for_customers']:
subscribes, all_options = get_subsribes_w_options()
subscribes, all_options = get_subscribes_w_options()
Dict.update({
'subscribes': subscribes,
})
@@ -103,8 +276,11 @@ def StaticPageView(request, url):
'page': page,
})
# from PushMessages.views import send_push
# send_push(user=request.user, title='title', text='text')
t = loader.get_template('pages/p_static_page.html')
return get_inter_http_respose(t, Dict, request)
return get_inter_http_response(t, Dict, request)
# return HttpResponse(t.render(Dict, request))

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

53
PushMessages/views.py Normal file
View File

@@ -0,0 +1,53 @@
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 _
from SubscribesApp.funcs import check_option_in_cur_user_subscribe
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):
if not check_option_in_cur_user_subscribe(user, 'push уведомления'):
return False
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"})

View File

@@ -2,6 +2,7 @@ from django.contrib import admin
from sets.admin import Admin_Trans_BaseModel
from .models import *
from modeltranslation.admin import TranslationAdmin
from django.utils.translation import gettext as _
class Admin_Country(Admin_Trans_BaseModel):
fieldsets = [
@@ -10,11 +11,20 @@ class Admin_Country(Admin_Trans_BaseModel):
'fields': [
'name', 'enable', 'short_code', 'code',
]
}]
}],
[_('Дополнительно'), {
'classes': ['wide', 'collapse'],
'fields': (
'timezone',
'geo_lat', 'geo_lon',
'json_data',
)
}],
]
list_display = [
'id', 'name', 'name_en', 'name_ru',
'timezone',
'short_code', 'code',
'enable', 'area_id', 'parsing_finished_DT',
'order', 'modifiedDT', 'createDT']
@@ -22,18 +32,35 @@ class Admin_Country(Admin_Trans_BaseModel):
admin.site.register(Country, Admin_Country)
class Admin_City(Admin_Trans_BaseModel):
def cur_dt(self, obj):
if obj.timezone:
return obj.get_current_datetime()
else:
return '-'
cur_dt.short_description = 'текущее время'
fieldsets = [
[None, {
'classes': ['wide'],
'fields': [
'name', 'enable', 'country',
]
}]
}],
[_('Дополнительно'), {
'classes': ['wide', 'collapse'],
'fields': (
'timezone',
'geo_lat', 'geo_lon',
'json_data',
)
}],
]
list_display = [
'id', 'name', 'name_en', 'name_ru',
'country',
'timezone', 'cur_dt',
'enable', 'area_id', 'parsing_finished_DT',
'order', 'modifiedDT', 'createDT']
search_fields = ['id', 'name_en', 'name_ru', 'country__name']
@@ -50,12 +77,21 @@ class Admin_Airport(Admin_Trans_BaseModel):
'international_name',
# 'area_id'
]
}]
}],
[_('Дополнительно'), {
'classes': ['wide', 'collapse'],
'fields': (
'timezone',
'geo_lat', 'geo_lon',
'json_data',
)
}],
]
list_display = [
'id', 'name', 'name_en', 'name_ru',
'city', 'iata_code', 'icao_code',
'timezone',
'international_name',
'enable', 'area_id', 'parsing_finished_DT',
'order', 'modifiedDT', 'createDT']

View File

@@ -3,24 +3,45 @@ from .models import *
import hashlib, json
from datetime import datetime, timedelta
from django.db.models import Q
from timezonefinder import TimezoneFinder
tzf = TimezoneFinder()
def search_cities_in_db(search_str):
res_data = []
Q_obj = Q(name_en__icontains=search_str) | Q(name_ru__icontains=search_str) | \
Q(country__name_en__icontains=search_str) | Q(country__name_ru__icontains=search_str)
res_data = City.objects.filter(Q_obj).values('id', 'name', 'country__name')
objs = City.objects.filter(Q_obj)
if objs:
ids = objs.values_list('id', flat=True)
objs_wo_tz = objs.filter(timezone=None)
for item in objs_wo_tz:
item.get_n_save_timezone()
res_data = City.objects.filter(id__in=ids).values(
'id', 'name', 'country__name', 'timezone'
)
return list(res_data)
def search_airports_in_db(search_str):
res_data = []
Q_obj = Q(iata_code__icontains=search_str) | \
Q(name_en__icontains=search_str) | Q(name_ru__icontains=search_str) | \
Q(city__name_en__icontains=search_str) | Q(city__name_ru__icontains=search_str) | \
Q(city__country__name_en__icontains=search_str) | \
Q(city__country__name_ru__icontains=search_str)
res_data = Airport.objects.filter(Q_obj).values('id', 'name', 'iata_code', 'city__name', 'city__country__name')
objs = Airport.objects.filter(Q_obj)
if objs:
ids = objs.values_list('id', flat=True)
objs_wo_tz = objs.filter(city__timezone=None)
for item in objs_wo_tz:
item.city.get_n_save_timezone()
res_data = Airport.objects.filter(id__in=ids).values(
'id', 'name', 'iata_code',
'city__name', 'city__country__name', 'city__timezone'
)
return list(res_data)
@@ -57,25 +78,39 @@ def create_airports_by_airportsList(airportsList, city=None):
if airport_Dict['iata']:
kwargs.update({'iata_code': airport_Dict['iata']})
airport = Airport.objects.get(**kwargs)
if airport.geo_lat and airport.geo_lon and not airport.timezone:
airport.timezone = tzf.timezone_at(
lng=float(airport.geo_lon), lat=float(airport.geo_lat))
airport.modifiedDT = datetime.now()
airport.save()
print(f'airport {airport.international_name} - {airport.timezone}')
except Airport.DoesNotExist:
print(f' - - {airport_Dict["iata"]} не найден в БД > добавляем')
except Exception as e:
print(f'error = {str(e)}')
if not airport:
geo_lat = float(airport_Dict['@lat'])
geo_lon = float(airport_Dict['@lon'])
tz = tzf.timezone_at(lng=geo_lon, lat=geo_lat)
print(f'airport {airport_Dict["int_name"]} - {tz}')
airport_kwargs = {
'city': city,
# 'name_ru': airport_Dict['name:ru'],
# 'name_en': airport_Dict['name:en'],
'timezone': tz,
'geo_lat': str(airport_Dict['@lat']),
'geo_lon': str(airport_Dict['@lon']),
'geo_lat': str(geo_lat),
'geo_lon': str(geo_lon),
'international_name': airport_Dict['int_name'],
'iata_code': airport_Dict['iata'],
'icao_code': airport_Dict['icao'],
'modifiedDT': datetime.now(),
}
if airport_Dict['name:ru']:
@@ -119,7 +154,10 @@ def parse_data():
country = Country.objects.get(**kwargs)
if country.parsing_finished_DT and (datetime.now() - country.parsing_finished_DT).days < 30:
if (country.parsing_finished_DT
and (datetime.now() - country.parsing_finished_DT).days < 30
and country.timezone
):
print(f' + {country.name} - существует в БД, не требует парсинга')
continue
@@ -194,6 +232,12 @@ def parse_data():
else:
print(f'error = {str(e)}')
geo_lat = float(city_Dict['@lat'])
geo_lon = float(city_Dict['@lon'])
tz = tzf.timezone_at(lng=geo_lon, lat=geo_lat)
if not city or not city.timezone:
print(f'city {city_Dict["name:en"]} - {tz}')
# собираем данные
city_kwargs = {
'country': country,
@@ -201,8 +245,11 @@ def parse_data():
# 'name_ru': city_Dict['name:ru'],
# 'name_en': city_Dict['name:en'],
'geo_lat': str(city_Dict['@lat']),
'geo_lon': str(city_Dict['@lon']),
'timezone': tz,
'geo_lat': str(geo_lat),
'geo_lon': str(geo_lon),
}
if city_Dict['name:ru']:
@@ -232,8 +279,12 @@ def parse_data():
hash_data = hashlib.md5(json.dumps(country_Dict, sort_keys=True, ensure_ascii=True).encode('utf-8')).hexdigest()
country.add_node_to_json_data({'hash': hash_data})
if not country.timezone:
country.timezone = tzf.timezone_at(lng=float(country.geo_lon), lat=float(country.geo_lat))
print(f'country {country.name} - {country.timezone}')
if 'parsing_status' in country_Dict and country_Dict['parsing_status'] == 'finished':
country.parsing_finished_DT = datetime.now()
country.save(update_fields=['parsing_finished_DT'])
country.save()
return True

View File

@@ -13,7 +13,8 @@ from django.template.loader import render_to_string
from django.urls import reverse
from django.db.models import Q
import json
from GeneralApp.funcs import get_inter_http_respose
from GeneralApp.funcs import get_inter_http_response
from GeneralApp.funcs import get_and_set_lang
def get_address_point_ajax(request):
from .funcs import search_cities_in_db, search_airports_in_db
@@ -21,6 +22,9 @@ def get_address_point_ajax(request):
if request.method != 'POST':
raise Http404
lang = get_and_set_lang(request)
try:
data = json.loads(request.body)
@@ -52,10 +56,12 @@ def get_address_point_ajax(request):
item['fullname'] = f'{item["iata_code"]} - {item["name"]}'
item['city_name'] = item['city__name']
item['country_name'] = item['city__country__name']
item['city_DT'] = datetime.now(tz=pytz.timezone(item['city__timezone']))
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"]}'
item['city_DT'] = datetime.now(tz=pytz.timezone(item['timezone']))
html = f"{html}{render_to_string('widgets/w_ac_input_address_point.html', item)}"
i += 1
@@ -64,6 +70,8 @@ def get_address_point_ajax(request):
'res_search_list': html
}
from GeneralApp.funcs import get_add_to_ajax_response_Dict
res_Dict.update(get_add_to_ajax_response_Dict(request.user))
return JsonResponse(res_Dict)
except Exception as e:

View File

@@ -0,0 +1,28 @@
# Generated by Django 4.2.2 on 2024-07-12 17:23
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('ReferenceDataApp', '0005_remove_airport_parsing_finished_and_more'),
]
operations = [
migrations.AddField(
model_name='airport',
name='timezone',
field=models.CharField(blank=True, max_length=250, null=True, verbose_name='Часовая зона'),
),
migrations.AddField(
model_name='city',
name='timezone',
field=models.CharField(blank=True, max_length=250, null=True, verbose_name='Часовая зона'),
),
migrations.AddField(
model_name='country',
name='timezone',
field=models.CharField(blank=True, max_length=250, null=True, verbose_name='Часовая зона'),
),
]

View File

@@ -1,6 +1,8 @@
import pytz
from django.db import models
from BaseModels.base_models import BaseModel
from django.utils.translation import gettext_lazy as _
from datetime import datetime
class Country(BaseModel):
international_name = models.CharField(max_length=250, verbose_name=_('Международное название'), blank=True, null=True)
@@ -15,6 +17,8 @@ class Country(BaseModel):
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)
timezone = models.CharField(max_length=250, verbose_name=_('Часовая зона'), blank=True, null=True)
area_id = models.BigIntegerField(blank=True, null=True)
parsing_finished_DT = models.DateTimeField(verbose_name=_('Дата и время завершения парсинга'), blank=True, null=True)
@@ -46,6 +50,8 @@ class City(BaseModel):
area_id = models.BigIntegerField(blank=True, null=True)
timezone = models.CharField(max_length=250, verbose_name=_('Часовая зона'), blank=True, null=True)
parsing_finished_DT = models.DateTimeField(verbose_name=_('Дата и время завершения парсинга'), blank=True, null=True)
def __str__(self):
@@ -54,6 +60,17 @@ class City(BaseModel):
else:
return f'{self.id}'
def get_n_save_timezone(self):
from ReferenceDataApp.funcs import tzf
self.timezone = tzf.timezone_at(lng=float(self.geo_lon), lat=float(self.geo_lat))
self.save(update_fields=['timezone'])
return self.timezone
def get_current_datetime(self):
if not self.timezone:
self.timezone = self.get_n_save_timezone()
return datetime.now(tz=pytz.timezone(self.timezone))
def get_country_n_city_str(self):
country = _('Неизвестно')
city = self.name
@@ -83,6 +100,8 @@ class Airport(BaseModel):
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)
timezone = models.CharField(max_length=250, verbose_name=_('Часовая зона'), blank=True, null=True)
area_id = models.BigIntegerField(blank=True, null=True)
parsing_finished_DT = models.DateTimeField(verbose_name=_('Дата и время завершения парсинга'), blank=True, null=True)

View File

@@ -3,16 +3,33 @@ from .models import *
from django.contrib import admin
class Admin_Route(Admin_Trans_BaseModel):
readonly_fields = [
# 'highlight_end_DT',
'rising_DT'
]
list_display = [
'id', 'owner_type', 'type_transport', 'cargo_type',
'id', 'owner_type',
'rising_DT',
'receive_msg_by_email', 'type_transport', 'cargo_type',
'departure_DT', 'from_city', 'from_place',
'arrival_DT', 'to_city', 'to_place', 'owner',
'order', 'modifiedDT', 'createDT'
]
list_editable = ['rising_DT']
list_display_links = ['id']
list_filter = ['owner_type', 'type_transport', 'cargo_type', 'from_place', 'arrival_DT', 'modifiedDT', 'createDT']
search_fields = ['owner__first_name', 'owner__last_name']
list_filter = [
'owner_type', 'type_transport',
'rising_DT',
'cargo_type',
'from_place', 'arrival_DT',
'modifiedDT', 'createDT'
]
admin.site.register(Route,Admin_Route)
search_fields = [
'owner__first_name', 'owner__last_name', 'from_city__name', 'to_city__name', 'owner__email'
]
raw_id_fields = ['from_city', 'to_city', 'owner']
admin.site.register(Route, Admin_Route)

View File

@@ -6,9 +6,53 @@ 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)
departure_DT = forms.DateTimeField(required=True, input_formats=['%d.%m.%Y %H:%M'])
arrival_DT = forms.DateTimeField(required=True, input_formats=['%d.%m.%Y %H:%M'])
class Meta:
model = Route
exclude = [
@@ -20,10 +64,24 @@ class RouteForm(forms.ModelForm):
# print('check')
cleaned_data = super(RouteForm, self).clean()
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

@@ -1,18 +1,28 @@
from BaseModels.mailSender import techSendMail
from GeneralApp.funcs_options import get_mail_send_options
from .models import *
from .forms import *
from django.utils.translation import gettext as _
from django.template.loader import render_to_string
from datetime import datetime
from datetime import datetime, timedelta
from django.db.models import F, Q
elements_on_page = 25
def get_profile_new_route_page_html(request, data):
form = RouteForm()
Dict = {
'form': form
}
try:
errors_off = True
@@ -27,59 +37,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)}'})
@@ -89,9 +111,9 @@ def get_profile_new_route_page_html(request, data):
return html
def get_country_n_city_str_by_type_transport_and_address_point(type_transport, address_point):
city = get_city_by_type_transport_and_address_point(type_transport, address_point)
return city.get_country_n_city_str()
# def get_country_n_city_str_by_type_transport_and_address_point(type_transport, address_point):
# city = get_city_by_type_transport_and_address_point(type_transport, address_point)
# return city.get_country_n_city_str()
def get_city_by_type_transport_and_address_point(type_transport, address_point):
@@ -107,6 +129,16 @@ def get_city_by_type_transport_and_address_point(type_transport, address_point):
print(msg)
return None
def get_city_by_address_point(address_point):
from ReferenceDataApp.models import Airport, City
try:
return City.objects.get(id=address_point)
except Exception as e:
msg = f'get_city_by_address_point Error = {str(e)}, address_point = {address_point}'
print(msg)
return None
def get_profile_my_routes_page_content_html(request):
routes_Dict = get_routes_Dict(request.user)
@@ -115,6 +147,11 @@ def get_profile_my_routes_page_content_html(request):
print(msg)
return msg
from SubscribesApp.funcs import get_cur_user_subscribe
user_subscribe = get_cur_user_subscribe(request.user)
if user_subscribe:
routes_Dict.update(user_subscribe.remains_route_adding_options())
html = render_to_string('blocks/profile/b_my_routes.html', routes_Dict, request=request)
return html
@@ -135,24 +172,38 @@ def get_routes_Dict(user=None, data=None):
'owner': user
})
from_el = None
to_el = 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 (
@@ -171,20 +222,22 @@ def get_routes_Dict(user=None, data=None):
):
kwargs.update({key: val})
if key == 'from_address_point':
kwargs.update({f'from_city__id': val})
if key == 'from_address_point': # в from_address_point всегда город
# city = get_city_by_type_transport_and_address_point(type_transport, val)
city = get_city_by_address_point(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})
if key == 'to_address_point': # в to_address_point всегда город
# city = get_city_by_type_transport_and_address_point(type_transport, val)
city = get_city_by_address_point(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':
@@ -192,9 +245,41 @@ 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')
# rising_routes = Route.objects.filter(
# **kwargs,
# ).exclude(
# rising_DT=None
# ).order_by(
# '-rising_DT', '-departure_DT', '-arrival_DT', '-modifiedDT'
# )
# routes = Route.objects.exclude(
# rising_DT=None
# ).filter(
# departure_DT__lt=datetime.now()
# )
# routes.update(
# rising_DT=None
# )
routes_rising_off = Route.objects.exclude(rising_DT=None).filter(
Q(rising_DT__lt=datetime.now() - timedelta(days=1)) | Q(departure_DT__lt=datetime.now())
)
if routes_rising_off:
routes_rising_off.update(rising_DT=None)
routes = Route.objects.filter(
**kwargs
).order_by(
F('rising_DT').desc(nulls_last=True),
# '-rising_DT',
'-departure_DT', '-arrival_DT', '-modifiedDT'
)
routes_count = routes.count()
if from_el and to_el:
routes = routes[from_el:to_el]
elif from_el:

View File

@@ -4,6 +4,8 @@ from django.urls import path
# from AuthApp.import_funcs import *
from .js_views import *
# /routes/
urlpatterns = [
path('change_route/<int:route_id>/', create_or_change_route_ajax, name='change_route_ajax'),
path('create_or_change_route/', create_or_change_route_ajax, name='create_or_change_route_ajax'),
@@ -14,4 +16,7 @@ urlpatterns = [
path('get_routes/', get_my_routes_ajax, name='get_my_routes_ajax'),
path('find_routes/', find_routes_ajax, name='find_routes_ajax'),
path('raise_route/', raise_route_ajax, name='raise_route_ajax'),
path('highlight_route/', highlight_route_ajax, name='highlight_route_ajax'),
]

View File

@@ -1,4 +1,5 @@
import json
from copy import deepcopy
from django.shortcuts import render
@@ -10,17 +11,114 @@ from django.template import loader, RequestContext
from django.contrib.auth.decorators import login_required
from BaseModels.mailSender import techSendMail
from django.utils.translation import gettext as _
from datetime import datetime
from datetime import datetime, timedelta
from django.template.loader import render_to_string
from django.urls import reverse
from .forms import *
from .funcs import *
from GeneralApp.funcs import get_and_set_lang
from SubscribesApp.funcs import check_option_in_cur_user_subscribe
def highlight_route_ajax(request):
if request.method != 'POST':
raise Http404
data = request.POST
if not data and request.body:
data = json.loads(request.body)
if not data or not 'route_id' in data:
msg = _('Недостаточно данных')
return JsonResponse({'errors': msg})
try:
route = Route.objects.get(owner=request.user, id=data['route_id'])
except Route.DoesNotExist:
msg = _('Не найден маршрут')
return JsonResponse({'errors': msg})
if not route.get_permission_for_highlight():
msg = _('Нет доступа к выделению')
return JsonResponse({'errors': msg})
from SubscribesApp.funcs import get_cur_user_subscribe
user_subscribe = get_cur_user_subscribe(request.user)
user_subscribe.used_route_highlight_count += 1
user_subscribe.save(update_fields=['used_route_highlight_count'])
route.highlight_color = '#FF0000'
highlight_hours = user_subscribe.get_highlight_hours()
route.highlight_end_DT = datetime.now() + timedelta(hours=highlight_hours)
route.save(update_fields=['highlight_color', 'highlight_end_DT'])
Dict = {
'route': route,
}
html = render_to_string('widgets/routes/w_my_route.html', Dict, request=request)
res_Dict = {
'html': html
}
res_Dict.update(user_subscribe.remains_route_adding_options())
from GeneralApp.funcs import get_add_to_ajax_response_Dict
res_Dict.update(get_add_to_ajax_response_Dict(request.user))
return JsonResponse(res_Dict)
def raise_route_ajax(request):
if request.method != 'POST':
raise Http404
data = request.POST
if not data and request.body:
data = json.loads(request.body)
if not data or not 'route_id' in data:
msg = _('Недостаточно данных')
return JsonResponse({'errors': msg})
try:
route = Route.objects.get(owner=request.user, id=data['route_id'])
except Route.DoesNotExist:
msg = _('Не найден маршрут')
return JsonResponse({'errors': msg})
if not route.get_permission_for_raise():
msg = _('Нет доступных поднятий')
return JsonResponse({'errors': msg})
route.rising_DT = datetime.now()
route.save(update_fields=['rising_DT'])
from SubscribesApp.funcs import get_cur_user_subscribe
user_subscribe = get_cur_user_subscribe(request.user)
user_subscribe.used_route_rising_count += 1
user_subscribe.save(update_fields=['used_route_rising_count'])
res_Dict = {'status': 'ok'}
res_Dict.update(user_subscribe.remains_route_adding_options())
from GeneralApp.funcs import get_add_to_ajax_response_Dict
res_Dict.update(get_add_to_ajax_response_Dict(request.user))
return JsonResponse(res_Dict)
def del_route_ajax(request):
if request.method != 'POST':
raise Http404
if not check_option_in_cur_user_subscribe(request.user, 'размещение заявок'):
return JsonResponse({'html': 'нет доступа'}, status=403)
lang = get_and_set_lang(request)
try:
data = json.loads(request.body)
@@ -40,6 +138,8 @@ def del_route_ajax(request):
'html': html
}
from GeneralApp.funcs import get_add_to_ajax_response_Dict
res_Dict.update(get_add_to_ajax_response_Dict(request.user))
return JsonResponse(res_Dict)
except Exception as e:
@@ -54,6 +154,11 @@ def edit_route_ajax(request):
if request.method != 'POST':
raise Http404
if not check_option_in_cur_user_subscribe(request.user, 'размещение заявок'):
return JsonResponse({'html': 'нет доступа'}, status=403)
lang = get_and_set_lang(request)
data = json.loads(request.body)
Dict = {}
@@ -67,6 +172,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'],
@@ -86,7 +193,13 @@ def edit_route_ajax(request):
return JsonResponse({'errors': msg})
html = render_to_string('blocks/profile/b_new_route.html', Dict, request=request)
return JsonResponse({'html': html}, status=200)
res_Dict = {
'html': html,
'btn_title': _('Сохранить изменения')
}
from GeneralApp.funcs import get_add_to_ajax_response_Dict
res_Dict.update(get_add_to_ajax_response_Dict(request.user))
return JsonResponse(res_Dict)
@@ -96,6 +209,10 @@ def edit_route_ajax(request):
def new_route_view_ajax(request):
if request.method != 'POST':
raise Http404
if not check_option_in_cur_user_subscribe(request.user, 'размещение заявок'):
return JsonResponse({'html': 'нет доступа'}, status=403)
lang = get_and_set_lang(request)
# form = RouteForm()
# Dict = {
@@ -121,7 +238,10 @@ def new_route_view_ajax(request):
# html = render_to_string('blocks/profile/b_new_route.html', Dict, request=request)
return JsonResponse({'html': html}, status=200)
res_Dict = {'html': html}
from GeneralApp.funcs import get_add_to_ajax_response_Dict
res_Dict.update(get_add_to_ajax_response_Dict(request.user))
return JsonResponse(res_Dict)
def find_routes_ajax(request):
@@ -130,6 +250,8 @@ def find_routes_ajax(request):
if request.method != 'POST':
raise Http404
lang = get_and_set_lang(request)
try:
@@ -144,7 +266,10 @@ def find_routes_ajax(request):
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,
@@ -153,6 +278,8 @@ def find_routes_ajax(request):
# 'form': RouteForm(initial=data)
}
from GeneralApp.funcs import get_add_to_ajax_response_Dict
res_Dict.update(get_add_to_ajax_response_Dict(request.user))
return JsonResponse(res_Dict)
except Exception as e:
@@ -171,11 +298,30 @@ def get_my_routes_ajax(request):
if request.method != 'POST':
raise Http404
lang = get_and_set_lang(request)
data = request.POST.dict()
if not data and request.body:
data = json.loads(request.body)
try:
routes_Dict = get_routes_Dict(request.user)
if not request.user or request.user.is_anonymous:
msg = (f'get_my_routes_ajax not have user - user={str(request.user)}<br>'
f'data={str(data)}<br>'
f'request={str(request)}')
mail_sets = get_mail_send_options()
techSendMail(mail_sets, msg)
routes_Dict = get_routes_Dict(request.user, data)
if 'errors' in routes_Dict:
return JsonResponse(routes_Dict, status=400)
from SubscribesApp.funcs import get_cur_user_subscribe
user_subscribe = get_cur_user_subscribe(request.user)
if user_subscribe:
routes_Dict.update(user_subscribe.remains_route_adding_options())
html = render_to_string('blocks/profile/b_my_routes.html', routes_Dict, request=request)
@@ -183,6 +329,8 @@ def get_my_routes_ajax(request):
'html': html
}
from GeneralApp.funcs import get_add_to_ajax_response_Dict
res_Dict.update(get_add_to_ajax_response_Dict(request.user))
return JsonResponse(res_Dict)
except Exception as e:
@@ -202,7 +350,13 @@ def create_or_change_route_ajax(request, route_id=None):
if request.method != 'POST':
raise Http404
if not check_option_in_cur_user_subscribe(request.user, 'размещение заявок'):
return JsonResponse({'html': 'нет доступа'}, status=403)
lang = get_and_set_lang(request)
Dict = {}
route_old_Dict = None
try:
@@ -217,6 +371,7 @@ def create_or_change_route_ajax(request, route_id=None):
if route:
form = RouteForm(data, instance=route)
Dict.update({'route': route})
route_old_Dict = deepcopy(route.__dict__)
else:
form = RouteForm(data)
@@ -228,7 +383,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:
@@ -237,11 +392,28 @@ def create_or_change_route_ajax(request, route_id=None):
if obj.to_address_point:
obj.to_city = get_city_by_type_transport_and_address_point(obj.type_transport, obj.to_address_point)
if route_old_Dict:
if route_old_Dict['highlight_color'] != obj.highlight_color:
obj.highlight_color = route_old_Dict['highlight_color']
if route_old_Dict['highlight_end_DT'] != obj.highlight_end_DT:
obj.highlight_end_DT = route_old_Dict['highlight_end_DT']
if route_old_Dict['rising_DT'] != obj.rising_DT:
obj.rising_DT = route_old_Dict['rising_DT']
obj.owner = request.user
obj.save()
route_id = obj.id
routes_Dict = get_routes_Dict(request.user)
from SubscribesApp.funcs import get_cur_user_subscribe
user_subscribe = get_cur_user_subscribe(request.user)
if user_subscribe:
routes_Dict.update(user_subscribe.remains_route_adding_options())
if 'errors' in routes_Dict:
form.errors.update(routes_Dict['errors'])
Dict.update({'form': form})
@@ -255,6 +427,8 @@ def create_or_change_route_ajax(request, route_id=None):
'route_id': route_id
}
from GeneralApp.funcs import get_add_to_ajax_response_Dict
res_Dict.update(get_add_to_ajax_response_Dict(request.user))
return JsonResponse(res_Dict)
except Exception as e:

View File

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

@@ -0,0 +1,34 @@
# Generated by Django 4.2.2 on 2024-06-03 01:31
import colorfield.fields
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('RoutesApp', '0005_route_from_city_route_to_city'),
]
operations = [
migrations.AddField(
model_name='route',
name='rising_DT',
field=models.DateTimeField(blank=True, null=True, verbose_name='Дата и время последнего поднятия'),
),
migrations.AddField(
model_name='route',
name='select_color',
field=colorfield.fields.ColorField(blank=True, default=None, image_field=None, max_length=25, null=True, samples=None, verbose_name='Цвет выделения'),
),
migrations.AlterField(
model_name='route',
name='arrival_DT',
field=models.DateTimeField(verbose_name='Дата и время прибытия'),
),
migrations.AlterField(
model_name='route',
name='departure_DT',
field=models.DateTimeField(verbose_name='Дата и время выезда'),
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 4.2.2 on 2024-06-03 02:30
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('RoutesApp', '0006_route_rising_dt_route_select_color_and_more'),
]
operations = [
migrations.RenameField(
model_name='route',
old_name='select_color',
new_name='highlight_color',
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 4.2.2 on 2024-08-13 13:28
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('RoutesApp', '0007_rename_select_color_route_highlight_color'),
]
operations = [
migrations.AddField(
model_name='route',
name='highlight_end_DT',
field=models.DateTimeField(blank=True, null=True, verbose_name='Дата и время окончания выделения'),
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 4.2.2 on 2024-11-12 10:51
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('RoutesApp', '0008_route_highlight_end_dt'),
]
operations = [
migrations.AlterField(
model_name='route',
name='phone',
field=models.CharField(blank=True, null=True, verbose_name='Укажите номер для связи'),
),
]

View File

@@ -1,6 +1,7 @@
from django.db import models
from django.utils.translation import gettext_lazy as _
from BaseModels.base_models import BaseModel
from colorfield.fields import ColorField
type_transport_choices = [
@@ -38,8 +39,8 @@ class Route(BaseModel):
type_transport = models.CharField(
choices=type_transport_choices, default='', verbose_name=_('Выберите способ перевозки'))
departure_DT = models.DateTimeField(default=True, verbose_name=_('Дата и время выезда'))
arrival_DT = models.DateTimeField(default=True, verbose_name=_('Дата и время прибытия'))
departure_DT = models.DateTimeField(verbose_name=_('Дата и время выезда'))
arrival_DT = models.DateTimeField(verbose_name=_('Дата и время прибытия'))
from_address_point = models.IntegerField(verbose_name=_('Пункт выезда'))
to_address_point = models.IntegerField(verbose_name=_('Пункт приезда'))
from_city = models.ForeignKey(
@@ -56,12 +57,25 @@ class Route(BaseModel):
verbose_name=_('Куда можете доставить?'))
cargo_type = models.CharField(choices=cargo_type_choices, default='parcel', verbose_name=_('Могу перевезти'))
weight = models.IntegerField(verbose_name=_('Укажите вес до (кг)'))
phone = models.CharField(verbose_name=_('Укажите номер для связи'))
phone = models.CharField(verbose_name=_('Укажите номер для связи'), blank=True, null=True)
extra_phone = models.CharField(verbose_name=_('Дополнительный номер'), blank=True, null=True)
receive_msg_by_email = models.BooleanField(default=False, verbose_name=_('Получать уведомления по E-mail'))
receive_msg_by_sms = models.BooleanField(default=False, verbose_name=_('Получать уведомления по SMS'))
owner = models.ForeignKey(User, verbose_name=_('Владелец'), related_name='rel_routes_for_owner', on_delete=models.CASCADE)
rising_DT = models.DateTimeField(
verbose_name=_('Дата и время последнего поднятия'),
blank=True, null=True
)
highlight_color = ColorField(
verbose_name=_('Цвет выделения'),
blank=True, null=True
)
highlight_end_DT = models.DateTimeField(
verbose_name=_('Дата и время окончания выделения'),
blank=True, null=True
)
def __str__(self):
if self.name:
return f'{self.name}'
@@ -74,15 +88,38 @@ class Route(BaseModel):
verbose_name_plural = _(u'Маршруты')
ordering = ('name',)
def get_permission_for_raise(self):
from SubscribesApp.funcs import get_cur_user_subscribe
user_subscribe = get_cur_user_subscribe(self.owner)
if not user_subscribe:
return False
data_Dict = user_subscribe.remains_route_adding_options()
if data_Dict['remains_route_rising_count'] > 0:
return True
return False
def get_permission_for_highlight(self):
from SubscribesApp.funcs import get_cur_user_subscribe
user_subscribe = get_cur_user_subscribe(self.owner)
if not user_subscribe:
return False
data_Dict = user_subscribe.remains_route_adding_options()
if data_Dict['remains_route_highlight_count'] > 0:
return True
return False
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 +148,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],

214
RoutesApp/search_matches.py Normal file
View File

@@ -0,0 +1,214 @@
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
from SubscribesApp.funcs import check_option_in_cur_user_subscribe
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
if not check_option_in_cur_user_subscribe(route.owner, 'push уведомления'):
return False
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, matched_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]
subject = _('Мы нашли исполнителя по Вашему объявлению!')
res = admin_send_mail_by_SMTPlib(
mail_sets,
subject=subject,
from_email=mail_sets['sender_email'], to=to,
html_content=html
)
subject = f'route matches {route.id} <> {matched_route.id} send to {route.owner.email}'
to = ['web@syncsystems.net', 'sa@a3-global.com']
res = admin_send_mail_by_SMTPlib(
mail_sets,
subject=subject,
from_email=mail_sets['sender_email'], to=to,
html_content=html
)
return res
def user_notify_by_result_search_matches(route_for_send, founded_route, params):
log = ''
data_Dict = None
try:
data_Dict = get_Dict_for_send_msgs(params, founded_route.owner_type)
except Exception as e:
msg = f'<br>\n! search_matches Error get_Dict_for_send_msgs = {str(e)}'
print(msg)
log += msg
if data_Dict and check_option_in_cur_user_subscribe(
route_for_send.owner, 'push уведомления'
):
try:
msg = send_push_message_for_found_matches_routes(route_for_send, data_Dict)
if msg:
log += msg
except Exception as e:
msg = f'<br>\n! search_matches Error send_push_message_for_found_matches_routes = {str(e)}'
print(msg)
log += msg
if data_Dict and check_option_in_cur_user_subscribe(
route_for_send.owner,
'уведомление на e-mail о появлении перевозчика по заданным критериям'
):
try:
msg = send_mail_found_matches_routes(route_for_send, founded_route, data_Dict)
if msg:
log += msg
except Exception as e:
msg = f'<br>\n! search_matches Error send_mail_found_matches_routes = {str(e)}'
print(msg)
log += msg
return log
def users_notify_by_result_search_matches(source_route, found_routes, params):
log = ''
log += user_notify_by_result_search_matches(source_route, found_routes[0], params)
for route in found_routes:
log += user_notify_by_result_search_matches(route, source_route, params)
return log
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',
'from_city', 'to_city',
]
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)
if route.owner_type == 'mover':
# params.update({f"{field_name}__lte": field_val})
kwargs.update({f"{field_name}__lte": field_val})
else:
# params.update({f"{field_name}__gte": field_val})
kwargs.update({f"{field_name}__gte": field_val})
elif field_name == 'from_city':
params.update({'from_address_point': field_val.id})
kwargs.update({field_name: field_val})
elif field_name == 'to_city':
params.update({'to_address_point': field_val.id})
kwargs.update({field_name: field_val})
# elif field_name in ['from_address_point', 'to_address_point']:
# kwargs.update({field_name: 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()}'
print(msg)
log += users_notify_by_result_search_matches(route, found_routes, params)
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

@@ -11,7 +11,7 @@ from django.utils.translation import gettext as _
from datetime import datetime
from .funcs import *
from .forms import *
from GeneralApp.funcs import get_inter_http_respose
from GeneralApp.funcs import get_inter_http_response
@@ -19,42 +19,48 @@ from GeneralApp.funcs import get_inter_http_respose
def route_search_results_View(request):
Dict = {}
data = None
data = {}
if request.GET:
data = request.GET.dict()
try:
routes_Dict = get_routes_Dict(data=data)
if routes_Dict:
Dict = {
'routes': routes_Dict['routes'],
'last_block': routes_Dict['last_block'],
'show_filter_and_results': True,
'owner_type': data['owner_type'],
'last_el': routes_Dict['last_el'],
'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']})
if 'to_address_point_txt' in routes_Dict:
data.update({'to_address_point_txt': routes_Dict['to_address_point_txt']})
Dict.update({'route_form': RouteForm(initial=data)})
if request.GET:
data = request.GET.dict()
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"]}'
routes_Dict = get_routes_Dict(data=data)
if routes_Dict:
Dict = {
'routes': routes_Dict['routes'],
'last_block': routes_Dict['last_block'],
'show_filter_and_results': True,
'owner_type': data['owner_type'],
'last_el': routes_Dict['last_el'],
'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']})
if 'to_address_point_txt' in routes_Dict:
data.update({'to_address_point_txt': routes_Dict['to_address_point_txt']})
Dict.update({'route_form': RouteForm(initial=data)})
Dict.update({
'page': {
'title': title,
'description': title,
'keywords': title,
}
})
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"]}'
t = loader.get_template('pages/p_results_find_route.html')
return get_inter_http_respose(t, Dict, request)
# return HttpResponse(t.render(Dict, request))
Dict.update({
'page': {
'title': title,
'description': title,
'keywords': title,
}
})
t = loader.get_template('pages/p_results_find_route.html')
return get_inter_http_response(t, Dict, request)
except Exception as e:
msg = f'!!! --- route_search_results_View Exception {str(e)}'
print(msg)
raise Http404

0
SitemapApp/__init__.py Normal file
View File

3
SitemapApp/models.py Normal file
View File

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

16
SitemapApp/tests.py Normal file
View File

@@ -0,0 +1,16 @@
"""
This file demonstrates writing tests using the unittest module. These will pass
when you run "manage.py test".
Replace this with more appropriate tests for your application.
"""
from django.test import TestCase
class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.
"""
self.assertEqual(1 + 1, 2)

11
SitemapApp/urls.py Normal file
View File

@@ -0,0 +1,11 @@
from django.urls import include, path
from django.contrib.sitemaps import views as sitemaps_views
from django.views.decorators.cache import cache_page
from django.contrib.sitemaps.views import sitemap
from SitemapApp.views import sitemaps
urlpatterns = [
path('sitemap.xml', sitemap, {'sitemaps': sitemaps},
name='django.contrib.sitemaps.views.sitemap')
]

149
SitemapApp/views.py Normal file
View File

@@ -0,0 +1,149 @@
# coding=utf-8
from django.contrib.sitemaps import Sitemap
from django.urls import reverse
from BaseModels.mailSender import techSendMail
import json
from datetime import datetime, time, timezone
# from PageSetsApp.models import *
# from ArticlesApp.models import *
# from BaseModels.base_api_requests import base_api_request
# from tEsiteProj.settings import API_URL
from django.db.models import Q
limit_records = 1000
sitemaps = {
}
protocol = 'https'
class sm_StaticPage(Sitemap):
changefreq = 'monthly'
priority = 1
i18n = True
protocol = protocol
def items(self):
from GeneralApp.models import StaticPage
return StaticPage.objects.filter(enable=True)
def location(self, item):
if item.url == 'main':
return reverse('main')
else:
return reverse('static_page', args=[item.url])
def lastmod(self, obj):
return obj.modifiedDT
sitemaps.update({'static_pages': sm_StaticPage})
class sm_ArticlesPage(Sitemap):
changefreq = 'daily'
priority = 2
i18n = True
protocol = protocol
def items(self):
return ['']
def location(self, item):
return reverse('articles')
def lastmod(self, obj):
from ArticlesApp.models import ArticleModel
article = ArticleModel.objects.filter(enable=True).order_by('-modifiedDT').first()
if article:
return article.modifiedDT
else:
return datetime.now()
sitemaps.update({'articles_page': sm_ArticlesPage})
class sm_Article(Sitemap):
changefreq = 'yearly'
priority = 2
i18n = True
protocol = protocol
def items(self):
from ArticlesApp.views import ArticleModel
objs = ArticleModel.objects.filter(enable=True)
return objs
def location(self, item):
return reverse('article_one', args=[item.url])
def lastmod(self, obj):
return obj.modifiedDT
sitemaps.update({'article': sm_Article})
class sm_UserPage(Sitemap):
changefreq = 'yearly'
priority = 2
i18n = True
protocol = protocol
def items(self):
from ArticlesApp.views import UserPageModel
objs = UserPageModel.objects.filter(enable=True)
return objs
def location(self, item):
return reverse('user_page', args=[item.url])
def lastmod(self, obj):
return obj.modifiedDT
sitemaps.update({'user_page': sm_UserPage})
class sm_Registration(Sitemap):
changefreq = 'never'
priority = 1
i18n = True
protocol = protocol
def items(self):
return ['']
def location(self, item):
return reverse('registration_page')
def lastmod(self, obj):
return datetime(2024, 6, 1)
sitemaps.update({'registration': sm_Registration})
class sm_Login(Sitemap):
changefreq = 'never'
priority = 1
i18n = True
protocol = protocol
def items(self):
return ['']
def location(self, item):
return reverse('login_profile')
def lastmod(self, obj):
return datetime(2024, 6, 1)
sitemaps.update({'login': sm_Login})

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,27 @@ class Admin_SubscribeOption(Admin_Trans_BaseModel):
(None, {
'classes': ['wide'],
'fields': ('name',
'order'
'order',
'enable'
)
}),
(None, {
'classes': ['wide'],
'fields': (
('allow_route_rising_count',),
('allow_route_highlight_count', 'route_highlight_hours'),
)
}),
)
list_display = [
'id',
'id', 'enable',
'name',
'allow_route_rising_count',
'allow_route_highlight_count', 'route_highlight_hours',
'order', 'modifiedDT', 'createDT'
]
list_editable = ['enable']
list_display_links = ['id']
@@ -60,7 +72,7 @@ class Admin_SubscribeForUser(Admin_Trans_BaseModel):
fieldsets = (
(None, {
'classes': ['wide'],
'fields': ('name',
'fields': ('enable',
'user', 'subscribe',
'last_paid_DT',
'paid_period_from_DT', 'paid_period_to_DT',
@@ -71,8 +83,9 @@ class Admin_SubscribeForUser(Admin_Trans_BaseModel):
)
list_display = [
'id',
'id', 'enable',
'name', 'user', 'subscribe',
'used_route_rising_count', 'used_route_highlight_count',
'last_paid_DT', 'paid_period_from_DT', 'paid_period_to_DT',
'auto_continue', 'receive_finish_subscribe_msg',
'order', 'modifiedDT', 'createDT'
@@ -85,6 +98,7 @@ class Admin_SubscribeForUser(Admin_Trans_BaseModel):
'auto_continue', 'receive_finish_subscribe_msg',
'modifiedDT', 'createDT'
]
search_fields = ['name']
list_editable = ['enable']
search_fields = ['name', 'id', 'user__email', 'user__first_name', 'user__last_name']
admin.site.register(SubscribeForUser,Admin_SubscribeForUser)

View File

@@ -1,41 +1,197 @@
from .models import *
from django.template.loader import render_to_string
from django.utils.translation import get_language, activate
from datetime import datetime, timedelta
import json
def get_user_subscribes_that_is_going_to_finish():
user_subscribes = SubscribeForUser.objects.filter(
enable=True,
subscribe__price__gt=0,
paid_period_to_DT__lt=datetime.now() + timedelta(days=3),
paid_period_to_DT__gt=datetime.now()
)
return user_subscribes
def extension_free_subscribes():
subscribe = get_null_price_subscribe()
if not subscribe:
return None
user_subscribes = SubscribeForUser.objects.filter(
enable=True,
subscribe=subscribe
)
for user_subscribe in user_subscribes:
user_subscribe.extension()
msg = f'{str(user_subscribe)} free subscribe extended'
print(msg)
return True
def finish_user_subscribes():
finished_user_subscribes = SubscribeForUser.objects.filter(
enable=True, paid_period_to_DT__lt=datetime.now()
)
finished_user_subscribes.update(enable=False)
for finished_user_subscribe in finished_user_subscribes:
msg = f'{str(finished_user_subscribe)} subscribe finished and switch to free'
print(msg)
subscribe_user_to_null_price_subscribe(finished_user_subscribe.user)
return True
def create_subscribe_by_data(create_kwargs):
subscribe = create_kwargs['subscribe']
create_kwargs.update({
'paid_period_from_DT': datetime.now(),
'paid_period_to_DT': datetime.now() + timedelta(hours=subscribe.period),
'enable': False
})
subscribe_for_user = SubscribeForUser.objects.create(**create_kwargs)
return subscribe_for_user
def check_option_in_cur_user_subscribe(user, option_name):
if not user or not user.is_active or not user.is_authenticated:
return False
user_subscribe = get_cur_user_subscribe(user)
try:
option = SubscribeOption.objects.get(
rel_subscribes_for_option=user_subscribe.subscribe,
name_ru__iexact=option_name
)
return True
except SubscribeOption.DoesNotExist:
return False
def get_null_price_subscribe():
subscribes_null_price = Subscribe.objects.filter(
enable=True,
price=0
)
if subscribes_null_price:
return subscribes_null_price[0]
return None
def subscribe_user_to_null_price_subscribe(user):
subscribe = get_null_price_subscribe()
if not subscribe:
return None
kwargs = {
'user': user,
'subscribe': subscribe,
}
subscribe_for_user = create_subscribe_by_data(kwargs)
subscribe_for_user = subscribe_for_user.activate()
return subscribe_for_user
def get_cur_user_subscribe(user):
user_subscribe = None
if not user or not user.is_active or not user.is_authenticated:
return None
try:
user_subscribe = SubscribeForUser.objects.get(user=user)
except Exception as e:
pass
user_subscribe = SubscribeForUser.objects.get(enable=True, user=user)
except SubscribeForUser.DoesNotExist:
user_subscribe = subscribe_user_to_null_price_subscribe(user)
except SubscribeForUser.MultipleObjectsReturned:
user_subscribes = SubscribeForUser.objects.filter(enable=True, user=user).order_by('-paid_period_to_DT')
user_subscribe = user_subscribes[0]
user_subscribes.exclude(id=user_subscribe.id).delete()
return user_subscribe
def get_subsribes_w_options():
def get_subscribes_w_options(user=None, check_subscribe_orders=False):
all_options = SubscribeOption.objects.filter(enable=True)
subscribes = Subscribe.objects.filter(enable=True)
for subscribe in subscribes:
subscribe_options_ids = subscribe.options.values_list('id', flat=True)
subscribe.disabled_options = all_options.exclude(id__in=subscribe_options_ids)
if user and check_subscribe_orders:
order = subscribe.get_last_order(user)
if order and order.status not in ['charged']:
error = f'{order.status}'
if 'status' in order.json_data and 'failure_message' in order.json_data['status']:
error = f'{error} ({order.json_data["status"]["failure_message"]})'
subscribe.order_error = error
return subscribes, all_options
def get_profile_subscribe_page_content_html(request):
def check_n_enable_subscribe_by_order(order):
if order and order.enable:
if order.status == 'charged':
order = order.activate_subscribe_for_user()
return order
def get_profile_subscribe_page_content_Dict(request, check_orders_required=False):
try:
# data = json.loads(request.body)
# all_options = SubscribeOption.objects.filter(enable=True)
subscribes, all_options = get_subsribes_w_options()
from GeneralApp.funcs import get_and_set_lang
lang = get_and_set_lang(request)
subscribe_for_user = SubscribeForUser.objects.filter(user=request.user)
if not subscribe_for_user:
data = {}
if request.body:
data = json.loads(request.body)
# check_orders_required = False
if data and 'check_orders_required' in data: #Требуется проверка статусов заказов
check_orders_required = data['check_orders_required']
# all_options = SubscribeOption.objects.filter(enable=True)
subscribes = []
subscribe_for_user = None
all_options = []
orders = None
if request.user and request.user.is_authenticated:
from BillingApp.funcs import get_orders_for_user, get_order_status
orders = get_orders_for_user(request.user)
if orders:
if check_orders_required:
for order in orders:
order = get_order_status(order)
order = check_n_enable_subscribe_by_order(order)
subscribe_for_user = order.subscribe_for_user
subscribes, all_options = get_subscribes_w_options(
request.user, check_subscribe_orders=True)
check_orders_required = False
else:
check_orders_required = True
if not subscribes:
subscribes, all_options = get_subscribes_w_options()
# if not subscribes_for_user:
subscribes_for_user = SubscribeForUser.objects.filter(enable=True, user=request.user)
if not subscribes_for_user:
tpl_name = 'blocks/profile/b_subscribe_variants.html'
else:
tpl_name = 'blocks/profile/b_subscribe_current.html'
subscribe_for_user = subscribe_for_user[0]
subscribe_for_user = subscribes_for_user[0]
subscribe_options_ids = subscribe_for_user.subscribe.options.values_list('id', flat=True)
subscribe_for_user.subscribe.disabled_options = all_options.exclude(id__in=subscribe_options_ids)
@@ -46,11 +202,14 @@ def get_profile_subscribe_page_content_html(request):
Dict = {
'subscribe_for_user': subscribe_for_user,
'subscribes': subscribes
'subscribes': subscribes,
}
html = render_to_string(tpl_name, Dict, request=request)
return html
return {
'html': html,
'check_orders_required': check_orders_required,
}
except Exception as e:
msg = f'show_cur_subscribe_ajax Error = {str(e)}'

View File

@@ -6,9 +6,12 @@ from .js_views import *
from django.contrib.auth import views
from RoutesApp.js_views import new_route_view_ajax
# /subscribes/receive_finish_subscribe_msg/
urlpatterns = [
path('show_cur_subscribe/', show_cur_subscribe_ajax, name='show_cur_subscribe_ajax'),
path('subscribe_now/', subscribe_now_ajax, name='subscribe_now_ajax'),
path('receive_finish_subscribe_msg/', receive_finish_subscribe_msg_ajax, name='receive_finish_subscribe_msg_ajax'),
# path('create_ticket/', create_ticket_ajax, name='create_ticket_ajax'),
# path('support_show_chat_by_ticket/', support_show_chat_by_ticket_ajax, name='support_show_chat_by_ticket_ajax'),
# # path('send_msg/', send_msg_ajax, name='send_msg_ajax'),

View File

@@ -3,7 +3,7 @@ from django.shortcuts import render
from uuid import uuid1
from .models import *
from django.contrib import auth
from django.http import HttpResponse, Http404, JsonResponse
from django.http import HttpResponse, Http404, JsonResponse, HttpResponseRedirect
from django.template import loader, RequestContext
from django.contrib.auth.decorators import login_required
from BaseModels.mailSender import techSendMail
@@ -16,36 +16,80 @@ import json
from datetime import datetime, time, timedelta
from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync
from GeneralApp.funcs import get_and_set_lang
from django.shortcuts import redirect
def receive_finish_subscribe_msg_ajax(request):
if request.method != 'POST':
raise Http404
@login_required(login_url='/profile/login/')
lang = get_and_set_lang(request)
try:
data = json.loads(request.body)
user_subscribe = get_cur_user_subscribe(request.user)
user_subscribe.receive_finish_subscribe_msg = data['receive_finish_subscribe_msg']
user_subscribe.save(update_fields=['receive_finish_subscribe_msg'])
except Exception as e:
msg = f'msg_send_after_subscribe_end_ajax Exception = {str(e)}'
return JsonResponse({'error': msg}, status=400)
res_Dict = {'status': user_subscribe.receive_finish_subscribe_msg}
from GeneralApp.funcs import get_add_to_ajax_response_Dict
res_Dict.update(get_add_to_ajax_response_Dict(request.user))
return JsonResponse(res_Dict)
@login_required()#login_url='/profile/login/')
def subscribe_now_ajax(request):
if request.method != 'POST':
raise Http404
lang = get_and_set_lang(request)
try:
data = json.loads(request.body)
subscribe = Subscribe.objects.get(id=data['subscribe_id'])
kwargs = {
kwargs_for_order = {
'user': request.user,
'subscribe': subscribe,
'last_paid_DT': datetime.now(),
'paid_period_from_DT': datetime.now(),
'paid_period_to_DT': datetime.now() + timedelta(hours=subscribe.period),
'receive_finish_subscribe_msg': True,
'currency': 'KZT',
'sum': subscribe.price,
}
subscribe_for_user = SubscribeForUser.objects.filter(user=request.user)
if subscribe_for_user:
subscribe_for_user.update(**kwargs)
subscribe_for_user = subscribe_for_user[0]
subscribe_for_user = None
if subscribe.price > 0:
from BillingApp.funcs import create_subscribe_order
order = create_subscribe_order(kwargs_for_order)
if order:
res_Dict = {'redirect_url': order.pay_page}
from GeneralApp.funcs import get_add_to_ajax_response_Dict
res_Dict.update(get_add_to_ajax_response_Dict(request.user))
return JsonResponse(res_Dict)
else:
subscribe_for_user = SubscribeForUser.objects.create(**kwargs)
subscribe_for_user = subscribe_user_to_null_price_subscribe(request.user)
# kwargs = {
# 'user': request.user,
# 'subscribe': subscribe,
# 'last_paid_DT': datetime.now(),
# 'paid_period_from_DT': datetime.now(),
# 'paid_period_to_DT': datetime.now() + timedelta(hours=subscribe.period),
# 'receive_finish_subscribe_msg': True,
# }
# subscribe_for_user = SubscribeForUser.objects.filter(enable=True, user=request.user)
# if subscribe_for_user:
# subscribe_for_user.update(**kwargs)
# subscribe_for_user = subscribe_for_user[0]
if not subscribe_for_user:
tpl_name = 'blocks/profile/b_subscribe_variants.html'
@@ -64,21 +108,30 @@ def subscribe_now_ajax(request):
}
html = render_to_string(tpl_name, Dict, request=request)
return JsonResponse({'html': html}, status=200)
res_Dict = {'html': html}
from GeneralApp.funcs import get_add_to_ajax_response_Dict
res_Dict.update(get_add_to_ajax_response_Dict(request.user))
return JsonResponse(res_Dict)
except Exception as e:
msg = f'show_cur_subscribe_ajax Error = {str(e)}'
return JsonResponse({'error': msg}, status=400)
@login_required(login_url='/profile/login/')
@login_required()#login_url='/profile/login/')
def show_cur_subscribe_ajax(request):
if request.method != 'POST':
raise Http404
html = get_profile_subscribe_page_content_html(request)
return JsonResponse({'html': html}, status=200)
lang = get_and_set_lang(request)
res_Dict = get_profile_subscribe_page_content_Dict(request)
from GeneralApp.funcs import get_add_to_ajax_response_Dict
res_Dict.update(get_add_to_ajax_response_Dict(request.user))
return JsonResponse(res_Dict)
# try:
#

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,33 @@
# Generated by Django 4.2.2 on 2024-06-02 12:58
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('SubscribesApp', '0003_alter_subscribe_bg_color_alter_subscribe_text_color'),
]
operations = [
migrations.AddField(
model_name='subscribeforuser',
name='used_route_rising_count',
field=models.IntegerField(default=0, verbose_name='Использовано поднятий объявлений'),
),
migrations.AddField(
model_name='subscribeforuser',
name='used_route_select_count',
field=models.IntegerField(default=0, verbose_name='Использовано выделений объявлений'),
),
migrations.AddField(
model_name='subscribeoption',
name='allow_route_rising_count',
field=models.IntegerField(default=0, verbose_name='Количество поднятий объявлений'),
),
migrations.AddField(
model_name='subscribeoption',
name='allow_route_select_count',
field=models.IntegerField(default=0, verbose_name='Количество выделений объявлений'),
),
]

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