Compare commits
1383 Commits
ebf57692ff
...
feature/su
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
15c9d589fe | ||
|
|
fa116c08c1 | ||
|
|
4f9129e718 | ||
|
|
df45f3a704 | ||
|
|
90ef093fca | ||
| 4331b26542 | |||
| dd8a8ddd53 | |||
| abb0d488eb | |||
| be97b848d0 | |||
| 6bc112d689 | |||
| dc534a0c51 | |||
| e71ed05e6c | |||
| 2048ed6baf | |||
| c146bd6155 | |||
| 98665abf4d | |||
| 9954140d3a | |||
| fafee63a64 | |||
| c623d69767 | |||
| 670eb28bc0 | |||
| 144ff286f6 | |||
| 05f94de0b4 | |||
| c4650ce603 | |||
| 3971a8ee23 | |||
| a3ba6bc783 | |||
| b87df02714 | |||
| 713695cf7d | |||
| a25f30eda7 | |||
| eddb3a1858 | |||
| 5a89200f1d | |||
| 2f47a9e3db | |||
| 155b6272ec | |||
| 1479584bfc | |||
| f86be5bd97 | |||
| c87a7095ad | |||
| ac4df7a5f7 | |||
| c48839ff8c | |||
| ea296e3f05 | |||
| 8124ed62fe | |||
| cc643d2641 | |||
| 6de42c5ba9 | |||
| 36b7f4dee7 | |||
| 2328f09023 | |||
| 60faeeace9 | |||
| abe53dd88b | |||
| c76a18c5ff | |||
| 3725ce1882 | |||
| 6a69ff02b1 | |||
| 6ba41af305 | |||
| 5815a08b55 | |||
| 7805161829 | |||
| 6fa31f3866 | |||
| 0763faf224 | |||
| a3d3e12467 | |||
| ab22a3ec88 | |||
| 9d0a059909 | |||
| 1011f112b2 | |||
| d07ab2c71f | |||
| 96bfef04a8 | |||
| 779dd7e93d | |||
| 0abcb34829 | |||
| 33c028207a | |||
| 64b3e40ed0 | |||
| 0023676b28 | |||
| b90039f21a | |||
| b5f24ebf2e | |||
| f99a010e4a | |||
| a4944360a6 | |||
| a2b5d81c98 | |||
| 13b7c2572d | |||
| 47b12882ba | |||
| c008aa585b | |||
| 406b5e8480 | |||
| 584a196784 | |||
| 618f7751d1 | |||
| faaea1129a | |||
| dd7afc28f7 | |||
| 9ecf5ce073 | |||
| 422373f00e | |||
| 60636daeb8 | |||
| 9d47f4c2bc | |||
| 4d6dbddd28 | |||
| 3f00ff39d2 | |||
| bff6a81586 | |||
| 9cb8036d3c | |||
| a43de1fa91 | |||
| 93717bee2d | |||
| 8db1d6fdce | |||
| b41f8c7eca | |||
| c19405d32a | |||
| 7b75c533a8 | |||
| 649dbab901 | |||
| 1a4498d19f | |||
| 2786ef454d | |||
| 961c0dd2a5 | |||
| 0a0835d3a6 | |||
| bc87d10d59 | |||
| 792693848b | |||
| de229c5f78 | |||
| 03f9a836e6 | |||
| 91751574cc | |||
| d5453dada6 | |||
| 22adb18a39 | |||
| 0a3c40dd5d | |||
| b29825d62b | |||
| c9bda8aab2 | |||
| 284a4b064a | |||
| 6f20f53d75 | |||
| 473a047af9 | |||
| 481f9a881f | |||
| 6ceedddbc1 | |||
| bd9e0fad48 | |||
| 6b118d00b6 | |||
| 01e221196f | |||
| ccf016999b | |||
| cb79e47796 | |||
| 4076bd6065 | |||
| e54c258007 | |||
| c3b7401255 | |||
| 9af72d30f4 | |||
| dbe948ae5f | |||
| 885d36a90c | |||
| 7acfbc0113 | |||
| 43c5faf988 | |||
| 437142fba0 | |||
| acf7b702ee | |||
| 74ca1be884 | |||
| 26b987d6ce | |||
| 3f7f1d88ed | |||
| 59225b1688 | |||
| 108aee2c43 | |||
| 9062ce32a1 | |||
| 7c74a0f3fe | |||
| 4fb3a12f47 | |||
| 59bc25f31c | |||
| 87fbe7852c | |||
| 793d283d97 | |||
| 651ae18345 | |||
| 67eb32968e | |||
| c6d41513c0 | |||
| 67ba698b60 | |||
| 15d1c00ac6 | |||
| 9e9a82ffc0 | |||
| a0eb5210ab | |||
| 3dacc0316e | |||
| e2c347c912 | |||
| 758f8b1f55 | |||
| b446a8f519 | |||
| c8ba0dd770 | |||
| f13a1329ca | |||
| 4b3604098f | |||
| defbf6746f | |||
| bf3f26ec4f | |||
| 76018333b0 | |||
| e6e345b9fe | |||
| eafccabb66 | |||
| f2e0628de1 | |||
| 2e1f3a10ab | |||
| bf18c96dbd | |||
| 23718a5f3f | |||
| c6a1d5bdcf | |||
| f75e94f706 | |||
| 11c9bb6c23 | |||
| b1ff9c47da | |||
| 35c09dc70b | |||
| f0efae5987 | |||
| 65120cd2d4 | |||
| 231d062814 | |||
| 615922a881 | |||
| 61b2b824d5 | |||
| 317445998a | |||
| 4ad3813499 | |||
| 9a88243323 | |||
| df0f32c71a | |||
| 4ddd402442 | |||
| a05c4b3898 | |||
| a3ab0973c9 | |||
| 0f801aa44b | |||
| 7bc386bc44 | |||
| e148c60d70 | |||
| 4667352ec4 | |||
| e7cf694d88 | |||
| b2abb3046b | |||
| 6c1011e59e | |||
| ad909b98bf | |||
| 9d2e35246a | |||
| 48dc573c0f | |||
| e559660912 | |||
| aa3bec304a | |||
| c7bc22813f | |||
| 46e73db10a | |||
| ad451c2ae0 | |||
| 0b5b557a35 | |||
| fb9228c432 | |||
| fbcbe93042 | |||
| ca44deb077 | |||
| 61403bfac2 | |||
| 190efa4b74 | |||
| ca06836b11 | |||
| b31241872f | |||
| f80e2844bf | |||
| 1dae86f0e7 | |||
| 0c146caeef | |||
| 410733211b | |||
| 14df8969c2 | |||
| 4388414ac2 | |||
| 791ac8d436 | |||
| a3d6f498b1 | |||
| b8fdd61948 | |||
| 4437372d7c | |||
| f8d29d80b7 | |||
| 36fd9599af | |||
| 65eccde487 | |||
| 037b4cc562 | |||
| 9c971a6fa4 | |||
| a3faa17754 | |||
| 085f905125 | |||
| dc16ced786 | |||
| d5cba26098 | |||
| 001dd2cb87 | |||
| 16e860a29f | |||
| 6a5331d8eb | |||
| aff0b0fe98 | |||
| fd3612c370 | |||
| d14a46d3d7 | |||
| d7ace77de8 | |||
| 885e4722af | |||
| 72ed6369d8 | |||
| b23e440efd | |||
| 75ddb002fd | |||
| 28a36335ce | |||
| fba225aa70 | |||
| af800ac84c | |||
| 87e90d7152 | |||
| c25942a6ca | |||
| 692419816f | |||
| 3a109340fd | |||
| 5925ecb975 | |||
| 325acd3580 | |||
| 3ac85784a9 | |||
| 5c4e715970 | |||
| 89b57feb4e | |||
| fc194d3f85 | |||
| 12af0ea238 | |||
| 6e758cf62e | |||
| f7783c070b | |||
| fb3cd30db4 | |||
| ff949a8205 | |||
| 624653f581 | |||
| f3e5f02f07 | |||
| d0792e9e84 | |||
| f752eb5d4a | |||
| f0861fde84 | |||
| 4e7aa09c21 | |||
| e68a0dc151 | |||
| fc37bea98a | |||
| 8a91e611ac | |||
| 7208db6981 | |||
| 447a78cd3a | |||
| 95dff519b8 | |||
| 62aeebae95 | |||
| c2e03728f8 | |||
| a64fbab270 | |||
| 00ea16f631 | |||
| e3aafcdfe9 | |||
| 421a3a2dab | |||
| 61e4f7e450 | |||
| 3b52cab162 | |||
| fe9be61772 | |||
| 0818f880cc | |||
| cca062efec | |||
| 2eb7ac85d3 | |||
| 3469a3923c | |||
| 20fb49b3e4 | |||
| afe8feebc2 | |||
| ae6a68d85b | |||
| d80c45acd5 | |||
| 3a9ac2c289 | |||
| 2d68836724 | |||
| 0deb85b5a3 | |||
| 7b38f6e3b3 | |||
| 43f050f070 | |||
| 098b7c4fb5 | |||
| eae56199e0 | |||
| 71e8f0f465 | |||
| 66d7183278 | |||
| 92b92f2d65 | |||
| d5ab7d82eb | |||
| 1ebd9f9c0b | |||
| 7fd2c60ddb | |||
| f068182557 | |||
| 02945b0691 | |||
| 21b959e6a3 | |||
| 747091c744 | |||
| 7b70052ff1 | |||
| 49fd26bc4c | |||
| 77f365ef45 | |||
| 6d34d46e38 | |||
| 970c2e0837 | |||
| b87549d567 | |||
| 78abdb2fef | |||
| f73ebb08c9 | |||
| 628e8eec09 | |||
| 66ddcaec5b | |||
| 3901c82aae | |||
| 9f682b66a5 | |||
| c74aff7b91 | |||
| 1be50b1277 | |||
| af00d1a54b | |||
| dd4ad82248 | |||
| 38c08cbced | |||
| ed2c74a280 | |||
| 90ab1bb6b4 | |||
| 3e2220e5f2 | |||
| 33e27620b1 | |||
| fbdef2a1ec | |||
| 1834639b50 | |||
| f9606a3c88 | |||
| c803d7abbb | |||
| efd75817bc | |||
| 36fff15e2b | |||
| 7573bfb344 | |||
| 0c33d638ba | |||
| 7d3da34e22 | |||
| 0e2723a367 | |||
| b102c44031 | |||
| 4b480c35e5 | |||
| 8e7bcd8fd8 | |||
| c60c545031 | |||
| 51d075f799 | |||
| db54ec1650 | |||
| 14b362442f | |||
| fcfbeece87 | |||
| aea501aedb | |||
| f1d175fe84 | |||
| 0f432c4fd9 | |||
| b53e19c439 | |||
| bebd20abf0 | |||
| 5dc2293212 | |||
| 37f480c01e | |||
| f16efa24b0 | |||
| e11d05eb02 | |||
| 32cd45106d | |||
| 7b95893b34 | |||
| b6769f6350 | |||
| 5650b2d6b9 | |||
| f0fe8edf80 | |||
| b30df5b6ed | |||
| 0ef26556a2 | |||
| ea92feab27 | |||
| 1720e156d2 | |||
| 9ed06e741e | |||
| d39a3a78d0 | |||
| 09dc2984f3 | |||
| 660e3f8a99 | |||
| cc9797eb71 | |||
| 6a8aa73e63 | |||
| 689495e410 | |||
| 415fad4f4e | |||
| 396db7a439 | |||
| 61bea5639b | |||
| c9d6812d11 | |||
| 18dd435678 | |||
| a7a4112312 | |||
| cf8cb9a6a4 | |||
| b31f1ddb0f | |||
| 382ddd48e4 | |||
| 0b57fa9238 | |||
| fe7721270b | |||
| 49b35abb0b | |||
| 41dbb6bad7 | |||
| fde640e997 | |||
| fd1f4ff9b1 | |||
| 3a4c1b12a6 | |||
| ce68dbee8a | |||
| 1976a4c1dc | |||
| 0dc3419651 | |||
| 7769608e03 | |||
| 9772d7670b | |||
| 36e9edb51b | |||
| 6191980dc7 | |||
| 7179b67137 | |||
| 65362e34b8 | |||
| ec76d336f3 | |||
| 12d5e4546d | |||
| 4a97b02010 | |||
| aa492f6ca4 | |||
| 7547d2cb89 | |||
| 3febf729b6 | |||
| fbfdec2380 | |||
| fb665b409c | |||
| f86e76615d | |||
| 7cfe3f699a | |||
| 03ab2ae2cd | |||
| ad1016a427 | |||
| 6fc40452d9 | |||
| de098bdf55 | |||
| dcfd66324e | |||
| ff962b9658 | |||
| 006ff44858 | |||
| f9fdcc5314 | |||
| e49605dea6 | |||
| e429f48320 | |||
| 43ef016751 | |||
| 4a59adc73f | |||
| 2ebc28519e | |||
| 23de94b8cd | |||
| 42cf20137b | |||
| d5bb15e695 | |||
| 039985fe5f | |||
| d618c10e8b | |||
| 069f2094f0 | |||
| 2b6bbba265 | |||
| f7e032a5bc | |||
| 0d394fb6b7 | |||
| 9635a1dcf2 | |||
| 6ae3a88d7b | |||
| 512499ab12 | |||
| b8e3092fc4 | |||
| 4b9e5e5f34 | |||
| a7d9dfe79a | |||
| cc503ec6d1 | |||
| 7eb8edbe1f | |||
| 1f4ccaec4a | |||
| 66e0edebc5 | |||
| ebdc84f7e1 | |||
| cd1b8d4579 | |||
| a733649521 | |||
| 01d72c5f45 | |||
| 55681c7fb8 | |||
| 4a19726a99 | |||
| 61f26299b8 | |||
| 8a6317da2b | |||
| 1124149cf8 | |||
| 426071fe15 | |||
| c97aa44723 | |||
| de6bd9682e | |||
| 16e7ea3109 | |||
| 41fa14351a | |||
| 35f135a10b | |||
| 037abac188 | |||
| fecd32a254 | |||
| 446af5e438 | |||
| 71ecd65814 | |||
| 3e101493dc | |||
| 453d4b7349 | |||
| 40a8bc158a | |||
| 2c711ed370 | |||
| fc1654dedb | |||
| dfec56fef9 | |||
| 942db49daf | |||
| d4562e7ca4 | |||
| 3a0845fe2a | |||
| 3740ac642f | |||
| c1ccf00302 | |||
| 4400a6b13f | |||
| 66fbf984e9 | |||
| 30ebc6037a | |||
| ac60b08f2d | |||
| f32e127148 | |||
| 8e3b798bce | |||
| 57dddf528b | |||
| 35d5e05f00 | |||
| 4ecc89a4e7 | |||
| 87bc1be15a | |||
| b1c599e71d | |||
| da3fb36a22 | |||
| ded7761c91 | |||
| d4de2ef739 | |||
| 7637f6fdd1 | |||
| f663954f03 | |||
| f2fd95b04e | |||
| 3880b97cae | |||
| 2fb00ee112 | |||
| dc92877beb | |||
| d9103e62a7 | |||
| e5a8c3cb8f | |||
| 97b00d94cf | |||
| 381f0a8490 | |||
| b8b3fd02fa | |||
| 3b244f4de0 | |||
| c4d101275a | |||
| c9b21ded98 | |||
| f5115f82fb | |||
| d6a6b4f319 | |||
| f3e418cf68 | |||
| a74a0c1f57 | |||
| 0f10e274e6 | |||
| 57a419eeaa | |||
| aa18a3c542 | |||
| dea8d064d4 | |||
| d022fb231f | |||
| 415784bf06 | |||
| 246974c1b8 | |||
| 34d2fea31f | |||
| 0571de3dd0 | |||
| 4e2d453ff1 | |||
| f4ba38654b | |||
| 7831973cdb | |||
| 4f2c7aeb2c | |||
| 237666d96f | |||
| f6d0486a19 | |||
| 200a9c308c | |||
| 28d3138c43 | |||
| 0d41c95e3d | |||
| e5ea92df3d | |||
| 9f7550eaae | |||
| 3e88458fce | |||
| a5cbf8c128 | |||
| 704b88320a | |||
| 0aae04eca8 | |||
| 3f1cd5431f | |||
| 5081b6ce3e | |||
| 7e7fb437a6 | |||
| addca29f0f | |||
| f1775237fb | |||
| f09ff3f7df | |||
| 4259f84764 | |||
| 707bbf1863 | |||
| a989f85b2b | |||
| b62396a907 | |||
| 998c91c727 | |||
| 64b8e74612 | |||
| 55eff16b9c | |||
| 31857131be | |||
| 77de950af8 | |||
| 176c84cf2d | |||
| 15ea6a982c | |||
| 6230b77473 | |||
| 2f81a73078 | |||
| cf83ae059e | |||
| 4418d4ad6f | |||
| 239b6a0da1 | |||
| cc02495459 | |||
| 153d0380de | |||
| 87fb930c63 | |||
| 38a8cef3d9 | |||
| 6f7551abbf | |||
| 64d6860e58 | |||
| 88e6c7eee8 | |||
| 75c5553852 | |||
| 9d1815c21f | |||
| c93cda4eaf | |||
| cce969d870 | |||
| 0b177d845c | |||
| 42f288e0e4 | |||
| 3948c79891 | |||
| c8a28de46a | |||
| c660d8cb72 | |||
| a2688c4a15 | |||
| 9d2e9b7acd | |||
| f37ed72b39 | |||
| 6fd3c11f06 | |||
| 414ffc703d | |||
| f7a587b7a5 | |||
| 534defa36b | |||
| 1fbf846270 | |||
| e6a1cd967e | |||
| c9adf1a785 | |||
| 8380b7e66e | |||
| e01c7e81f2 | |||
| 4751dd9079 | |||
| f82ae16e31 | |||
| 8a00446b5c | |||
| 39f37bcd23 | |||
| c8e4df8150 | |||
| 1e9e2cb048 | |||
| 06661cb187 | |||
| fade021048 | |||
| 9d90138847 | |||
| b7a677d79d | |||
| 3660f5af6d | |||
| 61e1c35f02 | |||
| 89721ce797 | |||
| 55b4c0ac11 | |||
| 70df8a53c8 | |||
| 3311ab5b37 | |||
| 49ad367a70 | |||
| cc3a5c4a4f | |||
| f7af979b7e | |||
| 6f06f96a94 | |||
| a3ef86ba37 | |||
| d6da292d5f | |||
| ccb8c6585c | |||
| ea567008c6 | |||
| 6cbde10b11 | |||
| 7e23776501 | |||
| e6a91ebc72 | |||
| 06a2e883fb | |||
| 00b0e00fd3 | |||
| 8086d5344e | |||
| ea76733305 | |||
| f0f8af48b3 | |||
| 9bc02c7752 | |||
| 3067535fe0 | |||
| cc6bd781e0 | |||
| 10a1cb096d | |||
| 47c228d048 | |||
| 11c35c9abd | |||
| ba8bde1153 | |||
| 7c991024b7 | |||
| 710d500980 | |||
| cde0b55aab | |||
| 6660db1a89 | |||
| 8f76b484ba | |||
| b8790be7fe | |||
| bd4a2e7507 | |||
| 70002f4efb | |||
| d40eed3c5d | |||
| 130d601e54 | |||
| 7ae8d0ce48 | |||
| 494ff26fdd | |||
| 330a582a26 | |||
| 54d5669b3b | |||
| a7491c545c | |||
| 6515979251 | |||
| a97d9ec2bc | |||
| 2685e80161 | |||
| ea94031545 | |||
| 298e3861cf | |||
| ce230e80a5 | |||
| b12ae238d3 | |||
| d482570221 | |||
| dde8c5fdd9 | |||
| 259d6662fe | |||
| e4849ec659 | |||
| 88f679cd41 | |||
| f97eeb83c2 | |||
| 155e5bdf57 | |||
| e78c9a1efb | |||
| 4b74dd8f19 | |||
| c3be6d3e83 | |||
| 50baa907bd | |||
| 40207ab256 | |||
| 0733851e4e | |||
| 1aea397f9a | |||
| 335af09596 | |||
| 95c3c062fd | |||
| f47e3e550c | |||
| d3d0dc5a22 | |||
| ff4c573941 | |||
| 8d52620d32 | |||
| 5856fbb670 | |||
| 7cb8a2de39 | |||
| d57be37c34 | |||
| 28a14aaf76 | |||
| 359ed5770d | |||
| fe093aa9ac | |||
| 338a9ed08a | |||
| a8c954e8d9 | |||
| 50ee432965 | |||
| 4b3e3b8401 | |||
| 2abf0f62e9 | |||
| 69dd70d42d | |||
| 405cae84fe | |||
| ae9902965a | |||
| 0c20d7d0f4 | |||
| d4e3b75bcb | |||
| bbd3fd51dc | |||
| 9ecc961e42 | |||
| dd2cc62d01 | |||
| 7e316bbc73 | |||
| e455a19ff3 | |||
| 618064d16a | |||
| 05705a91cf | |||
| ec8ede8e28 | |||
| 6131d2534a | |||
| 775ffe42d7 | |||
| 400621572f | |||
| fe4539c9ed | |||
| a19017351b | |||
| e1a6fdd21f | |||
| 264c5ae372 | |||
| 0a00e950b6 | |||
| b12f2e784f | |||
| bc170e982f | |||
| c68c7b6109 | |||
| ac95ac04bc | |||
| a23ccb7ac4 | |||
| 09c74d8f85 | |||
| 4c747a0c5e | |||
| 3aa4b774bd | |||
| 93cf3aa695 | |||
| e75dd6c552 | |||
| 6ea03098b2 | |||
| 2cef14d2d8 | |||
| b7b6750ad2 | |||
| a729070654 | |||
| af42956f60 | |||
| ad8518a4c3 | |||
| 1c1867610d | |||
| 8c3ebb00e5 | |||
| abba3e6e10 | |||
| 058fe769b9 | |||
| 4b037443a6 | |||
| 28db905e14 | |||
| 41d7a996fd | |||
| 114a65746c | |||
| 6dd0cf7724 | |||
| 8e5a018c2a | |||
| 052f236206 | |||
| da3774527f | |||
| 93401402ca | |||
| c1ea4788a4 | |||
| b32a79f966 | |||
| cd748dc371 | |||
| defce7a85c | |||
| 63d5b62229 | |||
| 1acda2bb11 | |||
| db8f5e16e3 | |||
| c5c8fb8689 | |||
| b11478b4c0 | |||
| 26463c1853 | |||
| b0b6513bb7 | |||
| 0c6135d786 | |||
| 0167baec84 | |||
| cb5ab935ee | |||
| 96efd045b4 | |||
| e1846e0564 | |||
| ed809290ca | |||
| 0b2b9e184f | |||
| 4dd32820a3 | |||
| ffa6de7138 | |||
| 189b9233ab | |||
| 8c05b987ed | |||
| ed00864447 | |||
| ad9e6aa6b9 | |||
| 04daddefa7 | |||
| acf51fe626 | |||
| 9d44384d22 | |||
| a435e85d4c | |||
| c6edd2c533 | |||
| 928c737ead | |||
| 794d30ebf1 | |||
| 0864a07cdf | |||
| b64f58c237 | |||
| cc86400957 | |||
| b8c282f95f | |||
| 47e39a1d9c | |||
| 308e9c1df2 | |||
| d3fd7b7428 | |||
| 31833000bb | |||
| 02f7edade5 | |||
| 371457735a | |||
| ea65d62be8 | |||
| d1b8a7a4aa | |||
| 9b94b56c6e | |||
| e07cf3f9d6 | |||
| 906856b01b | |||
| 4ac3349377 | |||
| 3a9b421503 | |||
| c844389f09 | |||
| 444f23f9b2 | |||
| 721f2916cd | |||
| 5d707853b7 | |||
| 19621752b5 | |||
| f0e8cb5101 | |||
| ac2de4ddcc | |||
| 5471696d62 | |||
| adee3383ce | |||
| 0ab9631e0f | |||
| cc377963e0 | |||
| 5c22478108 | |||
| 51598dc022 | |||
| f620cd26af | |||
| 1f3a8a258b | |||
| 19983bf7a1 | |||
| 47ffae4b82 | |||
| 487647029a | |||
| 89ee4960c2 | |||
| 9c95358305 | |||
| 71c4ce41f0 | |||
| f60c96e9fd | |||
| 9ec605bed1 | |||
| 6ac082c7df | |||
| f552d6c0f2 | |||
| 52c65f598d | |||
| 9b12ca8ff3 | |||
| 31ba8a86bf | |||
| fe90ab8f50 | |||
| 58acad0eb8 | |||
| 3ce22bcb32 | |||
| 71846ade42 | |||
| 9c24034776 | |||
| 735a84bf9a | |||
| b65a668e77 | |||
| ac2b1e43df | |||
| 63cea80a20 | |||
| 67a51c882a | |||
| 21b873c80d | |||
| c86ebc7aa3 | |||
| 32f65de458 | |||
| 63d3ffddd4 | |||
| 70f6ccc0da | |||
| 5fa470bd9c | |||
| 01414ca4c6 | |||
| c781453055 | |||
| 8b4b06c0f7 | |||
| 0737446ea1 | |||
| 5f71eb5e0b | |||
| b89b9ed017 | |||
| 0df3067416 | |||
| f850ef5c31 | |||
| a520c3872a | |||
| 16c32ebdfb | |||
| b0640e88f9 | |||
| 6121b6ceb1 | |||
| 2d865d9c3d | |||
| 95f92efa70 | |||
| 840a61511e | |||
| a1ed21cd17 | |||
| c2b9b0c85b | |||
| 2cc45c7efc | |||
| 6dfc41fc0d | |||
| f421e31de1 | |||
| 53c5b2b53e | |||
| c024b74f5b | |||
| 598bcaaea4 | |||
| 571c0d08e0 | |||
| a56c8c2609 | |||
| 724c450120 | |||
| 1794911d27 | |||
| 01c7b01c55 | |||
| 4bf5488d79 | |||
| 9d2b523f29 | |||
| 9eb079c5bc | |||
| fc8c28203c | |||
| a03d9b3dec | |||
| 641e3da1d0 | |||
| 15b2110617 | |||
| 7a8f3bdbb5 | |||
| 65c90e1f11 | |||
| dd7795d845 | |||
| 5af924556e | |||
| cec55a36ed | |||
| 09ec97ec2f | |||
| 32b8116357 | |||
| c3079f4a65 | |||
| 78148def17 | |||
| 754f0ecc43 | |||
| a0e8698aa5 | |||
| ff14b4aa2a | |||
| c0e6bcf7cb | |||
| 71e34c6b03 | |||
| f5208def43 | |||
| 4f28e5d5a4 | |||
| 0a4329ea67 | |||
| df5279e3f6 | |||
| cba94595f1 | |||
| ed38aeed45 | |||
| 57f5392203 | |||
| 2b95eceea9 | |||
| e4f017df2a | |||
| 20e6357127 | |||
| 31ad83e561 | |||
| 06219e8f69 | |||
| 2f5485cc25 | |||
| cf70c543e3 | |||
| 463f63af19 | |||
| 84620e74f8 | |||
| 573b8ec0c3 | |||
| 4aa659d206 | |||
| 02e6733b13 | |||
| 7c6891e46f | |||
| 35a953b546 | |||
| 52edbd867d | |||
| 9f2ec3e79f | |||
| 4ec85b85cb | |||
| 4888fc7211 | |||
| ca1d177565 | |||
| 0b608e1b3e | |||
| 5ae0e75a96 | |||
| 54105c47f0 | |||
| 0f9ce1abd6 | |||
| c322053b02 | |||
| dab09b193d | |||
| 97fb0e3e13 | |||
| 7abad9c43d | |||
| ce67fddcc9 | |||
| b33664d3c1 | |||
| d0359907d7 | |||
| 914133e73e | |||
| de34cedacf | |||
| c4d0975313 | |||
| 2fffff65c4 | |||
| d78ac25828 | |||
| 4a267122e2 | |||
| 8a8fdbb8ec | |||
| ef8e664276 | |||
| ab84352918 | |||
| 51f15e2f67 | |||
| e3fb527fe6 | |||
| 96c1b23362 | |||
| 9b7fbe8fd3 | |||
| 2d25fd3e38 | |||
| e850bceacf | |||
| da7b1cb549 | |||
| 1747b0ebb5 | |||
| eebdd35ec8 | |||
| 87b95f50fb | |||
| d09ca59279 | |||
| 8e6312f1ad | |||
| b221e7a330 | |||
| d60d03f666 | |||
| d90449f0fe | |||
| 677eb001bf | |||
| 4f5b7c5c08 | |||
| b94d8e1d87 | |||
| 4f46a01469 | |||
| ae4d871d90 | |||
| bae7e05077 | |||
| 636d97250b | |||
| 6097d5a2bd | |||
| 2dbbc7dcaf | |||
| 11506903cc | |||
| ec23d2ac37 | |||
| 1e00d941d1 | |||
| 214eb0f7ef | |||
| a24d1ac987 | |||
| 7345e70568 | |||
| 9e9c645799 | |||
| 8539e9ce30 | |||
| 21fb8d0955 | |||
| 2dc85fdb6f | |||
| b99f34fad1 | |||
| 34a789337c | |||
| 29416b838e | |||
| f5b00402c9 | |||
| 10e38edab8 | |||
| e456c2606f | |||
| 36037c3cfa | |||
| d14e2dcbbe | |||
| b0f138489d | |||
| 31379e0949 | |||
| d078a10f64 | |||
| 691b38f725 | |||
| 6c6801c1f0 | |||
| cc00322a04 | |||
| 77f96a39b6 | |||
| 7002bd2600 | |||
| ff47788d36 | |||
| 9d226e3f6f | |||
| fa2c3ee569 | |||
| 704c44a636 | |||
| 52a0105806 | |||
| ad66adefbf | |||
| 68978d09ac | |||
| 28504cbc45 | |||
| f2580cf766 | |||
| 60a21740db | |||
| 528ab0a8e2 | |||
| 1af65b01f6 | |||
| deadb0c73c | |||
| ebc9bacbf1 | |||
| 7dd1fe5dfe | |||
| 436cd9aa58 | |||
| 27db6bd53f | |||
| aef46d5d9c | |||
| 1f330f3660 | |||
| 8b41767751 | |||
| e49de29785 | |||
| bc9b47f651 | |||
| be6313d2d0 | |||
| 0d60283b36 | |||
| d81688eb59 | |||
| df03f16c0a | |||
| 2ea763265e | |||
| cc52dc3fa5 | |||
| df370606a6 | |||
| 18dd7ff1f1 | |||
| 835cce2d45 | |||
| 5999a67257 | |||
| 63879809fd | |||
| 45fb9d0060 | |||
| 22932459cc | |||
| 0dca0557c7 | |||
| a46bbdec84 | |||
| cb926522bb | |||
| 26d2a5699d | |||
| 5947b6fcb9 | |||
| e59028a11a | |||
| 1f71c4eba1 | |||
| bbf660a2eb | |||
| 0efe073a2a | |||
| 40b18a2a89 | |||
| cee09d18db | |||
| 7fc8beeb00 | |||
| bd5317fa27 | |||
| f7d4bbf2b3 | |||
| 3015a3e8f2 | |||
| 227aba33ee | |||
| 770289f1ae | |||
| 7f2e216db4 | |||
| c8a902998f | |||
| c23ccf6212 | |||
| 1b809790a2 | |||
| d5d702c431 | |||
| 2757ea4d95 | |||
| 79c32a013e | |||
| ecdf99a187 | |||
| fa06af7695 | |||
| 853706b36b | |||
| dcfe131237 | |||
| 075d2915d3 | |||
| 5081aca37d | |||
| 335101166c | |||
| a48777343c | |||
| 8c80f43819 | |||
| 15b1c9b5eb | |||
| 1298765964 | |||
| 7dba4864e9 | |||
| fcf3063e09 | |||
| f1bda3ce68 | |||
| aa6fce9f3d | |||
| e852a2b358 | |||
| db3d47b36f | |||
| 7fbc7b6e9d | |||
| 73888ec864 | |||
| 53548046b3 | |||
| 879f452690 | |||
| bf96a97d0b | |||
| d7c1585b21 | |||
| d36a59b2a0 | |||
| ee7b6b39d5 | |||
| 24215a9526 | |||
| b4e8a730a0 | |||
| 44b1b8ac56 | |||
| 51d5ed1dae | |||
| 34737e04bc | |||
| c3163a8571 | |||
| 411568fecd | |||
| e19c9610e8 | |||
| 6c0b187d25 | |||
| 252ca6f494 | |||
| e206e7e64f | |||
| 2d42d03dc8 | |||
| 01863bcf38 | |||
| 1f3bb2dce9 | |||
| 96f48f88df | |||
| 3312b825fc | |||
| e97d52d8a7 | |||
| 0a2019e833 | |||
| 6198ccaa97 | |||
| 63f0fe8dd9 | |||
| 00799916c6 | |||
| 2fce92acf8 | |||
| fdeb2a4ae1 | |||
| 59fb628ced | |||
| 1d56d81a3e | |||
| 19f62a0593 | |||
| 26e923ab58 | |||
| 58f42c4651 | |||
| a470bc3325 | |||
| b5652acad6 | |||
| 46bc6ea65a | |||
| f7fa3ef681 | |||
| 270c56b1b5 | |||
| 380dc4d77c | |||
| ca01e1a728 | |||
| 1f39da2b45 | |||
| bac7b7a2d5 | |||
| 4cd6d1d0f5 | |||
| 8b55479d0a | |||
| b9efd41a48 | |||
| 90f880ee70 | |||
| c8c0f43d4d | |||
| de0446c799 | |||
| 4ee4d3f836 | |||
| 408da784e1 | |||
| 5e77e204ba | |||
| 3a087616ee | |||
| e97dc7fcee | |||
| 1873933416 | |||
| 45001b5d3c | |||
| db0a40de71 | |||
| fc4095a7e4 | |||
| ec8fded136 | |||
| 237524be8e | |||
| 4354d1369d | |||
| 0457f1f476 | |||
| 05ea2a4076 | |||
| 8eaf664de6 | |||
| 3b615607a9 | |||
| 0e810aa790 | |||
| f92f7b6ba8 | |||
| fcb5df09b1 | |||
| 188866eda1 | |||
| f1246b3b27 | |||
| 2fcc7321cb | |||
| e8b465be5a | |||
| ca03dcaa6e | |||
| fb31feac39 | |||
| f5726c8e2e | |||
| 2d1a3464e7 | |||
| 16eda7c0af | |||
| 1e152c7dab | |||
| 6a2debcc2d | |||
| ec07a69c1e | |||
| df02cc1529 | |||
| 0d1ca2bb51 | |||
| b0de8e9159 | |||
| 3ca5f61221 | |||
| 2a56bb093b | |||
| 30b090c527 | |||
| 4f294455cc | |||
| fa360267a0 | |||
| 40fc623123 | |||
| f1596e1856 | |||
| 66f348d4a0 | |||
| 1e59047071 | |||
| 2f31fa3e10 | |||
| 27f8663051 | |||
| cf79c78d41 | |||
| 82fa7edc18 | |||
| 48da2b2848 | |||
| 80a87fb8e7 | |||
| 00952a0e3e | |||
| 945d401004 | |||
| fcc86d079a | |||
| c6a8862b43 | |||
| 352daf8c36 | |||
| 0be71f7497 | |||
| 393d2de7bc | |||
| cd8b59e225 | |||
| e36cb78a15 | |||
| a06830ae9d | |||
| 573ca32fe1 | |||
| a3e5c50940 | |||
| ddf9f74db5 | |||
| e6bc30cb80 | |||
| 20ed037311 | |||
| 9562796884 | |||
| 0ea84c3db4 | |||
| a2925ad45c | |||
| 895df67b1c | |||
| 00f99ce667 | |||
| 4db864ea7b | |||
| 7dc7ead417 | |||
| 5c3bffdda4 | |||
| dd8551c0c6 | |||
| d976ce9c89 | |||
| 4a8d2ad8c8 | |||
| 1018b4b318 | |||
| 3c17276e27 | |||
| bf451393b6 | |||
| 4fa6ce6141 | |||
| 51a65743d1 | |||
| 60bfa0fadb | |||
| e86aa76002 | |||
| 2d48ecc855 | |||
| a73adde79a | |||
| 4d8ee4bfcc | |||
| 0acfaca8f6 | |||
| 9dd4577bc7 | |||
| 66c142a4d6 | |||
| 54126265b2 | |||
| ebe09382c0 | |||
| 957b8c9041 | |||
| e8e9d6af41 | |||
| 31c51d6c0e | |||
| 64fd9c7b17 | |||
| 9e0b725b2f | |||
| 3588bd14e3 | |||
| 4f016990ea | |||
| 571e4b0cc1 | |||
| f5361f679a | |||
| 662138ac00 | |||
| 62c7694c50 | |||
| 4c6e2200c0 | |||
| 9d0998fb2b | |||
| e9d4d71c9d | |||
| a970f06dc8 | |||
| 7cbe8db366 | |||
| 8e07b3c304 | |||
| 9e3306f1be | |||
| 122e041b08 | |||
| 35da421ad2 | |||
| cc82bb8f36 | |||
| 4b05dcc7a7 | |||
| e280283e40 | |||
| b13c76816d | |||
| cbee5af4ed | |||
| 26877620b1 | |||
| 3c3daf13cd | |||
| 87b8b96f15 | |||
| 509052cc61 | |||
| d573df0359 | |||
| 5890415b06 | |||
| 9bef9366b3 | |||
| 9ed3e7d0dd | |||
| e2bed36c5f | |||
| 11cfcda4fb | |||
| 12213d83c4 | |||
| 24f26dd0ea | |||
| 3465563b27 | |||
| 42a5452fc5 | |||
| 56bc23375d | |||
| 05cd51ffc0 | |||
| bea4c1420b | |||
| 1c569b7358 | |||
| 3ece611ea0 | |||
| 604a9c198a | |||
| 8b03b33e22 | |||
| 0edc2c3b0b | |||
| 2e2b19d5e0 | |||
| 2bf5b18197 | |||
| 5e79bf8263 | |||
| 25b785c5ea | |||
| c1b8896799 | |||
| af5ed27902 | |||
| 9954efee98 | |||
| 5d806d1498 | |||
| 2dd03e4d2f | |||
| eb0c143166 | |||
| 6d70fad14b | |||
| a5362bd2ad | |||
| 0a8151f8fa | |||
| 437ee3066f | |||
| f5c709eb7b | |||
| 0a8d836d56 | |||
| c6cc191e17 | |||
| fd99e96d93 | |||
| 640e68d096 | |||
| cff935e633 | |||
| 1d64583697 | |||
| 7c7452a93d | |||
| 03882addc1 | |||
| 9ea81709eb | |||
| 27728a24a1 | |||
| ffbdd5aeb0 | |||
| 78ade08e65 | |||
| aeb90e106e | |||
| 4f91767c8a | |||
| bb94eba766 | |||
| 9e9cd03a21 | |||
| 7eeabdca79 | |||
| dcd7c36f66 | |||
| cf5a404b46 | |||
| e60c18c2e2 | |||
| 80370f11ae | |||
| b7ff089cca | |||
| 9bfa6dfee6 | |||
| 2b75e42c4c | |||
| 577b85627b | |||
| 067b7db2f0 | |||
| 0664a89c4d | |||
| 7684944246 | |||
| 198dac6ad0 | |||
| 724d5394d7 | |||
| 993daa4f82 | |||
| 9c9c1c024c | |||
| d873e7bb64 | |||
| 1962306282 | |||
| 05ce9a22ad | |||
| 589c441c83 | |||
| 5aaa26d503 | |||
| fbe54ad65a | |||
| d53d16071e | |||
| 5b9d311b06 | |||
| db609b47d8 | |||
| fa2186b407 | |||
| 58d28bceba | |||
| 85db13c885 | |||
| 41d8cb50dc | |||
| bbad0dc726 | |||
| bba583ae56 | |||
| cb30dc452d | |||
| dd761941cf | |||
| 94feb77a71 | |||
| 8eb1d22ae3 | |||
| 54b6d9d37e | |||
| 98c1a5facc | |||
| 1a6b176c24 | |||
| 9344c6fdd4 | |||
| ee4d3e7a84 | |||
| 7cfd5ce60b | |||
| 2f089ecaa3 | |||
| f1da9c28e7 | |||
| 812b27ca93 | |||
| 29998c6239 | |||
| ca1bbaa4f9 | |||
| 9d98983d26 | |||
| 442ee4da33 | |||
| bc3de1824d | |||
| 5f0d53fcb6 | |||
| dd0d0ec17b | |||
| cd2d3d10c4 | |||
| e77b18072c | |||
| fb8ccb5721 | |||
| 1207cdd105 | |||
| e36af0a49c | |||
| a983d70ffa | |||
| 417d0dc3be | |||
| bc8d6df5d0 | |||
| 1fb00ee19c | |||
| e2ff4baef5 | |||
| 662b2a0bed | |||
| f9694456f7 | |||
| 99f8dee269 | |||
| 9dd94ffac0 | |||
| cc74155226 | |||
| 3fc9f42378 | |||
| 6f03ba3720 | |||
| e5d7116cad | |||
| 73f791c8d9 | |||
| c3e42dbe33 | |||
| a80ecaa473 | |||
| f8ed2b6fd2 | |||
| e1c7a04ccc | |||
| 93771ebcf7 | |||
| 280ce76a8e | |||
| b3ea94db3d | |||
| 48e0e36f91 | |||
| 29bdb33466 | |||
| 5e5ba0b6fe | |||
| 21a509c6a5 | |||
| 80cb5d4c67 | |||
| f1c602abe5 | |||
| ac57eceb66 | |||
| e21d392ee2 | |||
| bca6d28542 | |||
| 19ef148991 | |||
| 9978d829ac | |||
| b3901bd430 | |||
| 0d545172d6 | |||
| 8f3773cda4 | |||
| 014ccf8f45 | |||
| f62c603ad4 | |||
| 66562b58d3 | |||
| 34fc82ea19 | |||
| 6d27151e6c | |||
| d69e3c6c1f | |||
| 392ea786d1 | |||
| 53590cd94e | |||
| 5812a41b2b | |||
| 81d9bc08f6 | |||
| b3d6c3e2e5 | |||
| b477c6f35d | |||
| 6d121c8879 | |||
| 9b7b7d52a4 | |||
| 0c8dc6f77b | |||
| d1ce756cc5 | |||
| 075459ad79 | |||
| 1dd6e356f8 | |||
| eaab071a1e | |||
| 53b6883a2c | |||
| 90a247746c | |||
| bf67fc98a7 | |||
| 67169a85d1 | |||
| d99f10fb6b | |||
| 43cea4a0dd | |||
| 487e925069 | |||
| 635a89fda9 | |||
| bf08964ff2 | |||
| 3f8b3e5c0f | |||
| d1c133309b | |||
| b0822f4076 | |||
| 8aed79ce43 | |||
| 5d1110b679 | |||
| 33a648d515 | |||
| eba4bd3735 | |||
| 712287785a | |||
| 6b8511da3d | |||
| 09cd04078c | |||
| ddec69a7d6 | |||
| 97d41e30b8 | |||
| f0acbcc8bf | |||
| 7a179602d7 | |||
| 0394771764 | |||
| ef2f2cc8e8 | |||
| 9a2af552d1 | |||
| 6bb2a4249e | |||
| 34f4f4b6d4 | |||
| 2eee8845b8 | |||
| fec98f1aa1 | |||
| a06e9c3435 | |||
| ba068613fa | |||
| 1b0e29aba8 | |||
| 8c2043198f | |||
| 5ce185cf01 | |||
| 7f2db62c47 | |||
| a40a3602b8 | |||
| 4e4c5ff6ee | |||
| 55ddbe917f |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -414,4 +414,5 @@ fabric.properties
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
celerybeat-schedule.db
|
||||
|
||||
|
||||
0
ArticlesApp/__init__.py
Normal file
0
ArticlesApp/__init__.py
Normal file
157
ArticlesApp/admin.py
Normal file
157
ArticlesApp/admin.py
Normal file
@@ -0,0 +1,157 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from django.contrib import admin
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from ArticlesApp.models import ArticleModel, UserPageModel
|
||||
from sets.admin import *
|
||||
|
||||
|
||||
# class Admin_ArticlesPageSets(Admin_BaseIconModel):
|
||||
#
|
||||
# fieldsets = (
|
||||
# (None, {
|
||||
# 'classes': ['wide'],
|
||||
# 'fields': (
|
||||
# 'name', 'url', 'description', 'picture'
|
||||
# )
|
||||
#
|
||||
#
|
||||
# }),
|
||||
# ('Управление отображением страницы', {
|
||||
# 'classes': ['wide'],
|
||||
# 'fields': (
|
||||
# # ('serviceBlockStateShow'),
|
||||
# # ('articlesCountInBlock'),
|
||||
# # ('advicesCountInBlock'),
|
||||
# )
|
||||
# }),
|
||||
#
|
||||
# ('SEO', {
|
||||
# 'classes': ['wide', 'collapse'],
|
||||
# 'fields': ('seo_title', 'seo_description','seo_keywords', 'seo_text')
|
||||
# }),
|
||||
#
|
||||
# )
|
||||
#
|
||||
# prepopulated_fields = {"url": ("name",)}
|
||||
# list_display = ('name', 'url', 'seo_title', 'createDT')
|
||||
# # list_editable = ('dish_price', 'allowForDelivery', 'dish_maxDiscount','dish_rating',
|
||||
# # 'dish_enabled')
|
||||
# # filter_horizontal = ['service_works',]
|
||||
# # date_hierarchy = 'createDT'
|
||||
# # list_filter = ('device_name', 'vendor',)
|
||||
# list_display_links = ('name',)
|
||||
# save_on_top = True
|
||||
#
|
||||
# def has_add_permission(self, request):
|
||||
# return not ArticlesPageSets.objects.all().count() > 0
|
||||
#
|
||||
# def has_delete_permission(self, request, obj=None):
|
||||
# if not request.user.is_superuser:
|
||||
# return False
|
||||
# else:
|
||||
# return True
|
||||
#
|
||||
# admin.site.register(ArticlesPageSets,Admin_ArticlesPageSets)
|
||||
|
||||
|
||||
|
||||
|
||||
class Admin_Article(Admin_Trans_BaseModelViewPage):
|
||||
|
||||
fieldsets = (
|
||||
(None, {
|
||||
'classes': ['wide'],
|
||||
'fields': (('name'),
|
||||
('url'),
|
||||
# 'pub_DT',
|
||||
'picture',
|
||||
# ('devices'),
|
||||
)
|
||||
}),
|
||||
(_('Статья'), {
|
||||
'classes': ['wide'],
|
||||
'fields': (
|
||||
'description', 'text',
|
||||
)
|
||||
}),
|
||||
|
||||
('SEO', {
|
||||
'classes': ['wide', 'collapse'],
|
||||
'fields': ('seo_title', 'seo_description','seo_keywords')
|
||||
}),
|
||||
|
||||
)
|
||||
|
||||
prepopulated_fields = {"url": ("name",)}
|
||||
list_display = (
|
||||
# 'image_thumb',
|
||||
'name', 'url', 'order', 'createDT')
|
||||
list_editable = ('order',) # 'allowForDelivery', 'dish_maxDiscount','dish_rating',
|
||||
# 'dish_enabled')
|
||||
# filter_horizontal = ['sites']
|
||||
date_hierarchy = 'createDT'
|
||||
list_filter = ('enable', 'createDT')
|
||||
list_display_links = (
|
||||
'name',
|
||||
# 'image_thumb',
|
||||
)
|
||||
save_on_top = True
|
||||
|
||||
admin.site.register(ArticleModel, Admin_Article)
|
||||
|
||||
# class Admin_ArticleSliders(admin.TabularInline):
|
||||
# model = ArticleModel.SliderSets.through
|
||||
|
||||
|
||||
class Admin_UserPage(Admin_Trans_BaseModelViewPage):
|
||||
|
||||
fieldsets = (
|
||||
(None, {
|
||||
'classes': ['wide'],
|
||||
'fields': (('name'),
|
||||
('url'),
|
||||
# 'pub_DT',
|
||||
# ('devices'),
|
||||
)
|
||||
}),
|
||||
(_('Статья'), {
|
||||
'classes': ['wide'],
|
||||
'fields': ('picture', 'description', 'text')
|
||||
}),
|
||||
|
||||
('SEO', {
|
||||
'classes': ['wide', 'collapse'],
|
||||
'fields': ('seo_title', 'seo_description','seo_keywords')
|
||||
}),
|
||||
|
||||
)
|
||||
|
||||
prepopulated_fields = {"url": ("name",)}
|
||||
list_display = (
|
||||
# 'image_thumb',
|
||||
'name', 'url', 'order', 'seo_title', 'createDT')
|
||||
list_editable = ('order', ) # 'allowForDelivery', 'dish_maxDiscount','dish_rating',
|
||||
# 'dish_enabled')
|
||||
# filter_horizontal = ['sites']
|
||||
date_hierarchy = 'createDT'
|
||||
list_filter = ('enable', 'createDT')
|
||||
list_display_links = (
|
||||
'name',
|
||||
# 'image_thumb',
|
||||
)
|
||||
save_on_top = True
|
||||
|
||||
actions = ['create_copy']
|
||||
|
||||
|
||||
|
||||
def has_delete_permission(self, request, obj=None):
|
||||
if request.user.is_superuser:
|
||||
return True
|
||||
|
||||
if obj and obj.url in ('for-partners', 'dealers', 'contacts'):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
admin.site.register(UserPageModel,Admin_UserPage)
|
||||
45
ArticlesApp/funcs.py
Normal file
45
ArticlesApp/funcs.py
Normal file
@@ -0,0 +1,45 @@
|
||||
from .models import *
|
||||
|
||||
|
||||
elements_on_page = 10
|
||||
|
||||
def get_articles(art_kwargs, request_Data=None, from_el=None, to_el=None):
|
||||
|
||||
if request_Data:
|
||||
if not from_el and 'from_el' in request_Data:
|
||||
from_el = request_Data['from_el']
|
||||
|
||||
if not to_el and 'to_el' in request_Data:
|
||||
to_el = request_Data['to_el']
|
||||
|
||||
arts = ArticleModel.objects.filter(**art_kwargs).order_by('-createDT')
|
||||
el_count = arts.count()
|
||||
|
||||
if from_el and to_el:
|
||||
arts = arts[from_el:to_el]
|
||||
elif from_el:
|
||||
arts = arts[from_el:]
|
||||
elif to_el:
|
||||
arts = arts[:to_el]
|
||||
else:
|
||||
to_el = elements_on_page
|
||||
arts = arts[:to_el]
|
||||
|
||||
last_block = False
|
||||
if not to_el or to_el >= el_count:
|
||||
last_block = True
|
||||
|
||||
if el_count - to_el > elements_on_page:
|
||||
next_page_els_count = elements_on_page
|
||||
else:
|
||||
next_page_els_count = el_count - to_el
|
||||
|
||||
Dict = {
|
||||
'articles': arts,
|
||||
'last_block': last_block,
|
||||
'last_el': to_el,
|
||||
'next_page_els_count': next_page_els_count,
|
||||
'elements_on_page': elements_on_page
|
||||
}
|
||||
|
||||
return Dict
|
||||
10
ArticlesApp/js_urls.py
Normal file
10
ArticlesApp/js_urls.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# coding=utf-8
|
||||
from django.urls import path
|
||||
# from AuthApp.js_views import *
|
||||
# from AuthApp.import_funcs import *
|
||||
from .js_views import *
|
||||
|
||||
urlpatterns = [
|
||||
path('get_articles_block/', get_articles_block_ajax, name='get_articles_block_ajax'),
|
||||
|
||||
]
|
||||
55
ArticlesApp/js_views.py
Normal file
55
ArticlesApp/js_views.py
Normal file
@@ -0,0 +1,55 @@
|
||||
import json
|
||||
|
||||
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.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 django.template.loader import render_to_string
|
||||
from django.urls import reverse
|
||||
# from .forms import *
|
||||
from .funcs import *
|
||||
|
||||
def get_articles_block_ajax(request):
|
||||
|
||||
if request.method != 'POST':
|
||||
raise Http404
|
||||
|
||||
try:
|
||||
|
||||
data = request.POST.dict()
|
||||
if not data and request.body:
|
||||
data = json.loads(request.body)
|
||||
|
||||
art_kwargs = {}
|
||||
|
||||
Dict = get_articles(art_kwargs=art_kwargs, request_Data=data)
|
||||
if 'errors' in Dict:
|
||||
return JsonResponse(Dict, status=400)
|
||||
|
||||
html = render_to_string('blocks/articles/b_news_elements.html', Dict, request=request)
|
||||
|
||||
res_Dict = {
|
||||
'html': html,
|
||||
'last_block': Dict['last_block'],
|
||||
'next_page_els_count': Dict['next_page_els_count'],
|
||||
# 'form': RouteForm(initial=data)
|
||||
}
|
||||
|
||||
return JsonResponse(res_Dict)
|
||||
|
||||
except Exception as e:
|
||||
|
||||
|
||||
errors_Dict = {
|
||||
'errors': {
|
||||
'all__': f'{_("ошибка в запросе")} = {str(e)}'
|
||||
}
|
||||
}
|
||||
return JsonResponse(errors_Dict, status=400)
|
||||
103
ArticlesApp/migrations/0001_initial.py
Normal file
103
ArticlesApp/migrations/0001_initial.py
Normal file
@@ -0,0 +1,103 @@
|
||||
# Generated by Django 4.2.2 on 2023-08-28 17:17
|
||||
|
||||
import ckeditor.fields
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ArticleModel',
|
||||
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='Дополнительные данные')),
|
||||
('url', models.TextField(help_text='можно изменить адрес страницы (!!! ВНИМАНИЕ !!! поисковые системы потеряют страницу и найдут лишь спустя неделю...месяц)', unique=True, verbose_name='URL привязанной страницы')),
|
||||
('title', models.TextField(blank=True, null=True, verbose_name='Заголовок')),
|
||||
('description', ckeditor.fields.RichTextField(blank=True, help_text='краткое описание страницы (до 240 символов)', null=True, verbose_name='Краткое описание')),
|
||||
('description_ru', ckeditor.fields.RichTextField(blank=True, help_text='краткое описание страницы (до 240 символов)', null=True, verbose_name='Краткое описание')),
|
||||
('description_en', ckeditor.fields.RichTextField(blank=True, help_text='краткое описание страницы (до 240 символов)', null=True, verbose_name='Краткое описание')),
|
||||
('picture', models.ImageField(blank=True, null=True, upload_to='uploads/', verbose_name='Картинка')),
|
||||
('visible', models.BooleanField(default=True, verbose_name='Отображать')),
|
||||
('background_image_left', models.ImageField(blank=True, null=True, upload_to='', verbose_name='Левая подложка')),
|
||||
('background_image_right', models.ImageField(blank=True, null=True, upload_to='', verbose_name='Правая подложка')),
|
||||
('seo_title', models.CharField(blank=True, max_length=250, null=True, verbose_name='Title (80 знаков)')),
|
||||
('seo_title_ru', models.CharField(blank=True, max_length=250, null=True, verbose_name='Title (80 знаков)')),
|
||||
('seo_title_en', models.CharField(blank=True, max_length=250, null=True, verbose_name='Title (80 знаков)')),
|
||||
('seo_description', models.CharField(blank=True, max_length=250, null=True, verbose_name='Description (150 знаков)')),
|
||||
('seo_description_ru', models.CharField(blank=True, max_length=250, null=True, verbose_name='Description (150 знаков)')),
|
||||
('seo_description_en', models.CharField(blank=True, max_length=250, null=True, verbose_name='Description (150 знаков)')),
|
||||
('seo_keywords', models.CharField(blank=True, max_length=250, null=True, verbose_name='Keywords (200 знаков)')),
|
||||
('seo_keywords_ru', models.CharField(blank=True, max_length=250, null=True, verbose_name='Keywords (200 знаков)')),
|
||||
('seo_keywords_en', models.CharField(blank=True, max_length=250, null=True, verbose_name='Keywords (200 знаков)')),
|
||||
('seo_text', ckeditor.fields.RichTextField(blank=True, null=True, verbose_name='Текст SEO статьи')),
|
||||
('seo_text_ru', ckeditor.fields.RichTextField(blank=True, null=True, verbose_name='Текст SEO статьи')),
|
||||
('seo_text_en', ckeditor.fields.RichTextField(blank=True, null=True, verbose_name='Текст SEO статьи')),
|
||||
('FAQ_title', models.CharField(blank=True, max_length=250, null=True, verbose_name='FAQ Заголовок')),
|
||||
('text', ckeditor.fields.RichTextField(verbose_name='Текст')),
|
||||
('text_ru', ckeditor.fields.RichTextField(null=True, verbose_name='Текст')),
|
||||
('text_en', ckeditor.fields.RichTextField(null=True, verbose_name='Текст')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Статья',
|
||||
'verbose_name_plural': 'Статьи',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='UserPageModel',
|
||||
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='Дополнительные данные')),
|
||||
('url', models.TextField(help_text='можно изменить адрес страницы (!!! ВНИМАНИЕ !!! поисковые системы потеряют страницу и найдут лишь спустя неделю...месяц)', unique=True, verbose_name='URL привязанной страницы')),
|
||||
('title', models.TextField(blank=True, null=True, verbose_name='Заголовок')),
|
||||
('description', ckeditor.fields.RichTextField(blank=True, help_text='краткое описание страницы (до 240 символов)', null=True, verbose_name='Краткое описание')),
|
||||
('description_ru', ckeditor.fields.RichTextField(blank=True, help_text='краткое описание страницы (до 240 символов)', null=True, verbose_name='Краткое описание')),
|
||||
('description_en', ckeditor.fields.RichTextField(blank=True, help_text='краткое описание страницы (до 240 символов)', null=True, verbose_name='Краткое описание')),
|
||||
('picture', models.ImageField(blank=True, null=True, upload_to='uploads/', verbose_name='Картинка')),
|
||||
('visible', models.BooleanField(default=True, verbose_name='Отображать')),
|
||||
('background_image_left', models.ImageField(blank=True, null=True, upload_to='', verbose_name='Левая подложка')),
|
||||
('background_image_right', models.ImageField(blank=True, null=True, upload_to='', verbose_name='Правая подложка')),
|
||||
('seo_title', models.CharField(blank=True, max_length=250, null=True, verbose_name='Title (80 знаков)')),
|
||||
('seo_title_ru', models.CharField(blank=True, max_length=250, null=True, verbose_name='Title (80 знаков)')),
|
||||
('seo_title_en', models.CharField(blank=True, max_length=250, null=True, verbose_name='Title (80 знаков)')),
|
||||
('seo_description', models.CharField(blank=True, max_length=250, null=True, verbose_name='Description (150 знаков)')),
|
||||
('seo_description_ru', models.CharField(blank=True, max_length=250, null=True, verbose_name='Description (150 знаков)')),
|
||||
('seo_description_en', models.CharField(blank=True, max_length=250, null=True, verbose_name='Description (150 знаков)')),
|
||||
('seo_keywords', models.CharField(blank=True, max_length=250, null=True, verbose_name='Keywords (200 знаков)')),
|
||||
('seo_keywords_ru', models.CharField(blank=True, max_length=250, null=True, verbose_name='Keywords (200 знаков)')),
|
||||
('seo_keywords_en', models.CharField(blank=True, max_length=250, null=True, verbose_name='Keywords (200 знаков)')),
|
||||
('seo_text', ckeditor.fields.RichTextField(blank=True, null=True, verbose_name='Текст SEO статьи')),
|
||||
('seo_text_ru', ckeditor.fields.RichTextField(blank=True, null=True, verbose_name='Текст SEO статьи')),
|
||||
('seo_text_en', ckeditor.fields.RichTextField(blank=True, null=True, verbose_name='Текст SEO статьи')),
|
||||
('FAQ_title', models.CharField(blank=True, max_length=250, null=True, verbose_name='FAQ Заголовок')),
|
||||
('text', ckeditor.fields.RichTextField(verbose_name='Текст')),
|
||||
('text_ru', ckeditor.fields.RichTextField(null=True, verbose_name='Текст')),
|
||||
('text_en', ckeditor.fields.RichTextField(null=True, verbose_name='Текст')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Пользовательская страница',
|
||||
'verbose_name_plural': 'Пользовательские страницы',
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,104 @@
|
||||
# Generated by Django 4.2.2 on 2023-09-22 13:29
|
||||
|
||||
import ckeditor_uploader.fields
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('ArticlesApp', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='articlemodel',
|
||||
name='description',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, help_text='краткое описание страницы (до 240 символов)', null=True, verbose_name='Краткое описание'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='articlemodel',
|
||||
name='description_en',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, help_text='краткое описание страницы (до 240 символов)', null=True, verbose_name='Краткое описание'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='articlemodel',
|
||||
name='description_ru',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, help_text='краткое описание страницы (до 240 символов)', null=True, verbose_name='Краткое описание'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='articlemodel',
|
||||
name='seo_text',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, null=True, verbose_name='Текст SEO статьи'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='articlemodel',
|
||||
name='seo_text_en',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, null=True, verbose_name='Текст SEO статьи'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='articlemodel',
|
||||
name='seo_text_ru',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, null=True, verbose_name='Текст SEO статьи'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='articlemodel',
|
||||
name='text',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(verbose_name='Текст'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='articlemodel',
|
||||
name='text_en',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(null=True, verbose_name='Текст'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='articlemodel',
|
||||
name='text_ru',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(null=True, verbose_name='Текст'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='userpagemodel',
|
||||
name='description',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, help_text='краткое описание страницы (до 240 символов)', null=True, verbose_name='Краткое описание'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='userpagemodel',
|
||||
name='description_en',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, help_text='краткое описание страницы (до 240 символов)', null=True, verbose_name='Краткое описание'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='userpagemodel',
|
||||
name='description_ru',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, help_text='краткое описание страницы (до 240 символов)', null=True, verbose_name='Краткое описание'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='userpagemodel',
|
||||
name='seo_text',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, null=True, verbose_name='Текст SEO статьи'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='userpagemodel',
|
||||
name='seo_text_en',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, null=True, verbose_name='Текст SEO статьи'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='userpagemodel',
|
||||
name='seo_text_ru',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, null=True, verbose_name='Текст SEO статьи'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='userpagemodel',
|
||||
name='text',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(verbose_name='Текст'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='userpagemodel',
|
||||
name='text_en',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(null=True, verbose_name='Текст'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='userpagemodel',
|
||||
name='text_ru',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(null=True, verbose_name='Текст'),
|
||||
),
|
||||
]
|
||||
0
ArticlesApp/migrations/__init__.py
Normal file
0
ArticlesApp/migrations/__init__.py
Normal file
38
ArticlesApp/models.py
Normal file
38
ArticlesApp/models.py
Normal file
@@ -0,0 +1,38 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
__author__ = 'sync'
|
||||
|
||||
from django.db import models
|
||||
|
||||
from BaseModels.base_models import BaseModelViewPage, BaseModel
|
||||
# from ckeditor.fields import RichTextField
|
||||
from ckeditor_uploader.fields import RichTextUploadingField
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
||||
# class ArticlesPageSets(BaseModelViewPage):
|
||||
#
|
||||
# class Meta:
|
||||
# verbose_name = 'Настройки страницы архива статей'
|
||||
# verbose_name_plural = 'Настройки страницы архива статей'
|
||||
|
||||
|
||||
class UserPageModel(BaseModelViewPage):
|
||||
# pub_DT = models.DateTimeField(verbose_name=u'Дата и время публикации', auto_created=True)
|
||||
text = RichTextUploadingField(verbose_name=_('Текст'))
|
||||
|
||||
class Meta:
|
||||
verbose_name=_("Пользовательская страница")
|
||||
verbose_name_plural =_("Пользовательские страницы")
|
||||
# unique_together = ('url', 'region')
|
||||
# managed=True
|
||||
# app_label = u'ArticlesApp'
|
||||
|
||||
|
||||
class ArticleModel(BaseModelViewPage):
|
||||
# pub_DT = models.DateTimeField(verbose_name=u'Дата и время публикации', auto_created=True)
|
||||
text = RichTextUploadingField(verbose_name=_("Текст"))
|
||||
|
||||
class Meta:
|
||||
verbose_name=_("Статья")
|
||||
verbose_name_plural =_("Статьи")
|
||||
1
ArticlesApp/templatetags/__init__.py
Normal file
1
ArticlesApp/templatetags/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
__author__ = 'SDE'
|
||||
48
ArticlesApp/templatetags/arts_tags_extra.py
Normal file
48
ArticlesApp/templatetags/arts_tags_extra.py
Normal file
@@ -0,0 +1,48 @@
|
||||
__author__ = 'SDE'
|
||||
|
||||
from django import template
|
||||
from django.template.defaultfilters import stringfilter
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
# @register.filter('get_side_art')
|
||||
@register.simple_tag
|
||||
def get_side_art(last_el, counter, els_on_page):
|
||||
cur_el = last_el - els_on_page + counter
|
||||
if els_on_page < 4:
|
||||
first_left_el = els_on_page + 1
|
||||
else:
|
||||
first_left_el = 4
|
||||
if (cur_el - first_left_el) % 2:
|
||||
return 'even'
|
||||
else:
|
||||
return 'odd'
|
||||
|
||||
# @register.filter()
|
||||
# def get_numbers_list(from_el, to_el):
|
||||
# res = range(from_el, to_el+1)
|
||||
# return res
|
||||
#
|
||||
#
|
||||
# def val_type(value):
|
||||
# res = type(value)
|
||||
# return res.__name__
|
||||
# register.filter('val_type', val_type)
|
||||
#
|
||||
# @register.filter()
|
||||
# def get_cols_table_data_for_row_when_cols3(value, row):
|
||||
# el_count = 3
|
||||
# from_el = (row-1) * el_count
|
||||
# to_el = row * el_count
|
||||
# part = list(value)[from_el:to_el]
|
||||
# return part
|
||||
# # register.filter('val_type', val_type)
|
||||
#
|
||||
#
|
||||
# @register.filter
|
||||
# @stringfilter
|
||||
# def correct_for_tables(value):
|
||||
# if value in ['None', '0.0']:
|
||||
# return '-'
|
||||
# return value
|
||||
16
ArticlesApp/tests.py
Normal file
16
ArticlesApp/tests.py
Normal 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)
|
||||
26
ArticlesApp/translation.py
Normal file
26
ArticlesApp/translation.py
Normal file
@@ -0,0 +1,26 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from modeltranslation.translator import translator, TranslationOptions, register
|
||||
from .models import *
|
||||
|
||||
@register(ArticleModel)
|
||||
class Article_TranslationOptions(TranslationOptions):
|
||||
|
||||
fields = (
|
||||
'name', 'description', 'seo_title', 'seo_description', 'seo_keywords', 'seo_text',
|
||||
'text'
|
||||
)
|
||||
|
||||
# translator.register(ArticleModel, Article_TranslationOptions)
|
||||
|
||||
|
||||
|
||||
@register(UserPageModel)
|
||||
class UserPage_TranslationOptions(TranslationOptions):
|
||||
|
||||
fields = (
|
||||
'name', 'description', 'seo_title', 'seo_description', 'seo_keywords', 'seo_text',
|
||||
'text'
|
||||
)
|
||||
|
||||
# translator.register(UserPageModel, UserPage_TranslationOptions)
|
||||
5
ArticlesApp/urls.py
Normal file
5
ArticlesApp/urls.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from django.urls import path
|
||||
from .views import *
|
||||
|
||||
urlpatterns = [
|
||||
]
|
||||
9
ArticlesApp/urls_translate.py
Normal file
9
ArticlesApp/urls_translate.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from django.urls import path
|
||||
from .views import *
|
||||
|
||||
urlpatterns = [
|
||||
path('articles/', ArticlesPageView, name=u'articles'),
|
||||
path('articles/<int:year>/', ArticlesPageView, name=u'articles_by_year'),
|
||||
path('article/<str:art_url>/', ArticlesOnePageView, name=u'article_one'),
|
||||
path('info_page/<str:page_url>/', UserPageView, name=u'user_page'),
|
||||
]
|
||||
159
ArticlesApp/views.py
Normal file
159
ArticlesApp/views.py
Normal file
@@ -0,0 +1,159 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from .models import *
|
||||
|
||||
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 django.utils.translation import gettext_lazy as _
|
||||
|
||||
# from django.contrib.auth.decorators import login_required
|
||||
# from BaseModels.search_optimization.ld_json.ld_article_news import get_ld_article_news
|
||||
# from django.contrib.sites.shortcuts import get_current_site
|
||||
|
||||
|
||||
|
||||
def get_flat_pages_links_Dict(site):
|
||||
|
||||
flat_pages_links = UserPageModel.objects.filter(
|
||||
url__in=('for-partners', 'contacts'),
|
||||
sites=site
|
||||
).values_list('url', flat=True)
|
||||
|
||||
return {'flat_pages_links': flat_pages_links}
|
||||
|
||||
|
||||
|
||||
def get_article_breadcrumbs(request, art):
|
||||
# print('get_article_breadcrumbs')
|
||||
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]
|
||||
# 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 = {
|
||||
'breadcrumbs_arts': breadcrumbs_arts
|
||||
# 'arts_top': arts_top,
|
||||
# 'arts_down': arts_down
|
||||
}
|
||||
return Dict
|
||||
|
||||
|
||||
def get_user_pages_breadcrumbs(request, art):
|
||||
from ArticlesApp.models import UserPageModel
|
||||
# print('get_user_pages_breadcrumbs')
|
||||
half_count = art.articlesCountInBlock / 2
|
||||
|
||||
art_List = UserPageModel.objects.filter(enable=True, article_DT__gte=art.article_DT).order_by(
|
||||
'article_DT')[:half_count]
|
||||
artListDown = UserPageModel.objects.filter(enable=True, article_DT__lt=art.article_DT).order_by(
|
||||
'-article_DT')[:art.articlesCountInBlock-len(art_List)]
|
||||
if len(artListDown)<half_count:
|
||||
art_List = UserPageModel.objects.filter(enable=True, article_DT__gte=art.article_DT).order_by(
|
||||
'article_DT')[:art.articlesCountInBlock-len(artListDown)]
|
||||
|
||||
art_List = list(art_List)
|
||||
art_List.reverse()
|
||||
artlist = art_List + list(artListDown)
|
||||
# print('artlist',artlist)
|
||||
return artlist
|
||||
|
||||
|
||||
# @login_required(login_url='/admin/')
|
||||
def ArticlesPageView(request, year=None):
|
||||
|
||||
kwargs = {}
|
||||
|
||||
if year:
|
||||
try:
|
||||
year = int(year)
|
||||
kwargs.update({'createDT__year': year})
|
||||
except:
|
||||
raise Http404
|
||||
|
||||
|
||||
Dict = get_articles(art_kwargs=kwargs)
|
||||
Dict.update({
|
||||
'page': {
|
||||
'title': _('Страница списка новостей'),
|
||||
'description': _('Все новости сайта tripwb.com'),
|
||||
'keywords': _('Все новости сайта tripwb.com'),
|
||||
}
|
||||
})
|
||||
|
||||
t = loader.get_template('pages/p_articles.html')
|
||||
return get_inter_http_respose(t, Dict, request)
|
||||
# return HttpResponse(t.render(Dict, request))
|
||||
|
||||
|
||||
|
||||
# @login_required(login_url='/admin/')
|
||||
def UserPageView(request, page_url):
|
||||
|
||||
|
||||
kwargs = {
|
||||
'url': page_url
|
||||
}
|
||||
|
||||
try:
|
||||
art = UserPageModel.objects.get(**kwargs)
|
||||
except UserPageModel.DoesNotExist:
|
||||
raise Http404
|
||||
|
||||
# service = ServiceModel.objects.filter(enable=True, artDevs=art)[0]
|
||||
|
||||
# article_breadcrumbs = get_user_pages_breadcrumbs(request,art)
|
||||
# print('article_breadcrumbs',article_breadcrumbs)
|
||||
|
||||
Dict = {
|
||||
'page' : art,
|
||||
'user_page' : True,
|
||||
# 'service' : service,
|
||||
# 'article_breadcrumbs' : article_breadcrumbs
|
||||
}
|
||||
|
||||
|
||||
|
||||
t = loader.get_template('pages/p_user_page.html')
|
||||
return get_inter_http_respose(t, Dict, request)
|
||||
# return HttpResponse(t.render(Dict, request))
|
||||
|
||||
|
||||
|
||||
# @login_required(login_url='/admin/')
|
||||
def ArticlesOnePageView(request, art_url):
|
||||
|
||||
kwargs = {
|
||||
'url': art_url
|
||||
}
|
||||
|
||||
try:
|
||||
art = ArticleModel.objects.get(**kwargs)
|
||||
except ArticleModel.DoesNotExist:
|
||||
raise Http404
|
||||
|
||||
|
||||
|
||||
# print('article_breadcrumbs',article_breadcrumbs)
|
||||
|
||||
Dict = {
|
||||
'page' : art,
|
||||
}
|
||||
|
||||
Dict.update(get_article_breadcrumbs(request, art))
|
||||
|
||||
|
||||
|
||||
t = loader.get_template('pages/p_article.html')
|
||||
return get_inter_http_respose(t, Dict, request)
|
||||
# return HttpResponse(t.render(Dict, request))
|
||||
@@ -39,16 +39,17 @@ class Admin_ProfileInline(admin.StackedInline):
|
||||
(None, {
|
||||
'classes': ['wide'],
|
||||
'fields': (
|
||||
('account_type',),
|
||||
# ('account_type',),
|
||||
('enable',),
|
||||
('phone',),
|
||||
('country', 'city'),
|
||||
('mailing_on', ),
|
||||
('authMailCode',),
|
||||
('birthdate'),
|
||||
'comment', 'creator'
|
||||
)
|
||||
}),
|
||||
('Дополнительно', {
|
||||
(_('Дополнительно'), {
|
||||
'classes': ['wide'],
|
||||
'fields': (
|
||||
('json_data',)
|
||||
@@ -71,6 +72,10 @@ class Admin_ProfileInline(admin.StackedInline):
|
||||
|
||||
class Admin_User(UserAdmin):
|
||||
|
||||
def mailing_on(self, obj):
|
||||
return obj.user_profile.mailing_on
|
||||
mailing_on.boolean = True
|
||||
|
||||
fieldsets = (
|
||||
(None, {
|
||||
'classes': ['wide'],
|
||||
@@ -91,61 +96,63 @@ class Admin_User(UserAdmin):
|
||||
|
||||
save_on_top = True
|
||||
|
||||
list_display = ['id', 'last_name', 'first_name', 'email', 'is_staff',
|
||||
list_display = ['id', 'last_name', 'first_name', 'mailing_on', 'email', 'is_staff',
|
||||
'is_active']
|
||||
list_editable = ['is_staff', 'is_active']
|
||||
list_display_links = ['first_name', 'last_name', 'email']
|
||||
search_fields = ['first_name', 'last_name', 'email']
|
||||
|
||||
list_filter = ['user_profile__mailing_on', 'is_staff', 'is_active']
|
||||
|
||||
inlines = (Admin_ProfileInline,)
|
||||
# actions = ['del_all_temp_users', ]
|
||||
|
||||
ordering = ['is_staff', 'last_name', 'first_name']
|
||||
ordering = ['is_staff', '-id', 'last_name', 'first_name']
|
||||
|
||||
# Re-register UserAdmin
|
||||
admin.site.unregister(User)
|
||||
admin.site.register(User, Admin_User)
|
||||
|
||||
|
||||
class Admin_UserProfile(Admin_BaseIconModel):
|
||||
|
||||
fieldsets = (
|
||||
(None, {
|
||||
'classes': ['wide'],
|
||||
'fields': (
|
||||
'user', 'enable',
|
||||
('account_type',),
|
||||
('phone',),
|
||||
('country', 'city'),
|
||||
('authMailCode',),
|
||||
('birthdate'),
|
||||
'creator'
|
||||
)
|
||||
}),
|
||||
('1С', {
|
||||
'classes': ['wide'],
|
||||
'fields': (
|
||||
('id_1s', 'name',),
|
||||
)
|
||||
}),
|
||||
)
|
||||
|
||||
save_on_top = True
|
||||
|
||||
list_display = [
|
||||
'id', 'user', 'enable', 'birthdate', 'modifiedDT', 'createDT'
|
||||
]
|
||||
list_editable = ['enable', 'birthdate']
|
||||
list_display_links = ['id', ] # 'user__last_name', 'user__first_name']
|
||||
search_fields = [
|
||||
'id', 'user__last_name', 'user__first_name', 'user__email',
|
||||
]
|
||||
|
||||
list_filter = ['enable', 'account_type']
|
||||
|
||||
# filter_horizontal = ['connected_mailings']
|
||||
# raw_id_fields = ("favourites",)
|
||||
verbose_name_plural = _(u'Профиль пользователя')
|
||||
|
||||
|
||||
admin.site.register(UserProfile, Admin_UserProfile)
|
||||
# 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)
|
||||
|
||||
@@ -14,17 +14,78 @@ class LoginForm(forms.Form):
|
||||
username = forms.CharField(required=True)
|
||||
password = forms.CharField(required=True)
|
||||
|
||||
|
||||
|
||||
class RegistrationForm(forms.Form):
|
||||
from .models import account_type_choices
|
||||
account_type = forms.ChoiceField(choices=account_type_choices, initial='sender', required=True)
|
||||
# account_type = forms.ChoiceField(choices=account_type_choices, initial='sender', required=True)
|
||||
firstname = forms.CharField(required=False)
|
||||
lastname = forms.CharField(required=False)
|
||||
country = forms.CharField(required=False)
|
||||
city = forms.CharField(required=False)
|
||||
email = forms.EmailField()
|
||||
password = forms.CharField(widget=forms.PasswordInput())
|
||||
confirm_password = forms.CharField(widget=forms.PasswordInput())
|
||||
tel = forms.CharField()
|
||||
agreement = forms.BooleanField(initial=False, required=True)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
required_password = True
|
||||
required_agreement = True
|
||||
required_email = True
|
||||
create_new_account = True
|
||||
if 'not_required_password' in kwargs.keys() and kwargs['not_required_password']:
|
||||
required_password = False
|
||||
del kwargs['not_required_password']
|
||||
if 'not_required_agreement' in kwargs.keys() and kwargs['not_required_agreement']:
|
||||
required_agreement = False
|
||||
del kwargs['not_required_agreement']
|
||||
if 'not_required_email' in kwargs.keys() and kwargs['not_required_email']:
|
||||
required_email = False
|
||||
del kwargs['not_required_email']
|
||||
if 'create_new_account' in kwargs.keys() and not kwargs['create_new_account']:
|
||||
create_new_account = False
|
||||
del kwargs['create_new_account']
|
||||
|
||||
super(RegistrationForm, self).__init__(*args, **kwargs)
|
||||
|
||||
self.fields['password'].required = required_password
|
||||
self.fields['confirm_password'].required = required_password
|
||||
|
||||
self.fields['agreement'].required = required_agreement
|
||||
|
||||
self.fields['email'].required = required_email
|
||||
|
||||
self.create_new_account = create_new_account
|
||||
|
||||
def clean(self):
|
||||
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 уже существует"))
|
||||
|
||||
|
||||
|
||||
|
||||
# # class PersonForm(NgModelFormMixin, NgFormValidationMixin, NgModelForm, Bootstrap3ModelForm):
|
||||
# #
|
||||
|
||||
96
AuthApp/funcs.py
Normal file
96
AuthApp/funcs.py
Normal file
@@ -0,0 +1,96 @@
|
||||
from django.template.loader import render_to_string
|
||||
|
||||
|
||||
def get_user_timezone_Dict(user, request=None):
|
||||
tz = None
|
||||
if request:
|
||||
tz = request.COOKIES.get("user_tz")
|
||||
if not tz and user.is_authenticated:
|
||||
tz = user.user_profile.get_timezone()
|
||||
|
||||
if not tz:
|
||||
from django.conf import settings
|
||||
tz = settings.TIME_ZONE
|
||||
|
||||
return {'user_tz': tz}
|
||||
|
||||
def get_dashboard_page_content_html(request):
|
||||
|
||||
from ChatServiceApp.funcs import get_unanswered_msgs_count_for_user
|
||||
|
||||
Dict = {
|
||||
'unanswered_msgs_count': get_unanswered_msgs_count_for_user(request.user)
|
||||
}
|
||||
|
||||
html = render_to_string('blocks/profile/b_profile_first_page.html', Dict, request=request)
|
||||
return html
|
||||
|
||||
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':
|
||||
from RoutesApp.funcs import get_profile_new_route_page_html
|
||||
return get_profile_new_route_page_html(request, {'owner_type': 'customer'})
|
||||
elif page_name == 'create_route_for_mover':
|
||||
from RoutesApp.funcs import get_profile_new_route_page_html
|
||||
return get_profile_new_route_page_html(request, {'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)
|
||||
elif page_name == 'change_profile':
|
||||
return get_profile_change_page_content_html(request)
|
||||
elif page_name == 'dashboard':
|
||||
return get_dashboard_page_content_html(request)
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def get_profile_change_page_content_html(request):
|
||||
|
||||
init_Dict = {
|
||||
'firstname': request.user.first_name,
|
||||
'lastname': request.user.last_name,
|
||||
'email': request.user.email,
|
||||
'tel': request.user.user_profile.phone,
|
||||
'country': request.user.user_profile.country,
|
||||
'city': request.user.user_profile.city,
|
||||
}
|
||||
from .forms import RegistrationForm
|
||||
form = RegistrationForm(initial=init_Dict)
|
||||
|
||||
from SubscribesApp.funcs import get_cur_user_subscribe
|
||||
|
||||
Dict = {
|
||||
'profileForm': form,
|
||||
'user_subscribe': get_cur_user_subscribe(request.user)
|
||||
}
|
||||
|
||||
html = render_to_string('blocks/profile/b_profile.html', Dict, request=request)
|
||||
return html
|
||||
|
||||
|
||||
def get_profile_support_page_content_html(request, data=None):
|
||||
if request.user.is_staff:
|
||||
from ChatServiceApp.funcs import get_ticketsDict_for_staff
|
||||
Dict = get_ticketsDict_for_staff(request.user)
|
||||
tpl_name = 'blocks/profile/b_support_chat.html'
|
||||
else:
|
||||
from ChatServiceApp.models import MsgGroup
|
||||
tickets = MsgGroup.objects.filter(enable=True, owner=request.user).order_by('-modifiedDT')
|
||||
|
||||
Dict = {
|
||||
'tickets': tickets,
|
||||
}
|
||||
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
|
||||
@@ -8,17 +8,28 @@ from RoutesApp.js_views import new_route_view_ajax
|
||||
|
||||
urlpatterns = [
|
||||
path('registration/', registration_ajax, name='registration_ajax'),
|
||||
|
||||
path('login/', login_ajax, name='login_ajax'),
|
||||
# path('login/', login_ajax, name='login_ajax'),
|
||||
|
||||
path('new_route_view/', new_route_view_ajax, name='new_route_view_ajax'),
|
||||
|
||||
path('dashboard/', dashboard_ajax, name='dashboard_ajax'),
|
||||
|
||||
|
||||
path('my_routes/', my_routes_ajax, name='my_routes_ajax'),
|
||||
path('subscribe/', subscribe_ajax, name='subscribe_ajax'),
|
||||
# path('subscribe/', subscribe_ajax, name='subscribe_ajax'),
|
||||
path('chats/', chats_ajax, name='chats_ajax'),
|
||||
|
||||
path('support_tickets/', support_tickets_ajax, name='support_tickets_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')
|
||||
|
||||
]
|
||||
@@ -11,26 +11,228 @@ from django.utils.translation import gettext as _
|
||||
from datetime import datetime
|
||||
from django.template.loader import render_to_string
|
||||
from django.urls import reverse
|
||||
from .funcs import *
|
||||
from django.core.exceptions import ValidationError
|
||||
import json
|
||||
from django.core.files import File
|
||||
import base64
|
||||
from django.core.validators import validate_email
|
||||
from django.urls import reverse
|
||||
|
||||
|
||||
@login_required(login_url='/profile/login/')
|
||||
def subscribe_ajax(request):
|
||||
# @login_required(login_url='/profile/login/')
|
||||
# def subscribe_ajax(request):
|
||||
# if request.method != 'POST':
|
||||
# raise Http404
|
||||
#
|
||||
# Dict = {
|
||||
# }
|
||||
#
|
||||
# html = render_to_string('blocks/profile/b_subscribe.html', Dict, request=request)
|
||||
# return JsonResponse({'html': html}, status=200)
|
||||
|
||||
|
||||
def mailing_subscribe_ajax(request):
|
||||
if request.method != 'POST':
|
||||
raise Http404
|
||||
|
||||
Dict = {
|
||||
}
|
||||
try:
|
||||
|
||||
email = request.POST['email']
|
||||
user = None
|
||||
if request.user and request.user.is_authenticated:
|
||||
user = request.user
|
||||
user.user_profile.mailing_on = True
|
||||
user.user_profile.save(update_fields=['mailing_on'])
|
||||
|
||||
return JsonResponse({
|
||||
'status': 'sended',
|
||||
'del_form': True,
|
||||
'html': _('Подписка на рассылку для адреса ') + user.email + _(' одобрена')
|
||||
})
|
||||
|
||||
if not user:
|
||||
try:
|
||||
user = User.objects.get(email=email)
|
||||
except User.DoesNotExist:
|
||||
user = None
|
||||
|
||||
if user:
|
||||
redirect_url = f"{reverse('login_profile')}?mailingSubscribeRequired=true"
|
||||
else:
|
||||
redirect_url = f"{reverse('registration_page')}?mailingSubscribeRequired=true"
|
||||
|
||||
return JsonResponse({
|
||||
'status': 'sended',
|
||||
'redirect_url': redirect_url,
|
||||
'email': email
|
||||
})
|
||||
|
||||
|
||||
except Exception as e:
|
||||
return JsonResponse({
|
||||
'status': 'error',
|
||||
'html': str(e)
|
||||
}, status=400)
|
||||
|
||||
|
||||
def send_message_ajax(request):
|
||||
if request.method != 'POST':
|
||||
raise Http404
|
||||
|
||||
try:
|
||||
|
||||
data = request.POST
|
||||
if not data and request.body:
|
||||
data = request.body
|
||||
|
||||
from GeneralApp.funcs_options import get_options_by_opt_types, get_mail_send_options
|
||||
sets = get_options_by_opt_types(['domain', 'project_name'], only_vals=True)
|
||||
|
||||
request_type = None
|
||||
subject = _('Получен запрос')
|
||||
if 'form_name' in data:
|
||||
if data['form_name'] == 'msg_from_advertisement':
|
||||
subject = _('Получен запрос на рекламу')
|
||||
request_type = _('запрос на рекламу')
|
||||
if data['form_name'] == 'msg_from_partners':
|
||||
subject = _('Получен запрос на подключение к партнерской сети')
|
||||
request_type = _('запрос на партнерство')
|
||||
if data['form_name'] == 'msg_from_customer_service':
|
||||
subject = _('Получен запрос в службу техподдержки')
|
||||
request_type = _('запрос в техподдержку')
|
||||
if data['form_name'] == 'msg_from_contacts':
|
||||
subject = _('Получен запрос со страницы контактов')
|
||||
request_type = _('запрос со страницы контактов')
|
||||
if data['form_name'] == 'msg_from_about_service':
|
||||
subject = _('Получен запрос со страницы О сервисе')
|
||||
request_type = _('запрос со страницы о сервисе')
|
||||
if data['form_name'] == 'msg_from_footer':
|
||||
subject = _('Получен запрос на рассылку')
|
||||
request_type = _('запрос на рассылку')
|
||||
|
||||
request_type_str = ''
|
||||
name_str = ''
|
||||
phone_str = ''
|
||||
email_str = ''
|
||||
msg_str = ''
|
||||
form_type = 'one_field'
|
||||
errors = {}
|
||||
|
||||
for name, val in data.items():
|
||||
if not val:
|
||||
errors.update({name: _('Обязательное поле')})
|
||||
|
||||
if name == 'form_name':
|
||||
request_type_str = f'<b>{_("Тип запроса")}:</b> {request_type}<br>'
|
||||
|
||||
if name == 'name':
|
||||
name_str = f'<b>{_("Имя")}:</b> {data["name"]}<br>'
|
||||
if form_type == 'one_field':
|
||||
form_type = 'two_fields'
|
||||
|
||||
if name =='phone':
|
||||
from BaseModels.validators.form_field_validators import get_phone_valid_error
|
||||
error = get_phone_valid_error(data["phone"])
|
||||
if error:
|
||||
errors.update({name: _(error)})
|
||||
phone_str = f'<b>{_("Телефон")}:</b> {data["phone"]}<br>'
|
||||
|
||||
if name =='email':
|
||||
try:
|
||||
error = validate_email(data["email"])
|
||||
except ValidationError as e:
|
||||
error = e.message
|
||||
if error:
|
||||
errors.update({name: _(error)})
|
||||
email_str = f'<b>{_("email")}:</b> {data["email"]}<br>'
|
||||
|
||||
if name =='text_msg':
|
||||
msg_str = (f'<b>{_("Сообщение")}:</b><br>'
|
||||
f'<div style="margin-left: 40px; line-height: 20px;">{data["text_msg"]}</div><br>')
|
||||
form_type = 'full'
|
||||
|
||||
if errors:
|
||||
Dict = {
|
||||
'form': data.dict()
|
||||
}
|
||||
Dict['form'].update({
|
||||
'errors': errors
|
||||
})
|
||||
|
||||
tpl = 'forms/f_one_field_form.html'
|
||||
if form_type == 'full':
|
||||
tpl = 'forms/f_feedback_form.html'
|
||||
elif form_type == 'two_fields':
|
||||
tpl = 'forms/f_commercial_offer.html'
|
||||
|
||||
html = render_to_string(tpl, Dict, request)
|
||||
return JsonResponse({'html': html}, status=400)
|
||||
|
||||
Dict = {
|
||||
'logo': f'{sets["domain"]}/static/img/svg/LogoMobile.svg',
|
||||
'project_name': sets['project_name'],
|
||||
'message_title': subject,
|
||||
'message_text': f'<p><b>{_("ДАННЫЕ ЗАПРОСА")}</b></p>'
|
||||
f'<p style="padding-left: 20px; line-height: 30px;">'
|
||||
f'{request_type_str}'
|
||||
f'{name_str}'
|
||||
f'{phone_str}'
|
||||
f'{email_str}'
|
||||
f'{msg_str}'
|
||||
f'</p>'
|
||||
}
|
||||
|
||||
html = render_to_string('mail/m_request_offer.html', Dict, request)
|
||||
from BaseModels.mailSender import admin_send_mail_by_SMTPlib
|
||||
mail_sets = get_mail_send_options()
|
||||
to = [mail_sets['sender_email'], 'web@syncsystems.net']
|
||||
res = admin_send_mail_by_SMTPlib(
|
||||
mail_sets,
|
||||
subject=subject,
|
||||
from_email=mail_sets['sender_email'], to=to,
|
||||
html_content=html
|
||||
)
|
||||
|
||||
html = render_to_string('widgets/w_msg_send_success.html', Dict, request)
|
||||
|
||||
return JsonResponse({
|
||||
'status': 'sended',
|
||||
'html': html
|
||||
})
|
||||
except Exception as e:
|
||||
return JsonResponse({
|
||||
'status': 'error',
|
||||
'html': str(e)
|
||||
}, status=400)
|
||||
|
||||
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 chats_ajax(request):
|
||||
if request.method != 'POST':
|
||||
raise Http404
|
||||
|
||||
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)
|
||||
|
||||
cur_chat_msgs = None
|
||||
|
||||
# try:
|
||||
# cur_receiver = User.objects.get(id=user_id)
|
||||
# if not cur_receiver in receivers:
|
||||
# receivers.insert(0, cur_receiver)
|
||||
# cur_chat_msgs = get_msgs_for_chat_w_users(request.user, cur_receiver)
|
||||
# except User.DoesNotExist:
|
||||
# cur_receiver = None
|
||||
|
||||
Dict = {
|
||||
'page': 'chat',
|
||||
# 'cur_receiver': cur_receiver,
|
||||
'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)
|
||||
@@ -40,33 +242,138 @@ def support_tickets_ajax(request):
|
||||
if request.method != 'POST':
|
||||
raise Http404
|
||||
|
||||
if request.user.is_staff:
|
||||
from ChatServiceApp.funcs import get_ticketsDict_for_staff
|
||||
Dict = get_ticketsDict_for_staff(request.user)
|
||||
tpl_name = 'blocks/profile/b_support_chat.html'
|
||||
else:
|
||||
from ChatServiceApp.models import MsgGroup
|
||||
tickets = MsgGroup.objects.filter(enable=True, owner=request.user).order_by('-modifiedDT')
|
||||
html = get_profile_support_page_content_html(request)
|
||||
|
||||
Dict = {
|
||||
'tickets': tickets,
|
||||
}
|
||||
tpl_name = 'blocks/profile/b_support_tickets.html'
|
||||
|
||||
html = render_to_string(tpl_name, Dict, request=request)
|
||||
return JsonResponse({'html': html}, status=200)
|
||||
|
||||
|
||||
@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
|
||||
|
||||
try:
|
||||
|
||||
file_data = json.loads(request.body)
|
||||
head, content = file_data['file'].split(',')
|
||||
content = base64.b64decode(content)
|
||||
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)
|
||||
return JsonResponse({'error': msg}, status=400)
|
||||
|
||||
return JsonResponse({'url': request.user.user_profile.avatar.url})
|
||||
|
||||
|
||||
@login_required(login_url='/profile/login/')
|
||||
def change_profile_confirm_ajax(request):
|
||||
if request.method != 'POST':
|
||||
raise Http404
|
||||
|
||||
data = request.POST
|
||||
if not data:
|
||||
data = json.loads(request.body)
|
||||
|
||||
from .forms import RegistrationForm
|
||||
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)
|
||||
if 'firstname' in data:
|
||||
data_for_save.update({'first_name': data['firstname']})
|
||||
if 'lastname' in data:
|
||||
data_for_save.update({'last_name': data['lastname']})
|
||||
if 'email' in data:
|
||||
data_for_save.update({'email': data['email']})
|
||||
data_for_save.update({'username': data['email']})
|
||||
|
||||
if data_for_save:
|
||||
users.update(**data_for_save)
|
||||
|
||||
data_for_save = {}
|
||||
|
||||
password = None
|
||||
confirm_password = None
|
||||
if 'password' in data:
|
||||
password = data['password']
|
||||
if 'confirm_password' in data:
|
||||
confirm_password = data['confirm_password']
|
||||
if password and confirm_password:
|
||||
if password != confirm_password:
|
||||
errors = {
|
||||
'password': _("Не совпадают пароли"),
|
||||
'confirm_password': _("Не совпадают пароли"),
|
||||
}
|
||||
raise ValidationError(errors)
|
||||
|
||||
request.user.set_password(password)
|
||||
request.user.save()
|
||||
|
||||
|
||||
data_for_save = {}
|
||||
user_profiles = UserProfile.objects.filter(user__in=users)
|
||||
if 'country' in data:
|
||||
data_for_save.update({'country': data['country']})
|
||||
if 'city' in data:
|
||||
data_for_save.update({'city': data['city']})
|
||||
if 'tel' in data:
|
||||
data_for_save.update({'phone': data['tel']})
|
||||
|
||||
if data_for_save:
|
||||
user_profiles.update(**data_for_save)
|
||||
|
||||
html = get_profile_change_page_content_html(request)
|
||||
return JsonResponse({'html': html}, status=200)
|
||||
|
||||
|
||||
@login_required(login_url='/profile/login/')
|
||||
def dashboard_ajax(request):
|
||||
if request.method != 'POST':
|
||||
raise Http404
|
||||
|
||||
try:
|
||||
|
||||
from .funcs import get_dashboard_page_content_html
|
||||
html = get_dashboard_page_content_html(request)
|
||||
|
||||
except Exception as e:
|
||||
msg = f'dashboard_ajax Error = {str(e)}'
|
||||
print(msg)
|
||||
html = msg
|
||||
|
||||
return JsonResponse({'html': html}, status=200)
|
||||
|
||||
|
||||
@login_required(login_url='/profile/login/')
|
||||
def change_profile_ajax(request):
|
||||
if request.method != 'POST':
|
||||
raise Http404
|
||||
|
||||
Dict = {
|
||||
}
|
||||
|
||||
html = render_to_string('blocks/profile/b_profile.html', Dict, request=request)
|
||||
html = get_profile_change_page_content_html(request)
|
||||
return JsonResponse({'html': html}, status=200)
|
||||
|
||||
|
||||
@@ -104,10 +411,13 @@ def login_ajax(request):
|
||||
user = authenticate(username=form.data['username'], password=form.data['password'])
|
||||
if user is not None:
|
||||
auth.login(request, user)
|
||||
if 'mailingSubscribeRequired' in data and data['mailingSubscribeRequired'] == 'true':
|
||||
user.user_profile.mailing_on = True
|
||||
user.user_profile.save(update_fields=['mailing_on'])
|
||||
else:
|
||||
errors_Dict = {
|
||||
'errors': {
|
||||
'all__': f'неверный логин и\или пароль'
|
||||
'all__': _("неверный логин и\или пароль")
|
||||
}
|
||||
}
|
||||
Dict = {'form': errors_Dict}
|
||||
@@ -116,7 +426,7 @@ def login_ajax(request):
|
||||
|
||||
|
||||
res_Dict = {
|
||||
'redirect_url': reverse('user_profile')
|
||||
'redirect_url': reverse('profile_page', args=['dashboard'])
|
||||
}
|
||||
|
||||
return JsonResponse(res_Dict)
|
||||
@@ -125,7 +435,7 @@ def login_ajax(request):
|
||||
|
||||
errors_Dict = {
|
||||
'errors': {
|
||||
'all__': f'ошибка в запросе = {str(e)}'
|
||||
'all__': f'{_("ошибка в запросе")} = {str(e)}'
|
||||
}
|
||||
}
|
||||
Dict = {'form': errors_Dict}
|
||||
@@ -133,6 +443,42 @@ def login_ajax(request):
|
||||
return JsonResponse({'html': html}, status=400)
|
||||
|
||||
|
||||
|
||||
|
||||
def send_registration_mail(data_Dict, user):
|
||||
|
||||
try:
|
||||
|
||||
from GeneralApp.funcs_options import get_options_by_opt_types, get_mail_send_options
|
||||
sets = get_options_by_opt_types(['domain', 'project_name'], only_vals=True)
|
||||
|
||||
subject = _('Добро пожаловать в Trip With Bonus!')
|
||||
|
||||
Dict = {
|
||||
'logo': f'{sets["domain"]}/static/img/svg/LogoMobile.svg',
|
||||
'project_name': sets['project_name'],
|
||||
'message_title': subject,
|
||||
}
|
||||
Dict.update(data_Dict)
|
||||
|
||||
html = render_to_string('mail/m_registration.html', Dict)
|
||||
from BaseModels.mailSender import admin_send_mail_by_SMTPlib
|
||||
mail_sets = get_mail_send_options()
|
||||
to = [user.email, 'web@syncsystems.net', 'sa@a3-global.com', 'sysadmin.hax@gmail.com']
|
||||
res = admin_send_mail_by_SMTPlib(
|
||||
mail_sets,
|
||||
subject=subject,
|
||||
from_email=mail_sets['sender_email'], to=to,
|
||||
html_content=html
|
||||
)
|
||||
|
||||
return res
|
||||
except Exception as e:
|
||||
print(f'send_registration_mail Error = {str(e)}')
|
||||
return None
|
||||
|
||||
|
||||
|
||||
def registration_ajax(request):
|
||||
if request.method != 'POST':
|
||||
raise Http404
|
||||
@@ -148,17 +494,20 @@ def registration_ajax(request):
|
||||
html = render_to_string('forms/f_registration.html', Dict, request=request)
|
||||
return JsonResponse({'html': html}, status=400)
|
||||
|
||||
users = User.objects.filter(email=form.data['email'])
|
||||
if users:
|
||||
form.errors['email'] = 'Пользователь с указанным email уже существует'
|
||||
Dict = {'form': form}
|
||||
html = render_to_string('forms/f_registration.html', Dict, request=request)
|
||||
return JsonResponse({'html': html}, status=400)
|
||||
# users = User.objects.filter(email=form.data['email'])
|
||||
# if users:
|
||||
# form.errors['email'] = _("Пользователь с указанным email уже существует")
|
||||
# Dict = {'form': form}
|
||||
# html = render_to_string('forms/f_registration.html', Dict, request=request)
|
||||
# return JsonResponse({'html': html}, status=400)
|
||||
|
||||
user = User.objects.create_user(username=form.data['email'], email=form.data['email'], password=form.data['password'])
|
||||
# user = auth.authenticate(username=new_user_Dict['name'], password=new_user_Dict['pass'])
|
||||
if user:
|
||||
auth.login(request, user)
|
||||
auth.login(request, user, backend='django.contrib.auth.backends.ModelBackend')
|
||||
|
||||
if 'mailingSubscribeRequired' in data and data['mailingSubscribeRequired'] == 'true':
|
||||
user.user_profile.mailing_on = True
|
||||
|
||||
user.last_name = form.data['lastname']
|
||||
user.first_name = form.data['firstname']
|
||||
@@ -166,8 +515,14 @@ def registration_ajax(request):
|
||||
user.user_profile.phone = form.data['tel']
|
||||
user.user_profile.save()
|
||||
|
||||
mail_Dict = {
|
||||
'user': user,
|
||||
'pass': form.data['password']
|
||||
}
|
||||
res = send_registration_mail(mail_Dict, user)
|
||||
|
||||
res_Dict = {
|
||||
'redirect_url': reverse('user_profile')
|
||||
'redirect_url': reverse('profile_page', args=['dashboard'])
|
||||
}
|
||||
|
||||
return JsonResponse(res_Dict)
|
||||
@@ -176,7 +531,7 @@ def registration_ajax(request):
|
||||
|
||||
errors_Dict = {
|
||||
'errors': {
|
||||
'__all__': f'ошибка в запросе = {str(e)}'
|
||||
'__all__': f'{_("ошибка в запросе")} = {str(e)}'
|
||||
}
|
||||
}
|
||||
Dict = {'form': errors_Dict}
|
||||
|
||||
92
AuthApp/middleware.py
Normal file
92
AuthApp/middleware.py
Normal file
@@ -0,0 +1,92 @@
|
||||
import json
|
||||
import datetime
|
||||
from django.http import HttpResponse, JsonResponse
|
||||
from django.conf import settings
|
||||
from django.utils.deprecation import MiddlewareMixin
|
||||
|
||||
|
||||
def set_cookie(response, key, value, days_expire=7):
|
||||
if days_expire is None:
|
||||
max_age = 365 * 24 * 60 * 60 # one year
|
||||
else:
|
||||
max_age = days_expire * 24 * 60 * 60
|
||||
expires = datetime.datetime.strftime(
|
||||
datetime.datetime.utcnow() + datetime.timedelta(seconds=max_age),
|
||||
"%a, %d-%b-%Y %H:%M:%S GMT",
|
||||
)
|
||||
response.set_cookie(
|
||||
key,
|
||||
value,
|
||||
max_age=max_age,
|
||||
expires=expires,
|
||||
domain=settings.SESSION_COOKIE_DOMAIN,
|
||||
secure=settings.SESSION_COOKIE_SECURE or None,
|
||||
)
|
||||
|
||||
return response
|
||||
|
||||
class ResponseInterceptionMiddleware:
|
||||
def __init__(self, get_response):
|
||||
self.get_response = get_response
|
||||
|
||||
def __call__(self, request):
|
||||
response = self.get_response(request)
|
||||
for_save_to_session = None
|
||||
|
||||
try:
|
||||
if type(response) == JsonResponse:
|
||||
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)
|
||||
response.content = json.dumps(data)
|
||||
except Exception as e:
|
||||
msg = f'ResponseInterceptionMiddleware error = {str(e)}'
|
||||
print(msg)
|
||||
# if 'errors' in response.data:
|
||||
# response.data.update({'success': False})
|
||||
# print(response.data)
|
||||
return response
|
||||
|
||||
# def process_view(self, request, view_func, *view_args, **view_kwargs):
|
||||
#
|
||||
# request.META.update({'ws_port': settings.WS_PORT})
|
||||
#
|
||||
# # if request.user.is_authenticated and request.body:
|
||||
# # for_save_to_session = request.user.user_profile.pop_node_by_name('for_save_to_session')
|
||||
# # if for_save_to_session:
|
||||
# # data = json.loads(request.body)
|
||||
# # data.update(for_save_to_session)
|
||||
# #
|
||||
# # # request_data = getattr(request, '_body', request.body)
|
||||
# # # request_data = json.loads(request_data)
|
||||
# # # # here you can write the logic to append the payload to request data
|
||||
# # request._body = json.dumps(data)
|
||||
# return None
|
||||
|
||||
# def __call__(self, request):
|
||||
# # Code to be executed for each request before
|
||||
# # the view (and later middleware) are called.
|
||||
#
|
||||
# if request.user.is_authenticated and request.body:
|
||||
# for_save_to_session = request.user.user_profile.pop_node_by_name('for_save_to_session')
|
||||
# if for_save_to_session:
|
||||
# data = json.loads(request.body)
|
||||
# data.update(for_save_to_session)
|
||||
# request._body = json.dumps(data)
|
||||
# # return JsonResponse(data)
|
||||
# # request = request.user.user_profile.save_user_alerts_to_session(request)
|
||||
#
|
||||
# response = self.get_response(request)
|
||||
# # if request.user.is_authenticated:
|
||||
# # for_save_to_session = request.user.user_profile.pop_node_by_name('for_save_to_session')
|
||||
# # if for_save_to_session:
|
||||
# # for key, val in for_save_to_session.items():
|
||||
# # set_cookie(response, key, json.dumps(val), 30)
|
||||
#
|
||||
# # Code to be executed for each request/response after
|
||||
# # the view is called.
|
||||
#
|
||||
# return response
|
||||
|
||||
18
AuthApp/migrations/0005_userprofile_mailing_on.py
Normal file
18
AuthApp/migrations/0005_userprofile_mailing_on.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.2 on 2024-02-01 17:17
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('AuthApp', '0004_alter_userprofile_account_type'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='userprofile',
|
||||
name='mailing_on',
|
||||
field=models.BooleanField(default=False, verbose_name='Рассылка'),
|
||||
),
|
||||
]
|
||||
@@ -1,5 +1,8 @@
|
||||
# coding=utf-8
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import json
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
@@ -48,6 +51,21 @@ 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:
|
||||
for key, val in for_save_to_session.items():
|
||||
request.session[key] = val
|
||||
return request
|
||||
|
||||
|
||||
def __str__(self):
|
||||
if self.user:
|
||||
@@ -64,8 +82,23 @@ class UserProfile(BaseModel):
|
||||
|
||||
|
||||
def create_user_profile(sender, instance, created, **kwargs):
|
||||
user_profile = None
|
||||
if created:
|
||||
UserProfile.objects.create(user=instance)
|
||||
user_profile = UserProfile.objects.create(user=instance)
|
||||
|
||||
# if user_profile and not user_profile.avatar:
|
||||
# from allauth.socialaccount.models import SocialAccount
|
||||
# # try:
|
||||
# social_accounts = SocialAccount.objects.filter(user=instance)
|
||||
# if social_accounts:
|
||||
# for social_account in social_accounts:
|
||||
# if 'picture' in social_account.account.extra_data and social_account.account.extra_data['picture']:
|
||||
# with open(social_account.account.extra_data['picture'], 'rb') as fd:
|
||||
# user_profile.avatar.save(f'avatar_{instance.id}.jpeg', fd.read(), True)
|
||||
#
|
||||
# # except Exception as e:
|
||||
# # msg = f'post_save create_user_profile Error = {str(e)}'
|
||||
# # print(msg)
|
||||
|
||||
|
||||
post_save.connect(create_user_profile, sender=User, dispatch_uid='post_save_connect')
|
||||
@@ -75,6 +108,7 @@ def preSaveUser(sender, instance, **kwargs):
|
||||
if not instance.email:
|
||||
instance.email = str(instance.username).lower()
|
||||
|
||||
|
||||
try:
|
||||
instance.user_profile.modifiedDT = datetime.now()
|
||||
except:
|
||||
|
||||
@@ -8,10 +8,20 @@ from django.contrib.auth import views
|
||||
urlpatterns = [
|
||||
|
||||
path('registration/', registration_View, name='registration_page'),
|
||||
path('', user_profile_View, name='user_profile'),
|
||||
path('chat/<int:user_id>/', chat_w_user_View, name='chat_w_user'),
|
||||
path('chat/', chat_w_user_View, name='chat_w_user_wo_user_id'),
|
||||
# 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'),
|
||||
|
||||
path('page/<str:page_name>/', profile_page_View, name='profile_page'),
|
||||
path('page/<str:page_name>/<int:id>/', profile_page_View, name='profile_page_w_param'),
|
||||
|
||||
# path('create_route_for_customer/', create_route_for_customer_View, name='create_route_for_customer_View'),
|
||||
# path('create_route_for_mover/', create_route_for_mover_View, name='create_route_for_mover_View'),
|
||||
|
||||
path('login/', login_View, name='login_profile'),
|
||||
path('logout/', logout_View, name='logout_profile'),
|
||||
|
||||
path('account/signup/', login_View, name="custom_singup" ),
|
||||
|
||||
|
||||
# ajax ----------------
|
||||
|
||||
134
AuthApp/views.py
134
AuthApp/views.py
@@ -12,59 +12,133 @@ from BaseModels.mailSender import techSendMail
|
||||
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
|
||||
|
||||
def registration_View(request):
|
||||
|
||||
Dict = {}
|
||||
|
||||
t = loader.get_template('pages/profile/p_registration.html')
|
||||
return HttpResponse(t.render(Dict, request))
|
||||
if request.GET and 'mailingSubscribeRequired' in request.GET and request.GET['mailingSubscribeRequired'] == 'true':
|
||||
request.session['mailingSubscribeRequired'] = 'true'
|
||||
|
||||
# if request.p
|
||||
|
||||
t = loader.get_template('pages/profile/p_registration.html')
|
||||
return get_inter_http_respose(t, Dict, request)
|
||||
# return HttpResponse(t.render(Dict, request))
|
||||
|
||||
|
||||
# def create_route_for_customer_View(request):
|
||||
# Dict = {}
|
||||
# t = loader.get_template('pages/profile/p_user_profile.html')
|
||||
# return HttpResponse(t.render(Dict, request))
|
||||
#
|
||||
#
|
||||
# def create_route_for_mover_View(request):
|
||||
# Dict = {}
|
||||
# t = loader.get_template('pages/profile/p_user_profile.html')
|
||||
# return HttpResponse(t.render(Dict, request))
|
||||
|
||||
|
||||
@login_required(login_url='/profile/login/')
|
||||
def chat_w_user_View(request, user_id=None):
|
||||
from ChatServiceApp.funcs import get_chat_receivers_for_user, get_msgs_for_chat_w_users
|
||||
|
||||
receivers = get_chat_receivers_for_user(request.user)
|
||||
|
||||
cur_chat_msgs = None
|
||||
|
||||
try:
|
||||
cur_receiver = User.objects.get(id=user_id)
|
||||
if not cur_receiver in receivers:
|
||||
receivers.insert(0, cur_receiver)
|
||||
cur_chat_msgs = get_msgs_for_chat_w_users(request.user, cur_receiver)
|
||||
except User.DoesNotExist:
|
||||
cur_receiver = None
|
||||
|
||||
|
||||
def profile_page_View(request, page_name, id=None):
|
||||
Dict = {
|
||||
'page': 'chat',
|
||||
'cur_receiver': cur_receiver,
|
||||
'receivers': receivers,
|
||||
'cur_chat_msgs':cur_chat_msgs
|
||||
'page_html': get_profile_page_content_html(request, page_name, id),
|
||||
'page_name': page_name,
|
||||
'page_type': 'profile'
|
||||
}
|
||||
|
||||
if request.session and 'mailingSubscribeRequired' in request.session and request.session['mailingSubscribeRequired'] == 'true':
|
||||
request.user.user_profile.mailing_on = True
|
||||
request.user.user_profile.save(update_fields=['mailing_on'])
|
||||
del request.session['mailingSubscribeRequired']
|
||||
|
||||
title = f"{_('Личный кабинет пользователя')} {request.user.first_name} {request.user.last_name}"
|
||||
|
||||
Dict.update({
|
||||
'page': {
|
||||
'title': title,
|
||||
'description': title,
|
||||
'keywords': title,
|
||||
}
|
||||
})
|
||||
|
||||
# if request.GET and 'mobile' in request.GET and request.GET['mobile'] == 'true':
|
||||
# Dict.update({
|
||||
# 'mobile': True
|
||||
# })
|
||||
|
||||
t = loader.get_template('pages/profile/p_user_profile.html')
|
||||
return HttpResponse(t.render(Dict, request))
|
||||
return get_inter_http_respose(t, Dict, request)
|
||||
# return HttpResponse(t.render(Dict, request))
|
||||
|
||||
|
||||
# @login_required(login_url='/profile/login/')
|
||||
# def chat_w_user_View(request, user_id=None):
|
||||
# from ChatServiceApp.funcs import get_chat_page_content_Dict
|
||||
#
|
||||
# # receivers = get_chat_receivers_for_user(request.user)
|
||||
#
|
||||
# Dict = get_chat_page_content_Dict(request, user_id)
|
||||
#
|
||||
# # cur_chat_msgs = None
|
||||
# #
|
||||
# # try:
|
||||
# # cur_receiver = User.objects.get(id=user_id)
|
||||
# # if not cur_receiver in receivers:
|
||||
# # receivers.insert(0, cur_receiver)
|
||||
# # cur_chat_msgs = get_msgs_for_chat_w_users(request.user, cur_receiver)
|
||||
# # except User.DoesNotExist:
|
||||
# # cur_receiver = None
|
||||
# #
|
||||
# #
|
||||
# # Dict = {
|
||||
# # 'page': 'chat',
|
||||
# # 'cur_receiver': cur_receiver,
|
||||
# # 'receivers': receivers,
|
||||
# # 'messages':cur_chat_msgs
|
||||
# # }
|
||||
#
|
||||
# t = loader.get_template('pages/profile/p_user_profile.html')
|
||||
# return HttpResponse(t.render(Dict, request))
|
||||
|
||||
@login_required(login_url='/profile/login/')
|
||||
def user_profile_View(request):
|
||||
|
||||
Dict = {}
|
||||
|
||||
t = loader.get_template('pages/profile/p_user_profile.html')
|
||||
return HttpResponse(t.render(Dict, request))
|
||||
user_online = request.session.get('online', False)
|
||||
# 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 = HttpResponse(t.render(Dict, request))
|
||||
response.set_cookie('user_id', request.user.id)
|
||||
return response
|
||||
|
||||
|
||||
def logout_View(request):
|
||||
from django.contrib.auth import logout
|
||||
from django.shortcuts import redirect
|
||||
|
||||
logout(request)
|
||||
return redirect('login_profile')
|
||||
|
||||
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 HttpResponse(t.render(Dict, request))
|
||||
return get_inter_http_respose(t, Dict, request)
|
||||
# return HttpResponse(t.render(Dict, request))
|
||||
|
||||
|
||||
|
||||
@@ -111,7 +185,7 @@ def create_personal_user(data, creator):
|
||||
}
|
||||
except Exception as e:
|
||||
return {
|
||||
'error': 'Ошибка добавление нового пользователя = {0}'.format(str(e)),
|
||||
'error': f'{_("Ошибка добавление нового пользователя")} = {str(e)}',
|
||||
}
|
||||
|
||||
|
||||
@@ -148,7 +222,7 @@ def create_temporary_user():
|
||||
from django.utils.translation import gettext as _
|
||||
user_id = str(uuid1().hex)[:10]
|
||||
user_name = u'user'+user_id
|
||||
mail = user_id+u'@truenergy.by'
|
||||
mail = user_id+u'@domain'
|
||||
user = User.objects.create_user(mail, mail,user_id)
|
||||
user.first_name = _(u'незарег. пользователь')
|
||||
user.last_name = u''
|
||||
|
||||
@@ -266,8 +266,8 @@ def osm_get_country_w_cities_n_airports(country_Dict, area_id):
|
||||
country_Dict['parsing_status'] = 'finished'
|
||||
|
||||
airports_wo_city = []
|
||||
if airports_Dict and None in airports_Dict:
|
||||
airports_wo_city = airports_Dict[None]
|
||||
# if airports_Dict and None in airports_Dict:
|
||||
# airports_wo_city = airports_Dict[None]
|
||||
|
||||
return country_Dict, airports_wo_city
|
||||
|
||||
|
||||
70
BaseModels/PIL/pillow_backend.py
Normal file
70
BaseModels/PIL/pillow_backend.py
Normal file
@@ -0,0 +1,70 @@
|
||||
import os
|
||||
from io import BytesIO
|
||||
|
||||
from django.conf import settings
|
||||
from django.utils.functional import cached_property
|
||||
from PIL import Image
|
||||
|
||||
from ckeditor_uploader import utils
|
||||
|
||||
|
||||
THUMBNAIL_SIZE = getattr(settings, "CKEDITOR_THUMBNAIL_SIZE", (75, 75))
|
||||
|
||||
|
||||
class PillowBackend:
|
||||
def __init__(self, storage_engine, file_object):
|
||||
self.file_object = file_object
|
||||
self.storage_engine = storage_engine
|
||||
|
||||
@cached_property
|
||||
def is_image(self):
|
||||
try:
|
||||
Image.open(
|
||||
BytesIO(self.file_object.read())
|
||||
).verify() # verify closes the file
|
||||
return True
|
||||
except OSError:
|
||||
return False
|
||||
finally:
|
||||
self.file_object.seek(0)
|
||||
|
||||
def _compress_image(self, image):
|
||||
quality = getattr(settings, "CKEDITOR_IMAGE_QUALITY", 75)
|
||||
image = image.resize(image.size, Image.ANTIALIAS).convert("RGB")
|
||||
image_tmp = BytesIO()
|
||||
image.save(image_tmp, format="JPEG", quality=quality, optimize=True)
|
||||
return image_tmp
|
||||
|
||||
def save_as(self, filepath):
|
||||
if not self.is_image:
|
||||
saved_path = self.storage_engine.save(filepath, self.file_object)
|
||||
return saved_path
|
||||
|
||||
image = Image.open(self.file_object)
|
||||
|
||||
should_compress = getattr(settings, "CKEDITOR_FORCE_JPEG_COMPRESSION", False)
|
||||
is_animated = hasattr(image, "is_animated") and image.is_animated
|
||||
if should_compress and not is_animated:
|
||||
file_object = self._compress_image(image)
|
||||
filepath = f"{os.path.splitext(filepath)[0]}.jpg"
|
||||
saved_path = self.storage_engine.save(filepath, file_object)
|
||||
else:
|
||||
file_object = self.file_object
|
||||
saved_path = self.storage_engine.save(filepath, self.file_object)
|
||||
|
||||
if not is_animated:
|
||||
self.create_thumbnail(file_object, saved_path)
|
||||
return saved_path
|
||||
|
||||
def create_thumbnail(self, file_object, file_path):
|
||||
thumbnail_filename = utils.get_thumb_filename(file_path)
|
||||
thumbnail_io = BytesIO()
|
||||
# File object after saving e.g. to S3 can be closed.
|
||||
try:
|
||||
image = Image.open(file_object).convert("RGBA")
|
||||
except ValueError:
|
||||
file_object = self.storage_engine.open(file_path)
|
||||
image = Image.open(file_object).convert("RGBA")
|
||||
image.thumbnail(THUMBNAIL_SIZE, Image.ANTIALIAS)
|
||||
image.save(thumbnail_io, format="PNG", optimize=True)
|
||||
return self.storage_engine.save(thumbnail_filename, thumbnail_io)
|
||||
@@ -26,9 +26,9 @@ def send_SMS(phone, text, urgent=False, staff=False):
|
||||
phone.encode('utf-8')
|
||||
|
||||
http_request = 'http://cp.websms.by/?r=api/msg_send' \
|
||||
'&user=administrator@baldenini.by' \
|
||||
'&apikey=zTwevODOYl' \
|
||||
'&sender=Baldenini'
|
||||
'&user=administrator@site.by' \
|
||||
'&apikey=key' \
|
||||
'&sender=company'
|
||||
# '&test=1'
|
||||
|
||||
if urgent:
|
||||
|
||||
@@ -8,6 +8,7 @@ from django.utils.safestring import mark_safe
|
||||
from django.db import models
|
||||
from django.contrib import admin
|
||||
from django.contrib.contenttypes.admin import GenericTabularInline, GenericStackedInline
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
import re
|
||||
# from modeltranslation.admin import TranslationAdmin
|
||||
@@ -36,14 +37,14 @@ def get_base_fieldsets():
|
||||
)
|
||||
}],
|
||||
|
||||
(u'Описание и текст', {
|
||||
(_('Описание и текст'), {
|
||||
'classes': ['wide', 'collapse'],
|
||||
'fields': (
|
||||
'description', 'text',
|
||||
)
|
||||
}),
|
||||
|
||||
(u'Промо ФОН', {
|
||||
(_('Промо ФОН'), {
|
||||
'classes': ['wide', 'collapse'],
|
||||
'fields': (
|
||||
'background_promo_show', 'background_promo_inherits',
|
||||
@@ -63,7 +64,7 @@ def get_base_fieldsets():
|
||||
)
|
||||
}),
|
||||
|
||||
(u'Партнерские ссылки', {
|
||||
(_('Партнерские ссылки'), {
|
||||
'classes': ['wide', 'collapse'],
|
||||
'fields': (
|
||||
'link_left_promo_show',
|
||||
@@ -118,6 +119,9 @@ def init_formfield_for_dbfield(class_model, self, db_field, request, **kwargs):
|
||||
if db_field.name in ['question', 'FAQ_title']:
|
||||
formfield.widget = admin.widgets.AdminTextInputWidget(attrs={'style': 'width: 80%'})
|
||||
|
||||
# if db_field.name in ['text']:
|
||||
# formfield.widget.attrs.update({'style': 'width: 80%'})
|
||||
|
||||
if formfield and formfield.widget:
|
||||
# if type(formfield.widget) in (admin.widgets.AdminSplitDateTime, ):
|
||||
# formfield.widget.attrs.update({'style': 'width: 400px'})
|
||||
@@ -215,7 +219,7 @@ class Admin_GenericBaseIconStackedInline(GenericStackedInline):
|
||||
def image_thumb(self, obj):
|
||||
return get_image_thumb(self, obj)
|
||||
|
||||
image_thumb.short_description = u'Миниатюра'
|
||||
image_thumb.short_description = _('Миниатюра')
|
||||
image_thumb.allow_tags = True
|
||||
|
||||
|
||||
@@ -228,7 +232,7 @@ class Admin_BaseIconStackedInline(admin.StackedInline):
|
||||
def image_thumb(self, obj):
|
||||
return get_image_thumb(self, obj)
|
||||
|
||||
image_thumb.short_description = u'Миниатюра'
|
||||
image_thumb.short_description = _('Миниатюра')
|
||||
image_thumb.allow_tags = True
|
||||
|
||||
|
||||
@@ -240,7 +244,7 @@ class Admin_BaseIconTabularModel(admin.TabularInline):
|
||||
def image_thumb(self, obj):
|
||||
return get_image_thumb(self, obj)
|
||||
|
||||
image_thumb.short_description = u'Миниатюра'
|
||||
image_thumb.short_description = _('Миниатюра')
|
||||
image_thumb.allow_tags = True
|
||||
|
||||
|
||||
@@ -255,7 +259,7 @@ class Admin_BaseIconModel(admin.ModelAdmin):
|
||||
|
||||
return s
|
||||
|
||||
description_exists.short_description = u'Описание'
|
||||
description_exists.short_description = _('Описание')
|
||||
description_exists.allow_tags = True
|
||||
|
||||
def formfield_for_dbfield (self, db_field, request, **kwargs):
|
||||
@@ -268,7 +272,7 @@ class Admin_BaseIconModel(admin.ModelAdmin):
|
||||
def image_thumb(self, obj):
|
||||
return get_image_thumb(self, obj)
|
||||
|
||||
image_thumb.short_description = u'Миниатюра'
|
||||
image_thumb.short_description = _('Миниатюра')
|
||||
image_thumb.allow_tags = True
|
||||
|
||||
|
||||
|
||||
@@ -10,7 +10,8 @@ from django.utils.translation import gettext_lazy as _
|
||||
from django.db.models.signals import post_save, pre_save
|
||||
from django.utils.text import slugify
|
||||
from django.contrib.postgres.fields import JSONField
|
||||
from ckeditor.fields import RichTextField
|
||||
# from ckeditor.fields import RichTextField
|
||||
from ckeditor_uploader.fields import RichTextUploadingField
|
||||
from django.contrib.contenttypes.fields import GenericRelation
|
||||
|
||||
|
||||
@@ -34,6 +35,17 @@ class BaseModel(models.Model):
|
||||
else:
|
||||
return str(self.id)
|
||||
|
||||
def pop_node_by_name(self, node_name):
|
||||
if not self.json_data or not node_name in self.json_data:
|
||||
return None
|
||||
|
||||
res = self.json_data[node_name]
|
||||
del self.json_data[node_name]
|
||||
self.save(update_fields=['json_data'])
|
||||
|
||||
return res
|
||||
|
||||
|
||||
def get_node_by_name(self, node_name):
|
||||
if not self.json_data or not node_name in self.json_data:
|
||||
return None
|
||||
@@ -75,9 +87,9 @@ class BaseModelViewPage(BaseModel):
|
||||
help_text=_(
|
||||
'можно изменить адрес страницы (!!! ВНИМАНИЕ !!! поисковые системы потеряют страницу и найдут лишь спустя неделю...месяц)'))
|
||||
title = models.TextField(verbose_name=_('Заголовок'), null=True, blank=True)
|
||||
description = RichTextField(verbose_name=_('Краткое описание'), null=True, blank=True, # max_length=240,
|
||||
description = RichTextUploadingField(verbose_name=_('Краткое описание'), null=True, blank=True, # max_length=240,
|
||||
help_text=_('краткое описание страницы (до 240 символов)'))
|
||||
text = RichTextField(verbose_name=_('Полное описание'), null=True, blank=True, )
|
||||
text = RichTextUploadingField(verbose_name=_('Полное описание'), null=True, blank=True, )
|
||||
# help_text=_(u'краткое описание страницы (до 240 символов)'))
|
||||
picture = models.ImageField(upload_to='uploads/', verbose_name=_('Картинка'), null=True, blank=True,
|
||||
help_text=u'')
|
||||
@@ -91,7 +103,7 @@ class BaseModelViewPage(BaseModel):
|
||||
seo_description = models.CharField(max_length=250, verbose_name=_('Description (150 знаков)'), null=True,
|
||||
blank=True)
|
||||
seo_keywords = models.CharField(max_length=250, verbose_name=_('Keywords (200 знаков)'), null=True, blank=True)
|
||||
seo_text = RichTextField(verbose_name=_(u'Текст SEO статьи'), null=True, blank=True)
|
||||
seo_text = RichTextUploadingField(verbose_name=_(u'Текст SEO статьи'), null=True, blank=True)
|
||||
|
||||
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')
|
||||
@@ -100,6 +112,23 @@ class BaseModelViewPage(BaseModel):
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
def get_title(self):
|
||||
if self.seo_title:
|
||||
return self.seo_title
|
||||
elif self.title:
|
||||
return self.title
|
||||
else:
|
||||
return self.name
|
||||
|
||||
def get_description(self):
|
||||
if self.seo_description:
|
||||
return self.seo_description
|
||||
else:
|
||||
return self.description
|
||||
|
||||
def get_FAQ_items(self):
|
||||
return self.FAQ_items.filter(enable=True).order_by('order')
|
||||
|
||||
def get_description_exists(self):
|
||||
if self.description:
|
||||
return True
|
||||
|
||||
@@ -96,27 +96,27 @@ def sortByLength(inputStr):
|
||||
return len(inputStr)
|
||||
|
||||
|
||||
def add_domain(request, url, add_lang=False):
|
||||
domain = get_domain_by_request(request)
|
||||
if add_lang:
|
||||
cur_lang = get_cur_lang_by_request(request)
|
||||
return '{0}/{1}/{2}'.format(domain, cur_lang, url)
|
||||
else:
|
||||
return '{0}{1}'.format(domain, url)
|
||||
# def add_domain(request, url, add_lang=False):
|
||||
# domain = get_domain_by_request(request)
|
||||
# if add_lang:
|
||||
# cur_lang = get_cur_lang_by_request(request)
|
||||
# return '{0}/{1}/{2}'.format(domain, cur_lang, url)
|
||||
# else:
|
||||
# return '{0}{1}'.format(domain, url)
|
||||
|
||||
|
||||
def get_domain_by_request(request):
|
||||
from project_sets import domain
|
||||
if request.query_params and 'domain' in request.query_params:
|
||||
return request.query_params['domain']
|
||||
return domain
|
||||
|
||||
|
||||
def get_cur_lang_by_request(request):
|
||||
from project_sets import lang
|
||||
if request.query_params and 'cur_lang' in request.query_params:
|
||||
return request.query_params['cur_lang']
|
||||
return lang
|
||||
# def get_domain_by_request(request):
|
||||
# from project_sets import domain
|
||||
# if request.query_params and 'domain' in request.query_params:
|
||||
# return request.query_params['domain']
|
||||
# return domain
|
||||
#
|
||||
#
|
||||
# def get_cur_lang_by_request(request):
|
||||
# from project_sets import lang
|
||||
# if request.query_params and 'cur_lang' in request.query_params:
|
||||
# return request.query_params['cur_lang']
|
||||
# return lang
|
||||
|
||||
|
||||
def get_img_type_by_request(request):
|
||||
@@ -416,6 +416,8 @@ def kill_pretexts(txt):
|
||||
return ' '.join(words)
|
||||
|
||||
|
||||
|
||||
|
||||
def stay_only_text_and_numbers(txt):
|
||||
bad_symbols = '"~`{}[]|!@#$%^&*()_+№;:?= '
|
||||
nums = '0123456789'
|
||||
|
||||
@@ -10,6 +10,12 @@ import re
|
||||
numbers = '0123456789.,'
|
||||
|
||||
|
||||
def get_fieldsNames_of_model(model):
|
||||
|
||||
fields_names = [item.name for item in model._meta.get_fields()]
|
||||
return fields_names
|
||||
|
||||
|
||||
def get_unique_url(model, name, url=None):
|
||||
from .functions import url_translit
|
||||
|
||||
|
||||
@@ -20,11 +20,7 @@ import random
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
# tech@truenergy.by
|
||||
# k7n2d3ZFZo4@CU5$4YDk
|
||||
|
||||
# administrator@truenergy.by
|
||||
# 6&#WfW8$qR2w8uv69e5$
|
||||
|
||||
|
||||
# def fix_mailing_links_in_mail(html):
|
||||
@@ -86,34 +82,20 @@ def prepare_xls_attach_by_xls_virtual_file(virtual_file, filename):
|
||||
return file
|
||||
|
||||
|
||||
def admin_send_mail_by_SMTPlib(subject, from_email, to, html_content, attachments=None):
|
||||
def admin_send_mail_by_SMTPlib(sets, subject, from_email, to, html_content, attachments=None):
|
||||
res = None
|
||||
|
||||
try:
|
||||
# smtp_server = 'mail.cln.by' # 'mail.truenergy.by'
|
||||
# smtp_port = 2525 # 587
|
||||
# smtp_password = 'clNdt6a8a' # u'98q3$IjxH%RUIxySw8R2'
|
||||
# smtp_login = 'support@cln.by' # 'support@truenergy.by'
|
||||
# from_email = smtp_login
|
||||
|
||||
try:
|
||||
smtp_server = 'mail.truenergy.by'
|
||||
smtp_port = 587
|
||||
smtp_password = 'eg4$#95Xp0T*V%ig5BbR'
|
||||
smtp_login = 'support@truenergy.by'
|
||||
res = send_mail_by_SMTPlib(subject, from_email, to, html_content, smtp_server, smtp_port, smtp_login,
|
||||
smtp_password, attachments)
|
||||
except:
|
||||
smtp_server = 'mail.truenergy.by'
|
||||
smtp_port = 25
|
||||
smtp_password = 'PowH@aL0a4%$iz0Uo5V$'
|
||||
smtp_login = 'tech@truenergy.by'
|
||||
res = send_mail_by_SMTPlib(subject, smtp_login, to, html_content, smtp_server, smtp_port, smtp_login,
|
||||
smtp_password, attachments)
|
||||
smtp_server = sets['mail_server_url']
|
||||
smtp_port = sets['mail_server_smtp_port']
|
||||
smtp_password = sets['sender_mail_password']
|
||||
smtp_login = sets['sender_mail_login']
|
||||
res = send_mail_by_SMTPlib(sets, subject, from_email, to, html_content, smtp_server, smtp_port, smtp_login,
|
||||
smtp_password, attachments)
|
||||
|
||||
|
||||
except Exception as e:
|
||||
# from Baldenini_site.SMS_sender import send_SMS
|
||||
# send_SMS(u'375296177827', u'send_mail_by_SMTPlib error = {0}'.format(str(e)), urgent=True)
|
||||
msg = 'admin_send_mail_by_SMTPlib error = {0}'.format(str(e))
|
||||
print(msg)
|
||||
# techSendMail(msg)
|
||||
@@ -121,17 +103,17 @@ def admin_send_mail_by_SMTPlib(subject, from_email, to, html_content, attachment
|
||||
return str(res)
|
||||
|
||||
|
||||
def send_mail_by_SMTPlib(subject, from_email, to_init, html_content, smtp_server, smtp_port, smtp_login, smtp_password,
|
||||
def send_mail_by_SMTPlib(sets, subject, from_email, to_init, html_content, smtp_server, smtp_port, smtp_login, smtp_password,
|
||||
attachments=None):
|
||||
to = to_init
|
||||
if not settings.prod_server:
|
||||
to = 'web@syncsystems.net'
|
||||
else:
|
||||
to = to_init
|
||||
try:
|
||||
from settings_local import DEBUG
|
||||
except:
|
||||
print('get settings_local fail')
|
||||
# if not settings.prod_server:
|
||||
# to = 'web@syncsystems.net'
|
||||
# else:
|
||||
# to = to_init
|
||||
# try:
|
||||
# from settings_local import DEBUG
|
||||
# except:
|
||||
# print('get settings_local fail')
|
||||
|
||||
res = None
|
||||
mail_lib = None
|
||||
@@ -163,16 +145,16 @@ def send_mail_by_SMTPlib(subject, from_email, to_init, html_content, smtp_server
|
||||
res = None
|
||||
|
||||
if type(to) in (list, tuple):
|
||||
if 'support@truenergy.by' in to:
|
||||
to.remove('support@truenergy.by')
|
||||
if sets['sender_email'] in to:
|
||||
to.remove(sets['sender_email'])
|
||||
|
||||
if len(to) > 1:
|
||||
to_str = u', '.join(to)
|
||||
else:
|
||||
to_str = to[0]
|
||||
else:
|
||||
if to == 'support@truenergy.by':
|
||||
return None
|
||||
# if to == sets['sender_email']:
|
||||
# return None
|
||||
to_str = to
|
||||
to = []
|
||||
to.append(to_str)
|
||||
@@ -216,8 +198,6 @@ def send_mail_by_SMTPlib(subject, from_email, to_init, html_content, smtp_server
|
||||
# print('mail_lib.quit = {0}'.format(str(msg)))
|
||||
|
||||
except Exception as e:
|
||||
# from Baldenini_site.SMS_sender import send_SMS
|
||||
# send_SMS(u'375296177827', u'send_mail_by_SMTPlib error = {0}'.format(str(e)), urgent=True)
|
||||
msg = 'send_mail_by_SMTPlib error = {0}'.format(str(e))
|
||||
print(msg)
|
||||
try:
|
||||
@@ -241,10 +221,10 @@ def send_mail_by_SMTPlib(subject, from_email, to_init, html_content, smtp_server
|
||||
return msg
|
||||
|
||||
|
||||
def sendMail(subject, text_content, from_email, to, html_content):
|
||||
def sendMail(sets, subject, text_content, from_email, to, html_content):
|
||||
print('sendMail to {0}'.format(str(to)))
|
||||
|
||||
admin_send_mail_by_SMTPlib(subject, from_email, [to], html_content)
|
||||
admin_send_mail_by_SMTPlib(sets, subject, from_email, [to], html_content)
|
||||
|
||||
# msg = EmailMultiAlternatives(subject, text_content, from_email, [to])
|
||||
# msg.attach_alternative(html_content, "text/html")
|
||||
@@ -253,52 +233,10 @@ def sendMail(subject, text_content, from_email, to, html_content):
|
||||
return u'Accept'
|
||||
|
||||
|
||||
# def techSendMail_for_top_management(html_content, title=None):
|
||||
# try:
|
||||
#
|
||||
# # if not prod_server:
|
||||
# # msg = '{0}. Not sended because is local'.format(html_content)
|
||||
# # print(msg)
|
||||
# # return msg
|
||||
# from AuthApp.models import User
|
||||
# from django.db.models import Q
|
||||
#
|
||||
# # to = ['web@syncsystems.net']
|
||||
# to = User.objects.filter(
|
||||
# Q(is_superuser=True) | Q(groups__name__in=[
|
||||
# 'Отдел продаж: Начальник отдела продаж', 'Управляющий',
|
||||
# 'Бухгалтерия: Главный бухгалтер'
|
||||
# ]),
|
||||
# is_active=True,
|
||||
# is_staff=True
|
||||
# ).values_list('email', flat=True)
|
||||
# to = list(to)
|
||||
# to.append('office@truenergy.by')
|
||||
#
|
||||
# print('techSendMail_for_top_management')
|
||||
# if title:
|
||||
# subject = title
|
||||
# else:
|
||||
# subject = u'truEnergy Data техническое оповещение'
|
||||
# from_email = 'support@truenergy.by'
|
||||
#
|
||||
# res = admin_send_mail_by_SMTPlib(subject, from_email, to, html_content)
|
||||
#
|
||||
# # msg = EmailMultiAlternatives(subject, text_content, from_email, to)
|
||||
# # msg.attach_alternative(html_content, "text/html")
|
||||
# # msg.send()
|
||||
# print(res)
|
||||
# return u'Accept'
|
||||
#
|
||||
# except Exception as e:
|
||||
# msg = 'techSendMail_for_top_management error={0}'.format(str(e))
|
||||
# techSendMail(msg)
|
||||
# print(msg)
|
||||
#
|
||||
# return 'Fail'
|
||||
|
||||
|
||||
def techSendMail_for_specified_email_list(html_content, email_list, title=None):
|
||||
|
||||
def techSendMail_for_specified_email_list(sets, html_content, email_list, title=None):
|
||||
try:
|
||||
|
||||
print('techSendMail_for_specified_email_list')
|
||||
@@ -308,41 +246,44 @@ def techSendMail_for_specified_email_list(html_content, email_list, title=None):
|
||||
subject = u'truEnergy Data техническое оповещение'
|
||||
from_email = 'support@truenergy.by'
|
||||
|
||||
res = admin_send_mail_by_SMTPlib(subject, from_email, email_list, html_content)
|
||||
res = admin_send_mail_by_SMTPlib(sets, subject, from_email, email_list, html_content)
|
||||
|
||||
print(res)
|
||||
return u'Accept'
|
||||
|
||||
except Exception as e:
|
||||
msg = 'techSendMail_for_specified_email_list error={0}'.format(str(e))
|
||||
techSendMail(msg)
|
||||
techSendMail(sets, msg)
|
||||
print(msg)
|
||||
|
||||
return 'Fail'
|
||||
|
||||
|
||||
def techSendMail(html_content, title=None, add_emails=None):
|
||||
def techSendMail(sets, html_content, title=None, add_emails=None):
|
||||
# if not prod_server:
|
||||
# msg = '{0}. Not sended because is local'.format(html_content)
|
||||
# print(msg)
|
||||
# return msg
|
||||
|
||||
print('techSendMail')
|
||||
project_name = ''
|
||||
if 'project_name' in sets:
|
||||
project_name = sets['project_name']
|
||||
|
||||
try:
|
||||
# subject = u'truEnergy Data техническое оповещение'
|
||||
from_email = 'support@truenergy.by'
|
||||
from_email = sets['sender_email']
|
||||
to = ['web@syncsystems.net']
|
||||
if add_emails:
|
||||
to.extend(add_emails)
|
||||
text_content = 'Technical message from truEnergy.'
|
||||
text_content = f'Technical message from {project_name}'
|
||||
|
||||
if title:
|
||||
subject = title
|
||||
else:
|
||||
subject = u'truEnergy Data техническое оповещение'
|
||||
subject = f'{project_name} - техническое оповещение'
|
||||
|
||||
res = admin_send_mail_by_SMTPlib(subject, from_email, to, html_content)
|
||||
res = admin_send_mail_by_SMTPlib(sets, subject, from_email, to, html_content)
|
||||
|
||||
print(res)
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
## -*- coding: utf-8 -*-
|
||||
__author__ = 'SDE'
|
||||
# from Baldenini_site.inter import jsonify
|
||||
|
||||
def get_error_message_Dict(show_icon=None):
|
||||
print('get_error_message_Dict')
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
__author__ = 'SDE'
|
||||
|
||||
def get_paging_Dict(request, elements_count, elements_on_page, from_page, to_page=None):
|
||||
def get_paging_Dict(request, elements_count, next_page_els_count, from_page, to_page=None):
|
||||
|
||||
|
||||
|
||||
pages_count = elements_count / elements_on_page
|
||||
if elements_count % elements_on_page > 0:
|
||||
pages_count = elements_count / next_page_els_count
|
||||
if elements_count % next_page_els_count > 0:
|
||||
pages_count = pages_count + 1
|
||||
|
||||
pages = []
|
||||
|
||||
@@ -8,7 +8,7 @@ def get_ld_search(domain):
|
||||
data = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebSite",
|
||||
"url": domain, #"https://truenergy.by/",
|
||||
"url": domain,
|
||||
"potentialAction": {
|
||||
"@type": "SearchAction",
|
||||
"target": {
|
||||
|
||||
@@ -1,258 +1,75 @@
|
||||
from BaseModels.inter import cut_to_number_w_point
|
||||
|
||||
|
||||
def generate_seotext_by_properties(product_data_Dict):
|
||||
|
||||
power_txt = ''
|
||||
ip_txt = ''
|
||||
lm_txt = ''
|
||||
temp_txt = ''
|
||||
install_txt = ''
|
||||
diametr_txt = ''
|
||||
|
||||
try:
|
||||
|
||||
if 'diameter' in product_data_Dict:
|
||||
val = int(product_data_Dict['diameter'])
|
||||
else:
|
||||
val = int(product_data_Dict['width'])
|
||||
|
||||
diametr_txt = '{0} truEnergy {1} серии {2}.<br>'.format(
|
||||
product_data_Dict['product_type']['name'].upper(),
|
||||
product_data_Dict['article'],
|
||||
product_data_Dict['product_series']['name'].upper()
|
||||
)
|
||||
|
||||
# if product_data_Dict['product_type']['name'] == 'Светильник светодиодный':
|
||||
#
|
||||
# if val < 100:
|
||||
# diametr_txt = '{0} truEnergy {1} серии {2} - это хорошее решение для дома.<br>'.format(
|
||||
# product_data_Dict['product_type']['name'].upper(),
|
||||
# product_data_Dict['article'],
|
||||
# product_data_Dict['product_series']['name'].upper()
|
||||
# )
|
||||
#
|
||||
# elif val < 150:
|
||||
# diametr_txt = '{0} truEnergy {1} серии {2} отлично подойдет для освещения вашей квартиры, дома или офиса.<br>'.format(
|
||||
# product_data_Dict['product_type']['name'].upper(),
|
||||
# product_data_Dict['article'],
|
||||
# product_data_Dict['product_series']['name'].upper()
|
||||
# )
|
||||
#
|
||||
# else:
|
||||
# diametr_txt = '{0} truEnergy {1} серии {2} - это энергоэффективное освещение для различных площадей и объектов.<br>'.format(
|
||||
# product_data_Dict['product_type']['name'].upper(),
|
||||
# product_data_Dict['article'],
|
||||
# product_data_Dict['product_series']['name'].upper()
|
||||
# )
|
||||
# # не светильник
|
||||
# else:
|
||||
# diametr_txt = '{0} truEnergy {1} серии {2} - это энергоэффективное решение для освещения различных пространств.<br>'.format(
|
||||
# product_data_Dict['product_type']['name'].upper(),
|
||||
# product_data_Dict['article'],
|
||||
# product_data_Dict['product_series']['name'].upper()
|
||||
# )
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
# ---------
|
||||
for property in product_data_Dict['properties_w_values_filtred']:
|
||||
|
||||
# ------
|
||||
|
||||
try:
|
||||
|
||||
if property['property']['name'] == 'Мощность':
|
||||
power = int(property['property_value'])
|
||||
|
||||
if power < 7:
|
||||
power_txt = 'Обладая низким энергопотреблением, этот {0} является заменой лампочки накаливания мощностью до 40 Ватт.<br>'.format(
|
||||
product_data_Dict['product_type']['name'].lower(),
|
||||
)
|
||||
|
||||
elif power < 13:
|
||||
power_txt = 'Энергоэффективность этого устройства позволяет использовть его в местах, ' \
|
||||
'где ранее использовались светильники с лампами накаливания мощностью до 75 Ватт.<br>'.format(
|
||||
)
|
||||
elif power < 19:
|
||||
power_txt = 'Этот {0} мощностью {1} Ватт легко заменит старые лампы накаливания мощностью до 100 Ватт ' \
|
||||
'или люминесцентные лампы мощностью до 40 Ватт.<br>'.format(
|
||||
product_data_Dict['product_type']['name'].lower(),
|
||||
str(power)
|
||||
)
|
||||
|
||||
elif power < 37:
|
||||
power_txt = 'Данная модель подходит для освещения больших пространств. ' \
|
||||
'Она не только поможет решить вопрос освещения, но и существенно сэкономит бюджет, ' \
|
||||
'выделенный на решение этой задачи.<br>'.format(
|
||||
product_data_Dict['product_type']['name'].lower(),
|
||||
)
|
||||
else:
|
||||
power_txt = '{0} Ватт, в данной модели обеспечивает мощный световой поток. ' \
|
||||
'Это дает возможность установки одного изделия для освещения помещений с большой ' \
|
||||
'площадью или открытых пространств.<br>'.format(
|
||||
str(power),
|
||||
product_data_Dict['product_type']['name'].lower(),
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
# ------
|
||||
|
||||
try:
|
||||
|
||||
if property['property']['name'] == 'Световой поток' and product_data_Dict['article'] != '11043':
|
||||
val = int(property['property_value'])
|
||||
|
||||
if product_data_Dict['product_type']['name'] == 'Светильник светодиодный':
|
||||
lm_txt = 'Один {0} данной модели способен осветить до {1} м.кв. площади ' \
|
||||
'для рабочих зон и жилых комнат, и до {2} м.кв. площади для проходных и подсобных помещений ' \
|
||||
'(при стандартной высоте потолка и нормальной освещенности помещения).<br>'.format(
|
||||
product_data_Dict['product_type']['name'].lower(),
|
||||
str(round(val / 300,2)),
|
||||
str(round(val / 120, 2)),
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
# -------
|
||||
|
||||
try:
|
||||
|
||||
if property['property']['name'] == 'IP (пылевлагозащита)':
|
||||
val = int(property['property_value'])
|
||||
|
||||
if val > 66:
|
||||
ip_txt = 'Максимальная защита IP{0} способна выдержать самые сильные испытания водой. ' \
|
||||
'Освещение с такой защитой используют для фонтанов и бассейнов.<br>'.format(
|
||||
str(val),
|
||||
)
|
||||
|
||||
elif val > 64:
|
||||
ip_txt = 'Данный продукт имеет высокую степень пылевлагозащиты - IP{0}. В связи с этим данная модель прекрасно подходит как ' \
|
||||
'для отапливаемых помещений с нормальным уровнем влажности, так и для помещений неотапливаемых, ' \
|
||||
'а также для эксплуатации на улице. Устройство с данной степенью защиты не боится пыли и влаги' \
|
||||
'а так же имеет защиту от струй воды со всех направлений.<br>'.format(
|
||||
str(val),
|
||||
)
|
||||
|
||||
elif val > 60:
|
||||
ip_txt = 'Степень защиты IP{0} обозначает полную защиту от брызг с любых сторон и имеет полную пылинепроницаемость ' \
|
||||
'(никакая пыль не может проникнуть внутрь корпуса устройства). ' \
|
||||
'Светильники подходят для установки в помещении и на улице, при рабочих температурах -20 до +40 градусов.<br>'.format(
|
||||
str(val),
|
||||
)
|
||||
|
||||
elif val > 53:
|
||||
ip_txt = 'У изделия с степенью защиты IP{0} снижена возможность попадания пыли внутрь корпуса ' \
|
||||
'и обеспечена полная защита расположенной внутри устройстав электроники.' \
|
||||
'Часто используют для рабочих помещений с повышенным содержанием пыли и влаги, а также под навесами.<br>'.format(
|
||||
str(val),
|
||||
product_data_Dict['product_type']['name'].lower(),
|
||||
product_data_Dict['product_type']['name_plural'].lower(),
|
||||
)
|
||||
|
||||
elif val > 40:
|
||||
ip_txt = 'Могут устанавливаться в помещения с повышенным уровнем пыли.'.format(
|
||||
product_data_Dict['product_type']['name'].lower(),
|
||||
)
|
||||
else:
|
||||
ip_txt = 'IP{0} - степень защиты данной модели, в связи с этим могут устанавливаться в' \
|
||||
' отапливаемые помещения с умеренным уровнем влажности.<br>'.format(
|
||||
str(val),
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
# -------
|
||||
|
||||
try:
|
||||
|
||||
if property['property']['name'] == 'Цветовая температура':
|
||||
val = int(property['property_value'])
|
||||
|
||||
if val < 3001:
|
||||
temp_txt = 'Теплый свет, генерируемый этой моделью способствует отдыху и расслаблению. ' \
|
||||
'Он приятен для глаз. В связи с этим рекомендуется устанавливать {0} ' \
|
||||
'с температурой {1}К в зоны отдыха, жилые комнаты и спальни, кафе, лаундж зоны. ' \
|
||||
'Очень удачное решение для обеденных и гостинных комнат.<br>'.format(
|
||||
product_data_Dict['product_type']['name_plural'].lower(),
|
||||
str(val),
|
||||
)
|
||||
|
||||
elif val < 4601:
|
||||
temp_txt = 'Модель обладает нейтральным цветом свечения, который прекрасно подходит и как для жилых помещений и комнат, ' \
|
||||
'так и для рабочих зон (офисов, кабинетов, производств) . ' \
|
||||
'Данный свет стимулирует к работе не вызывая перенапряжения глаз и не искажая цветопередачу. ' \
|
||||
'Универсальное и наиболее распространенное решение.<br>'.format(
|
||||
str(val),
|
||||
)
|
||||
|
||||
elif val < 7001:
|
||||
temp_txt = 'Цветовая температура {0}К - наиболее оптимально использование в помещениях промышленного назначения, ' \
|
||||
'административных зданиях, на производствах, складах, гаражах, паркингах. ' \
|
||||
'Однако могут применяться и в интерьере для создания акцентов в дизайне, ' \
|
||||
'либо если предпочтения потребителя отданы в пользу белого света. <br>'.format(
|
||||
str(val),
|
||||
)
|
||||
|
||||
|
||||
|
||||
else:
|
||||
temp_txt = 'От показателя цветовой температуры зависит то, как Вы будут воспринимать предметы и другие объекты освещенные устройством. ' \
|
||||
'С помощью цветовой температуры можно сделать более приятным отдых и улучшить эффективность работы. ' \
|
||||
'Отниситесь внимательно к выбору устройства по этому параметру.<br>'.format(
|
||||
str(val),
|
||||
)
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
# -------
|
||||
|
||||
try:
|
||||
|
||||
if property['property']['name'] == 'Тип монтажа':
|
||||
val = property['property_value']
|
||||
|
||||
if val == 'встраиваемый':
|
||||
install_txt = 'Устройство устанавливается в предварительно вырезанное в поверхности отверстие. ' \
|
||||
'Этот вариант монтажа используется для подвесных и натяжных потолков, а так же для фальш-стен и ниш.'.format(
|
||||
str(val),
|
||||
)
|
||||
|
||||
elif val == 'накладной':
|
||||
install_txt = 'Способ крепления - накладной. Значит эта модель может быть закреплена на любую ровную поверхность.'.format(
|
||||
str(val),
|
||||
)
|
||||
|
||||
elif val == 'встраиваемый/накладной':
|
||||
install_txt = '{0} обладает возможностью монтажа как в отверстия на поверхности плоскостей, так и на любую ровную поверхность.'.format(
|
||||
product_data_Dict['article'],
|
||||
)
|
||||
|
||||
else:
|
||||
pass
|
||||
|
||||
if 'height_visible_part' in product_data_Dict and product_data_Dict['height_visible_part']:
|
||||
install_txt = install_txt + ' Высота видимой части устройства после монтажа составит {0}мм.<br>'.format(
|
||||
str(round(product_data_Dict['height_visible_part']))
|
||||
)
|
||||
else:
|
||||
install_txt = install_txt + '<br>'
|
||||
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
product_data_Dict['seo_text'] = '{0}{1}{2}{3}{4}{5}'.format(
|
||||
diametr_txt,
|
||||
power_txt,
|
||||
lm_txt,
|
||||
ip_txt,
|
||||
temp_txt,
|
||||
install_txt
|
||||
)
|
||||
|
||||
return product_data_Dict
|
||||
# def generate_seotext_by_properties(product_data_Dict):
|
||||
#
|
||||
# power_txt = ''
|
||||
# ip_txt = ''
|
||||
# lm_txt = ''
|
||||
# temp_txt = ''
|
||||
# install_txt = ''
|
||||
# diametr_txt = ''
|
||||
#
|
||||
# try:
|
||||
#
|
||||
#
|
||||
#
|
||||
# except Exception as e:
|
||||
# pass
|
||||
#
|
||||
# # ---------
|
||||
# for property in product_data_Dict['properties_w_values_filtred']:
|
||||
#
|
||||
# # ------
|
||||
#
|
||||
# try:
|
||||
#
|
||||
#
|
||||
# except Exception as e:
|
||||
# pass
|
||||
#
|
||||
# # ------
|
||||
#
|
||||
# try:
|
||||
#
|
||||
#
|
||||
#
|
||||
# except Exception as e:
|
||||
# pass
|
||||
#
|
||||
# # -------
|
||||
#
|
||||
# try:
|
||||
#
|
||||
#
|
||||
#
|
||||
# except Exception as e:
|
||||
# pass
|
||||
#
|
||||
# # -------
|
||||
#
|
||||
# try:
|
||||
#
|
||||
#
|
||||
# except Exception as e:
|
||||
# pass
|
||||
#
|
||||
# # -------
|
||||
#
|
||||
# try:
|
||||
#
|
||||
#
|
||||
#
|
||||
# except Exception as e:
|
||||
# pass
|
||||
#
|
||||
# product_data_Dict['seo_text'] = '{0}{1}{2}{3}{4}{5}'.format(
|
||||
# diametr_txt,
|
||||
# power_txt,
|
||||
# lm_txt,
|
||||
# ip_txt,
|
||||
# temp_txt,
|
||||
# install_txt
|
||||
# )
|
||||
#
|
||||
# return product_data_Dict
|
||||
24
BaseModels/validators/form_field_validators.py
Normal file
24
BaseModels/validators/form_field_validators.py
Normal file
@@ -0,0 +1,24 @@
|
||||
from django.utils.translation import gettext as _
|
||||
from django.utils.safestring import mark_safe
|
||||
def get_phone_valid_error(val):
|
||||
allow_chars = '01234567890()+ -'
|
||||
|
||||
error_msg = mark_safe(_('Некорректные символы в номере, введите номер в международном формате с кодом страны'))
|
||||
|
||||
if not val:
|
||||
return None
|
||||
|
||||
if len(val) < 10:
|
||||
return error_msg
|
||||
|
||||
if '+' in val and val[0] != '+':
|
||||
return error_msg
|
||||
|
||||
i = 0
|
||||
while i < len(val):
|
||||
if val[i] not in allow_chars:
|
||||
return error_msg
|
||||
|
||||
i += 1
|
||||
|
||||
return None
|
||||
@@ -1,6 +1,11 @@
|
||||
from sets.admin import *
|
||||
from .models import *
|
||||
from django.contrib import admin
|
||||
from django import forms
|
||||
from django.forms import widgets
|
||||
|
||||
|
||||
|
||||
|
||||
class Admin_MsgGroup(Admin_BaseModel):
|
||||
list_display = [
|
||||
@@ -11,8 +16,33 @@ class Admin_MsgGroup(Admin_BaseModel):
|
||||
admin.site.register(MsgGroup,Admin_MsgGroup)
|
||||
|
||||
class Admin_Message(Admin_BaseModel):
|
||||
|
||||
def cut_group_text(self, obj):
|
||||
if obj.group:
|
||||
return obj.group.name[:10]
|
||||
return '-'
|
||||
cut_group_text.allow_tags = True
|
||||
cut_group_text.short_description = 'ticket'
|
||||
|
||||
|
||||
def cut_text(self, obj):
|
||||
if obj.text:
|
||||
if len(obj.text) > 20:
|
||||
return f'{obj.text[:20]}...'
|
||||
else:
|
||||
return obj.text
|
||||
return '-'
|
||||
cut_text.allow_tags = True
|
||||
cut_text.short_description = 'сообщение'
|
||||
|
||||
search_fields = ['group__name', 'text', 'name', 'id']
|
||||
|
||||
list_filter = ['status']
|
||||
|
||||
list_display = [
|
||||
'id', 'msg_type', 'group', 'status', 'sender', 'receiver', 'text',
|
||||
'id',
|
||||
# 'msg_type',
|
||||
'cut_group_text', 'status', 'sender', 'receiver', 'cut_text',
|
||||
'name',
|
||||
'order', 'modifiedDT', 'createDT'
|
||||
]
|
||||
|
||||
@@ -1,5 +1,341 @@
|
||||
import copy
|
||||
|
||||
from .models import *
|
||||
from django.db.models import Q
|
||||
from django.db.models import Q, Value as V, Count, OuterRef, Subquery
|
||||
from django.http import HttpResponse, Http404, JsonResponse
|
||||
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 django.template.loader import render_to_string
|
||||
from django.urls import reverse
|
||||
import json
|
||||
from datetime import datetime, time
|
||||
from django.conf import settings
|
||||
from AuthApp.funcs import get_user_timezone_Dict
|
||||
|
||||
|
||||
def get_unanswered_msgs_count_for_user(user):
|
||||
msgs = Message.objects.filter(receiver=user, status='sended', group=None)
|
||||
return msgs.count()
|
||||
|
||||
|
||||
|
||||
def get_update_chat_Dict(data):
|
||||
from AuthApp.models import User
|
||||
|
||||
res_Dict = {}
|
||||
msgs = []
|
||||
Dict = {}
|
||||
context_Dict = {}
|
||||
|
||||
last_message_modifiedDT = None
|
||||
|
||||
required_beep = False
|
||||
|
||||
required_full_support_chat_html = False
|
||||
|
||||
try:
|
||||
|
||||
if type(data) == str:
|
||||
data = json.loads(data)
|
||||
ticket = None
|
||||
|
||||
tpl_name = 'blocks/profile/b_messages_container.html'
|
||||
|
||||
if 'ticket_id' in data and data['ticket_id'] and data['ticket_id'] != 'null':
|
||||
ticket = MsgGroup.objects.get(id=data['ticket_id'])
|
||||
res_Dict.update({'ticket': ticket.id})
|
||||
|
||||
sender = User.objects.get(id=data['sender'])
|
||||
receiver = None
|
||||
if 'receiver' in data and data['receiver']:
|
||||
receiver = User.objects.get(id=data['receiver'])
|
||||
|
||||
if data['sender'] == data['cur_user']:
|
||||
user = copy.copy(sender)
|
||||
cur_receiver = copy.copy(receiver)
|
||||
else:
|
||||
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': cur_receiver,
|
||||
'user': user,
|
||||
})
|
||||
context_Dict.update(get_user_timezone_Dict(user))
|
||||
|
||||
if sender == receiver:
|
||||
print('!')
|
||||
|
||||
required_beep = data['required_beep']
|
||||
|
||||
|
||||
if not ticket:
|
||||
|
||||
if data['receiver'] == data['cur_user']:
|
||||
# получаем правую панель с получателями
|
||||
# получатели
|
||||
receivers, unread_msgs_count = get_chat_receivers_for_user(receiver)
|
||||
|
||||
|
||||
# формируем правую панель
|
||||
context_Dict.update({
|
||||
'receivers': receivers,
|
||||
'MEDIA_URL': settings.MEDIA_URL
|
||||
})
|
||||
users_list_html = render_to_string(
|
||||
'blocks/profile/b_list_of_users_messenger.html', context_Dict)
|
||||
res_Dict.update({
|
||||
'users_list_html': users_list_html,
|
||||
'unread_msgs_count': unread_msgs_count
|
||||
})
|
||||
|
||||
msgs = get_msgs_for_chat_w_users(sender, receiver)
|
||||
|
||||
if ticket:
|
||||
msgs = get_messages_for_ticket(ticket)
|
||||
# если меньше 3 сообщений значит выведена не полная форма - требуется другой шаблон
|
||||
if len(msgs) < 3 and data['receiver'] == data['cur_user']:
|
||||
tpl_name = 'blocks/profile/b_support_chat.html'
|
||||
required_full_support_chat_html = True
|
||||
elif 'bad_manager' in data:
|
||||
tpl_name = 'blocks/profile/b_support_chat.html'
|
||||
required_full_support_chat_html = True
|
||||
|
||||
context_Dict.update({'ticket': ticket})
|
||||
if ticket.manager:
|
||||
context_Dict.update({'new_msg_allow': True})
|
||||
|
||||
context_Dict.update({
|
||||
'messages': msgs,
|
||||
'MEDIA_URL': settings.MEDIA_URL,
|
||||
})
|
||||
html = render_to_string(tpl_name, context_Dict)
|
||||
if required_full_support_chat_html:
|
||||
res_Dict.update({'support_chat_html': html})
|
||||
else:
|
||||
res_Dict.update({'chat_html': html})
|
||||
|
||||
|
||||
res_Dict.update({
|
||||
'required_beep': required_beep,
|
||||
})
|
||||
return res_Dict
|
||||
|
||||
except Exception as e:
|
||||
msg = f'update_chat_ajax2 Error = {str(e)}'
|
||||
return {'error': msg}
|
||||
|
||||
|
||||
def send_msg(data):
|
||||
from AuthApp.models import User
|
||||
import base64
|
||||
import os
|
||||
|
||||
res_Dict = {}
|
||||
msg = None
|
||||
required_update_tickets_list_wo_managers = False
|
||||
|
||||
try:
|
||||
if type(data) == str:
|
||||
data = json.loads(data)
|
||||
|
||||
ticket = None
|
||||
|
||||
tpl_name = 'blocks/profile/b_messages_container.html'
|
||||
|
||||
if 'text' in data or 'files' in data:
|
||||
|
||||
if 'ticket_id' in data:
|
||||
ticket = MsgGroup.objects.get(id=data['ticket_id'])
|
||||
|
||||
sender = User.objects.get(id=data['sender'])
|
||||
receiver = User.objects.get(id=data['receiver'])
|
||||
|
||||
msg_create_kwargs = {}
|
||||
|
||||
# если только что манагер присоединился к тикету
|
||||
if ticket:
|
||||
required_update_tickets_list_wo_managers = True
|
||||
if not ticket.manager:
|
||||
if sender.is_staff:
|
||||
ticket.manager = sender
|
||||
else:
|
||||
ticket.manager = receiver
|
||||
|
||||
ticket.save()
|
||||
|
||||
# создаем сообщение на базе темы и сообщения введенных пользователем при создании тикета
|
||||
kwargs = {
|
||||
'sender': ticket.owner,
|
||||
'receiver': ticket.manager,
|
||||
'text': ticket.text,
|
||||
'group': ticket,
|
||||
}
|
||||
|
||||
msg = Message.objects.create(**kwargs)
|
||||
Message.objects.filter(id=msg.id).update(modifiedDT=ticket.createDT, createDT=ticket.createDT)
|
||||
# ------------------------
|
||||
|
||||
else:
|
||||
if not sender in (ticket.owner, ticket.manager) or not receiver in (ticket.owner, ticket.manager):
|
||||
return {
|
||||
'msg': None,
|
||||
'required_update_tickets_list_wo_managers': required_update_tickets_list_wo_managers
|
||||
}
|
||||
|
||||
res_Dict.update({
|
||||
'ticket': ticket,
|
||||
})
|
||||
|
||||
msg_create_kwargs.update({
|
||||
'group': ticket,
|
||||
})
|
||||
|
||||
res_Dict.update(get_ticketsDict_for_staff(sender))
|
||||
|
||||
# if not msg:
|
||||
msg_create_kwargs.update({
|
||||
'sender': sender,
|
||||
'receiver': receiver,
|
||||
})
|
||||
|
||||
if 'text' in data:
|
||||
msg_create_kwargs.update({'text': data['text']})
|
||||
|
||||
msg = Message.objects.create(**msg_create_kwargs)
|
||||
|
||||
if 'files' in data:
|
||||
files_list = []
|
||||
for file in data['files']:
|
||||
file_data =json.loads(file)
|
||||
|
||||
if not os.path.exists(f'chat_file_storage/{msg.id}'):
|
||||
os.makedirs(f'chat_file_storage/{msg.id}')
|
||||
f = open(f'chat_file_storage/{msg.id}/{file_data["file_name"]}', 'wb+')
|
||||
head, content = file_data['file'].split(',')
|
||||
content = base64.b64decode(content)
|
||||
f.write(content)
|
||||
f.close()
|
||||
|
||||
del file_data['file']
|
||||
files_list.append(file_data)
|
||||
msg.files = files_list
|
||||
msg.save(update_fields=['files'])
|
||||
|
||||
|
||||
|
||||
# if ticket:
|
||||
# msgs = get_messages_for_ticket(ticket)
|
||||
# else:
|
||||
# msgs = get_msgs_for_chat_w_users(sender, receiver)
|
||||
#
|
||||
# receivers, unread_msgs_count = get_chat_receivers_for_user(sender)
|
||||
#
|
||||
# res_Dict.update({
|
||||
# 'messages': msgs,
|
||||
# 'cur_receiver': receiver,
|
||||
# 'receivers': receivers,
|
||||
# 'text': data['text'],
|
||||
# 'modifiedDT': msgs[0].modifiedDT
|
||||
# })
|
||||
#
|
||||
# html = render_to_string(tpl_name, res_Dict)
|
||||
# return {'html': html, 'sender': data['sender']}
|
||||
return {
|
||||
'msg': msg,
|
||||
'required_update_tickets_list_wo_managers': required_update_tickets_list_wo_managers
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
msg = f'send_msg_ajax Error = {str(e)}'
|
||||
print(msg)
|
||||
# return {'error': msg}
|
||||
return {
|
||||
'msg': msg,
|
||||
'required_update_tickets_list_wo_managers': required_update_tickets_list_wo_managers
|
||||
}
|
||||
|
||||
|
||||
|
||||
# def get_create_route_for_customer_page_content_Dict(request):
|
||||
# from AuthApp.models import User
|
||||
#
|
||||
# msgs = []
|
||||
# try:
|
||||
# cur_receiver = User.objects.get(id=receiver_id)
|
||||
#
|
||||
# msgs = get_msgs_for_chat_w_users(request.user, cur_receiver)
|
||||
# msgs.filter(receiver=request.user).update(status='seen')
|
||||
#
|
||||
# except User.DoesNotExist:
|
||||
# cur_receiver = None
|
||||
#
|
||||
# receivers, unread_msgs_count = get_chat_receivers_for_user(request.user)
|
||||
#
|
||||
# Dict = {
|
||||
# 'cur_receiver': cur_receiver,
|
||||
# 'messages': msgs,
|
||||
# 'receivers': receivers,
|
||||
# 'page': 'chat',
|
||||
# }
|
||||
# return Dict
|
||||
|
||||
|
||||
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:
|
||||
cur_receiver = User.objects.get(id=receiver_id)
|
||||
|
||||
msgs = get_msgs_for_chat_w_users(request.user, cur_receiver)
|
||||
msgs.filter(receiver=request.user).update(status='seen')
|
||||
|
||||
except User.DoesNotExist:
|
||||
cur_receiver = None
|
||||
|
||||
receivers, unread_msgs_count = get_chat_receivers_for_user(request.user)
|
||||
|
||||
Dict = {
|
||||
'cur_receiver': cur_receiver,
|
||||
'messages': msgs,
|
||||
'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)
|
||||
return html
|
||||
|
||||
def get_chat_page_content_Dict(request, receiver_id=None):
|
||||
from AuthApp.models import User
|
||||
|
||||
msgs = []
|
||||
try:
|
||||
cur_receiver = User.objects.get(id=receiver_id)
|
||||
|
||||
msgs = get_msgs_for_chat_w_users(request.user, cur_receiver)
|
||||
msgs.filter(receiver=request.user).update(status='seen')
|
||||
|
||||
except User.DoesNotExist:
|
||||
cur_receiver = None
|
||||
|
||||
receivers, unread_msgs_count = get_chat_receivers_for_user(request.user)
|
||||
|
||||
Dict = {
|
||||
'cur_receiver': cur_receiver,
|
||||
'messages': msgs,
|
||||
'receivers': receivers,
|
||||
'page': 'chat',
|
||||
}
|
||||
return Dict
|
||||
|
||||
|
||||
def get_msgs_for_chat_w_users(user1, user2):
|
||||
@@ -8,20 +344,69 @@ def get_msgs_for_chat_w_users(user1, user2):
|
||||
Q(sender=user1) | Q(receiver=user1),
|
||||
Q(sender=user2) | Q(receiver=user2),
|
||||
group=None
|
||||
)
|
||||
).order_by('-modifiedDT')
|
||||
return msgs
|
||||
|
||||
def get_chat_receivers_for_user(user):
|
||||
receivers = Message.objects.filter(
|
||||
def get_chat_receivers_for_user(user, cur_receiver=None):
|
||||
msgs = Message.objects.filter(
|
||||
Q(sender=user) | Q(receiver=user),
|
||||
group=None
|
||||
).order_by('-modifiedDT').values('sender', 'receiver')
|
||||
).order_by('-modifiedDT')#.select_related('sender', 'receiver').values('sender', 'receiver').distinct()
|
||||
|
||||
receivers_list = []
|
||||
receivers_list.extend([item['sender'] for item in receivers if item['sender'] != user])
|
||||
receivers_list.extend([item['receiver'] for item in receivers if item['receiver'] != user])
|
||||
|
||||
return receivers_list
|
||||
unread_msgs_count = 0
|
||||
|
||||
for msg in msgs:
|
||||
if msg.receiver not in receivers_list and msg.receiver != user:
|
||||
msg.receiver.unread_msgs_count = 0
|
||||
if msg.text:
|
||||
msg.receiver.last_msg = msg.text
|
||||
elif msg.files:
|
||||
msg.receiver.last_msg = msg.files[len(msg.files)-1]['file_name']
|
||||
receivers_list.append(msg.receiver)
|
||||
|
||||
|
||||
|
||||
if msg.sender not in receivers_list and msg.sender != user:
|
||||
msg.sender.unread_msgs_count = 0
|
||||
receivers_list.append(msg.sender)
|
||||
if msg.text:
|
||||
msg.sender.last_msg = msg.text
|
||||
elif msg.files:
|
||||
msg.sender.last_msg = msg.files[len(msg.files)-1]['file_name']
|
||||
|
||||
if msg.status == 'sended':
|
||||
i = receivers_list.index(msg.sender)
|
||||
receivers_list[i].unread_msgs_count += 1
|
||||
unread_msgs_count += 1
|
||||
|
||||
# if msg.status == 'sended':
|
||||
# i = receivers_list.index(msg.sender)
|
||||
# receivers_list[i].unread_msgs_count += 1
|
||||
# unread_msgs_count += 1
|
||||
|
||||
# if msg.receiver == user:# and (not cur_receiver or msg.sender != cur_receiver):
|
||||
# if msg.status == 'sended':
|
||||
# i = receivers_list.index(msg.sender)
|
||||
# receivers_list[i].unread_msgs_count += 1
|
||||
# unread_msgs_count += 1
|
||||
|
||||
return receivers_list, unread_msgs_count
|
||||
|
||||
# receivers_list.extend((item.sender for item in receivers if item.sender != user))
|
||||
# receivers_list.extend((item.receiver for item in receivers if item.receiver != user))
|
||||
#
|
||||
# return list(set(receivers_list))
|
||||
|
||||
|
||||
def get_tickets_Dict_by_manager(user):
|
||||
tickets = MsgGroup.objects.filter(enable=True, manager=user).order_by('-modifiedDT')
|
||||
|
||||
Dict = {
|
||||
'tickets': tickets,
|
||||
}
|
||||
return Dict
|
||||
|
||||
def get_messages_for_ticket(ticket):
|
||||
return ticket.rel_messages_for_group.filter(enable=True).order_by('-modifiedDT')
|
||||
@@ -36,12 +421,38 @@ def get_ticketsDict_for_staff(user):
|
||||
|
||||
def get_tickets_wo_manager():
|
||||
|
||||
tickets = MsgGroup.objects.filter(enable=True, manager=None)
|
||||
tickets = MsgGroup.objects.filter(
|
||||
enable=True, manager=None
|
||||
).annotate(
|
||||
unread_msgs_count=V(1)
|
||||
).order_by('-modifiedDT')
|
||||
|
||||
|
||||
return tickets
|
||||
|
||||
def get_tickets_for_manager(user):
|
||||
unread_msgs = Message.objects.filter(
|
||||
group=31, status='sended', receiver=user
|
||||
)
|
||||
|
||||
unread_msgs = Message.objects.filter(
|
||||
group=OuterRef('pk'), status='sended', receiver=user
|
||||
).values('id')[:1]
|
||||
|
||||
msgs = Message.objects.filter(
|
||||
group=OuterRef('pk')
|
||||
).order_by('-modifiedDT').values('modifiedDT')[:1]
|
||||
|
||||
tickets = MsgGroup.objects.filter(
|
||||
enable=True, manager=user
|
||||
).annotate(
|
||||
unread_msgs_count = Count(Subquery(unread_msgs)),
|
||||
last_msg_modifiedDT = Subquery(msgs)
|
||||
# unread_msgs_count=Count(
|
||||
# 'rel_messages_for_group',
|
||||
# filter=Q(rel_messages_for_group__status='sended', rel_messages_for_group__receiver=user)
|
||||
# )
|
||||
).order_by('-unread_msgs_count', '-last_msg_modifiedDT')
|
||||
|
||||
tickets = MsgGroup.objects.filter(enable=True, manager=user)
|
||||
|
||||
return tickets
|
||||
@@ -10,5 +10,9 @@ urlpatterns = [
|
||||
path('support_create_ticket_form/', support_create_ticket_form_ajax, name='support_create_ticket_form_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'),
|
||||
# path('send_msg/', send_msg_ajax, name='send_msg_ajax'),
|
||||
# path('update_chat/', update_chat_ajax2, name='update_chat_ajax'),
|
||||
path('show_chat_w_user/', show_chat_w_user_ajax, name='show_chat_w_user_ajax'),
|
||||
|
||||
path('get_file_from_msg/', get_file_from_msg_ajax, name='get_file_from_msg_ajax'),
|
||||
]
|
||||
@@ -13,83 +13,368 @@ from django.template.loader import render_to_string
|
||||
from django.urls import reverse
|
||||
from .funcs import *
|
||||
import json
|
||||
from datetime import datetime, time
|
||||
from channels.layers import get_channel_layer
|
||||
from asgiref.sync import async_to_sync
|
||||
|
||||
|
||||
@login_required(login_url='/profile/login/')
|
||||
def send_msg_ajax(request):
|
||||
def get_file_from_msg_ajax(request):
|
||||
|
||||
if request.method != 'POST':
|
||||
raise Http404
|
||||
|
||||
try:
|
||||
|
||||
data = json.loads(request.body)
|
||||
msg = Message.objects.get(id=data['message_id'])
|
||||
|
||||
res_Dict = {}
|
||||
for file in msg.files:
|
||||
if file['file_name'] == data['file_name']:
|
||||
res_Dict = file
|
||||
break
|
||||
|
||||
return JsonResponse(res_Dict, status=200)
|
||||
|
||||
except Exception as e:
|
||||
msg = f'get_file_from_msg_ajax Error = {str(e)}'
|
||||
return JsonResponse({'error': msg}, status=400)
|
||||
|
||||
|
||||
|
||||
@login_required(login_url='/profile/login/')
|
||||
def show_chat_w_user_ajax(request):
|
||||
|
||||
if request.method != 'POST':
|
||||
raise Http404
|
||||
|
||||
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)
|
||||
|
||||
except Exception as e:
|
||||
msg = f'show_chat_w_user_ajax Error = {str(e)}'
|
||||
return JsonResponse({'error': msg}, status=400)
|
||||
|
||||
|
||||
|
||||
def update_chat_ajax2(request):
|
||||
from AuthApp.models import User
|
||||
|
||||
if request.method != 'POST':
|
||||
raise Http404
|
||||
|
||||
res_Dict = {}
|
||||
msgs = []
|
||||
Dict = {}
|
||||
context_Dict = {}
|
||||
|
||||
last_message_modifiedDT = None
|
||||
|
||||
required_beep = False
|
||||
|
||||
try:
|
||||
|
||||
data = json.loads(request.body)
|
||||
ticket = None
|
||||
|
||||
if data['text']:
|
||||
tpl_name = 'blocks/profile/b_messages_container.html'
|
||||
|
||||
|
||||
if 'ticket_id' in data:
|
||||
ticket = MsgGroup.objects.get(id=data['ticket_id'])
|
||||
if 'ticket_id' in data and data['ticket_id'] and data['ticket_id'] != 'null':
|
||||
ticket = MsgGroup.objects.get(id=data['ticket_id'])
|
||||
|
||||
sender = User.objects.get(id=data['sender'])
|
||||
sender = User.objects.get(id=data['sender'])
|
||||
receiver = None
|
||||
if 'receiver' in data and data['receiver']:
|
||||
receiver = User.objects.get(id=data['receiver'])
|
||||
|
||||
# если только что манагер присоединился к тикету
|
||||
if ticket and not ticket.manager:
|
||||
if sender.is_staff:
|
||||
ticket.manager = sender
|
||||
else:
|
||||
ticket.manager = receiver
|
||||
context_Dict.update({'cur_receiver': receiver})
|
||||
context_Dict.update(get_user_timezone_Dict(request.user, request=request))
|
||||
|
||||
ticket.save()
|
||||
if not ticket:
|
||||
|
||||
kwargs = {
|
||||
'sender': ticket.owner,
|
||||
'receiver': ticket.manager,
|
||||
'text': ticket.text,
|
||||
}
|
||||
# получаем правую панель с получателями
|
||||
# получатели
|
||||
receivers, unread_msgs_count = get_chat_receivers_for_user(request.user, receiver)
|
||||
# собираем для сохранения в профиле
|
||||
receivers_unread_msgs_count = sorted(
|
||||
[{'id': item.id, 'unread_msgs_count': item.unread_msgs_count} for item in receivers],
|
||||
key=lambda d: d['id'])
|
||||
# забираем данные из профиля
|
||||
saved_receivers_unread_msgs_count = request.user.user_profile.get_node_by_name(
|
||||
'receivers_unread_msgs_count')
|
||||
# если данных нет или данные поменялись
|
||||
if saved_receivers_unread_msgs_count == None or receivers_unread_msgs_count != saved_receivers_unread_msgs_count:
|
||||
# записываем данные в профиль
|
||||
request.user.user_profile.add_node_to_json_data(
|
||||
{'receivers_unread_msgs_count': receivers_unread_msgs_count}, save=True)
|
||||
# разрешаем сигнал
|
||||
required_beep = True
|
||||
|
||||
if ticket:
|
||||
kwargs.update({'group': ticket})
|
||||
# формируем правую панель
|
||||
context_Dict.update({'receivers': receivers})
|
||||
|
||||
msg = Message.objects.create(**kwargs)
|
||||
Message.objects.filter(id=msg.id).update(modifiedDT=ticket.createDT, createDT=ticket.createDT)
|
||||
# ------------
|
||||
users_list_html = render_to_string(
|
||||
'blocks/profile/b_list_of_users_messenger.html', context_Dict, request=request)
|
||||
res_Dict.update({
|
||||
'users_list_html': users_list_html,
|
||||
'unread_msgs_count': unread_msgs_count
|
||||
})
|
||||
|
||||
kwargs = {
|
||||
'sender': sender,
|
||||
'receiver': receiver,
|
||||
'text': data['text']
|
||||
}
|
||||
|
||||
if ticket:
|
||||
kwargs.update({'group': ticket})
|
||||
if sender and receiver:
|
||||
msgs = get_msgs_for_chat_w_users(sender, receiver)
|
||||
unreaded_msgs = msgs.filter(status='sended')
|
||||
if msgs and unreaded_msgs:
|
||||
context_Dict.update({'messages': msgs})
|
||||
chat_html = render_to_string(tpl_name, context_Dict, request=request)
|
||||
res_Dict.update({'chat_html': chat_html})
|
||||
required_beep = True
|
||||
unreaded_msgs.update(status='seen')
|
||||
|
||||
msg = Message.objects.create(**kwargs)
|
||||
|
||||
|
||||
res_Dict.update({
|
||||
'ticket': ticket,
|
||||
'messages': get_messages_for_ticket(ticket)
|
||||
'required_beep': required_beep,
|
||||
})
|
||||
res_Dict.update(get_ticketsDict_for_staff(request.user))
|
||||
|
||||
tpl_name = 'blocks/profile/b_support_chat.html'
|
||||
|
||||
html = render_to_string(tpl_name, res_Dict, request=request)
|
||||
return JsonResponse({'html': html}, status=200)
|
||||
return JsonResponse(res_Dict, status=200)
|
||||
|
||||
except Exception as e:
|
||||
msg = f'send_msg_ajax Error = {str(e)}'
|
||||
msg = f'update_chat_ajax2 Error = {str(e)}'
|
||||
return JsonResponse({'error': msg}, status=400)
|
||||
|
||||
|
||||
|
||||
|
||||
def update_chat_ajax(request):
|
||||
from AuthApp.models import User
|
||||
|
||||
if request.method != 'POST':
|
||||
raise Http404
|
||||
|
||||
res_Dict = {}
|
||||
msgs = []
|
||||
Dict = {}
|
||||
context_Dict = {}
|
||||
|
||||
last_message_modifiedDT = None
|
||||
|
||||
required_beep = False
|
||||
|
||||
try:
|
||||
|
||||
data = json.loads(request.body)
|
||||
ticket = None
|
||||
|
||||
tpl_name = 'blocks/profile/b_messages_container.html'
|
||||
|
||||
|
||||
if 'ticket_id' in data and data['ticket_id'] and data['ticket_id'] != 'null':
|
||||
ticket = MsgGroup.objects.get(id=data['ticket_id'])
|
||||
|
||||
if 'last_message_modifiedDT' in data:
|
||||
last_message_modifiedDT = datetime.strptime(data['last_message_modifiedDT'], '%d.%m.%Y %H:%M:%S:%f')
|
||||
|
||||
sender = User.objects.get(id=data['sender'])
|
||||
receiver = None
|
||||
if 'receiver' in data and data['receiver']:
|
||||
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:
|
||||
|
||||
context_Dict.update({
|
||||
'ticket': ticket,
|
||||
})
|
||||
|
||||
msgs = get_messages_for_ticket(ticket)
|
||||
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({
|
||||
'tickets_list_html': tickets_list_html,
|
||||
'msgs_count': len(msgs)
|
||||
})
|
||||
else:
|
||||
|
||||
# получаем правую панель с получателями
|
||||
receivers, unread_msgs_count = get_chat_receivers_for_user(request.user, receiver)
|
||||
receivers_unread_msgs_count = sorted([{'id':item.id, 'unread_msgs_count': item.unread_msgs_count} for item in receivers], key=lambda d: d['id'])
|
||||
saved_receivers_unread_msgs_count = request.user.user_profile.get_node_by_name('receivers_unread_msgs_count')
|
||||
if saved_receivers_unread_msgs_count == None or receivers_unread_msgs_count != saved_receivers_unread_msgs_count:
|
||||
request.user.user_profile.add_node_to_json_data(
|
||||
{'receivers_unread_msgs_count': receivers_unread_msgs_count}, save=True)
|
||||
# if unread_msgs_count:
|
||||
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({
|
||||
'users_list_html': users_list_html,
|
||||
'unread_msgs_count': unread_msgs_count
|
||||
})
|
||||
|
||||
# если есть получатель - получаем сообщения чата
|
||||
if receiver:
|
||||
msgs = get_msgs_for_chat_w_users(sender, receiver)
|
||||
unreaded_msgs = msgs.filter(status='sended')
|
||||
if msgs and unreaded_msgs:
|
||||
context_Dict.update({'messages': msgs})
|
||||
chat_html = render_to_string(tpl_name, context_Dict, request=request)
|
||||
res_Dict.update({'chat_html': chat_html})
|
||||
required_beep = True
|
||||
unreaded_msgs.update(status='seen')
|
||||
|
||||
# if not msgs or (request.user != msgs[0].receiver) or (not msgs and not last_message_modifiedDT) or (msgs and last_message_modifiedDT and msgs[0].modifiedDT <= last_message_modifiedDT):
|
||||
# Dict.update({
|
||||
# 'required_beep': False
|
||||
# })
|
||||
# return JsonResponse(Dict, status=200)
|
||||
|
||||
|
||||
|
||||
res_Dict.update({
|
||||
'required_beep': required_beep,
|
||||
})
|
||||
return JsonResponse(res_Dict, status=200)
|
||||
|
||||
except Exception as e:
|
||||
msg = f'update_chat_ajax Error = {str(e)}'
|
||||
return JsonResponse({'error': msg}, status=400)
|
||||
|
||||
|
||||
# @login_required(login_url='/profile/login/')
|
||||
# def send_msg_ajax(request):
|
||||
# from AuthApp.models import User
|
||||
#
|
||||
# if request.method != 'POST':
|
||||
# raise Http404
|
||||
#
|
||||
# res_Dict = {}
|
||||
# msg = None
|
||||
#
|
||||
# try:
|
||||
#
|
||||
# data = json.loads(request.body)
|
||||
# ticket = None
|
||||
#
|
||||
# tpl_name = 'blocks/profile/b_messages_container.html'
|
||||
#
|
||||
# if data['text']:
|
||||
#
|
||||
#
|
||||
# if 'ticket_id' in data:
|
||||
# ticket = MsgGroup.objects.get(id=data['ticket_id'])
|
||||
#
|
||||
# sender = User.objects.get(id=data['sender'])
|
||||
# receiver = User.objects.get(id=data['receiver'])
|
||||
#
|
||||
# msg_create_kwargs = {}
|
||||
#
|
||||
# # если только что манагер присоединился к тикету
|
||||
# if ticket:
|
||||
# if not ticket.manager:
|
||||
# if sender.is_staff:
|
||||
# ticket.manager = sender
|
||||
# else:
|
||||
# ticket.manager = receiver
|
||||
#
|
||||
# ticket.save()
|
||||
#
|
||||
# kwargs = {
|
||||
# 'sender': ticket.owner,
|
||||
# 'receiver': ticket.manager,
|
||||
# 'text': ticket.text,
|
||||
# }
|
||||
#
|
||||
# kwargs.update({'group': ticket})
|
||||
#
|
||||
# msg = Message.objects.create(**kwargs)
|
||||
# Message.objects.filter(id=msg.id).update(modifiedDT=ticket.createDT, createDT=ticket.createDT)
|
||||
#
|
||||
# # if
|
||||
#
|
||||
# res_Dict.update({
|
||||
# 'ticket': ticket,
|
||||
# # 'cur_receiver': receiver,
|
||||
# # 'messages': get_messages_for_ticket(ticket),
|
||||
# # 'text': data['text'],
|
||||
# # 'modifiedDT': msg.modifiedDT
|
||||
# })
|
||||
#
|
||||
# msg_create_kwargs.update({
|
||||
# 'group': ticket,
|
||||
# })
|
||||
#
|
||||
# res_Dict.update(get_ticketsDict_for_staff(request.user))
|
||||
#
|
||||
#
|
||||
# # if not msg:
|
||||
# msg_create_kwargs.update({
|
||||
# 'sender': sender,
|
||||
# 'receiver': receiver,
|
||||
# 'text': data['text']
|
||||
# })
|
||||
#
|
||||
# session_data = {
|
||||
# 'for_save_to_session':{
|
||||
# 'user_alerts':{
|
||||
# 'new_message': True
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
#
|
||||
# receiver.user_profile.add_node_to_json_data(session_data, save=True)
|
||||
#
|
||||
# msg = Message.objects.create(**msg_create_kwargs)
|
||||
#
|
||||
# if ticket:
|
||||
# msgs = get_messages_for_ticket(ticket)
|
||||
# else:
|
||||
# msgs = get_msgs_for_chat_w_users(sender, receiver)
|
||||
#
|
||||
# receivers, unread_msgs_count = get_chat_receivers_for_user(request.user)
|
||||
#
|
||||
#
|
||||
# res_Dict.update({
|
||||
# 'messages': msgs,
|
||||
# 'cur_receiver': receiver,
|
||||
# 'receivers': receivers,
|
||||
# 'text': data['text'],
|
||||
# 'modifiedDT': msgs[0].modifiedDT
|
||||
# })
|
||||
#
|
||||
#
|
||||
# html = render_to_string(tpl_name, res_Dict, request=request)
|
||||
# return JsonResponse({'html': html}, status=200)
|
||||
#
|
||||
# except Exception as e:
|
||||
# msg = f'send_msg_ajax Error = {str(e)}'
|
||||
# return JsonResponse({'error': msg}, status=400)
|
||||
|
||||
|
||||
|
||||
|
||||
@login_required(login_url='/profile/login/')
|
||||
def support_show_chat_by_ticket_ajax(request):
|
||||
|
||||
@@ -102,14 +387,38 @@ def support_show_chat_by_ticket_ajax(request):
|
||||
|
||||
ticket = MsgGroup.objects.get(id=data['ticket_id'])
|
||||
|
||||
msgs = get_messages_for_ticket(ticket)
|
||||
|
||||
new_msg_allow = False
|
||||
cur_receiver = None
|
||||
if request.user.is_staff:
|
||||
cur_receiver = ticket.owner
|
||||
new_msg_allow = True
|
||||
else:
|
||||
if ticket.manager:
|
||||
cur_receiver = ticket.manager
|
||||
# if len(msgs) > 1:
|
||||
new_msg_allow = True
|
||||
|
||||
seen_msgs = msgs.filter(receiver=request.user, status='sended')
|
||||
if seen_msgs:
|
||||
seen_msgs.update(status='seen')
|
||||
msgs = get_messages_for_ticket(ticket)
|
||||
|
||||
Dict = {
|
||||
'ticket': ticket,
|
||||
'messages': get_messages_for_ticket(ticket),
|
||||
'messages': msgs,
|
||||
'cur_receiver': cur_receiver,
|
||||
'new_msg_allow': new_msg_allow,
|
||||
'staff': request.user.is_staff,
|
||||
# 'mobile': data['mobile']
|
||||
}
|
||||
Dict.update(get_ticketsDict_for_staff(request.user))
|
||||
|
||||
tpl_name = 'blocks/profile/b_support_chat.html'
|
||||
Dict.update(get_user_timezone_Dict(request.user))
|
||||
|
||||
tpl_name = 'blocks/profile/b_support_chat.html'
|
||||
Dict.update(get_user_timezone_Dict(request.user, request=request))
|
||||
html = render_to_string(tpl_name, Dict, request=request)
|
||||
return JsonResponse({'html': html}, status=200)
|
||||
|
||||
@@ -129,6 +438,9 @@ def support_create_ticket_form_ajax(request):
|
||||
Dict = {
|
||||
'form': TicketForm()
|
||||
}
|
||||
|
||||
Dict.update(get_user_timezone_Dict(request.user))
|
||||
|
||||
tpl_name = 'blocks/profile/b_create_ticket.html'
|
||||
|
||||
html = render_to_string(tpl_name, Dict, request=request)
|
||||
@@ -150,6 +462,8 @@ def create_ticket_ajax(request):
|
||||
if not form.is_valid():
|
||||
form.initial = form.cleaned_data
|
||||
Dict = {'form': form}
|
||||
Dict.update(get_user_timezone_Dict(request.user))
|
||||
|
||||
html = render_to_string('blocks/profile/b_create_ticket.html', Dict, request=request)
|
||||
return JsonResponse({'html': html}, status=400)
|
||||
|
||||
@@ -158,11 +472,39 @@ def create_ticket_ajax(request):
|
||||
ticket.enable = True
|
||||
ticket.save()
|
||||
|
||||
from .websocket_views import send_to_support_managers_list_tickets_wo_manager
|
||||
send_to_support_managers_list_tickets_wo_manager(ticket, required_beep=True)
|
||||
# # рассылаем всем менеджерам сообщение
|
||||
#
|
||||
# Dict = {
|
||||
# 'ticket': ticket,
|
||||
# 'tickets_wo_manager': get_tickets_wo_manager()
|
||||
# }
|
||||
# tickets_wo_manager_html = render_to_string('widgets/w_tickets_wo_manager.html', Dict, request=request)
|
||||
#
|
||||
# group_name = 'support_managers'
|
||||
# Dict = {
|
||||
# 'type': 'update_chat',
|
||||
# 'tickets_wo_manager_html': tickets_wo_manager_html,
|
||||
# 'required_beep': True,
|
||||
# 'group_name': group_name,
|
||||
# }
|
||||
# channel_layer = get_channel_layer()
|
||||
# async_to_sync(channel_layer.group_send)(
|
||||
# group_name,
|
||||
# Dict
|
||||
# )
|
||||
#
|
||||
#
|
||||
# # ---------------------
|
||||
|
||||
msgs_for_ticket = get_messages_for_ticket(ticket)
|
||||
Dict = {
|
||||
'ticket': ticket,
|
||||
'messages': get_messages_for_ticket(ticket)
|
||||
'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)
|
||||
|
||||
@@ -174,12 +516,24 @@ def create_ticket_ajax(request):
|
||||
|
||||
except Exception as e:
|
||||
|
||||
msg = f'{_("ошибка в запросе")} = {str(e)}'
|
||||
|
||||
errors_Dict = {
|
||||
'errors': {
|
||||
'all__': f'ошибка в запросе = {str(e)}'
|
||||
'all__': msg
|
||||
}
|
||||
}
|
||||
Dict = {'form': errors_Dict}
|
||||
html = render_to_string('blocks/profile/b_create_ticket.html', Dict, request=request)
|
||||
return JsonResponse({'html': html}, status=400)
|
||||
|
||||
|
||||
|
||||
def sendDeployments(owner, armies):
|
||||
type = "renderDeployments"
|
||||
message = owner + " has " + str(armies) + " to deploy"
|
||||
channel_layer = get_channel_layer()
|
||||
async_to_sync(channel_layer.group_send)(
|
||||
'render_updates_group',
|
||||
{'type': 'render', 'message': message}
|
||||
)
|
||||
@@ -0,0 +1,21 @@
|
||||
# Generated by Django 4.2.2 on 2023-08-11 23:21
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('ChatServiceApp', '0003_msggroup_text'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='message',
|
||||
options={'verbose_name': 'Сообщение', 'verbose_name_plural': 'Сообщения'},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='msggroup',
|
||||
options={'verbose_name': 'Тикет', 'verbose_name_plural': 'Тикеты'},
|
||||
),
|
||||
]
|
||||
@@ -3,41 +3,53 @@ from BaseModels.base_models import BaseModel
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
msg_type_choices = (
|
||||
('support', 'техподдержка'),
|
||||
('private', 'личное')
|
||||
('support', _('техподдержка')),
|
||||
('private', _('личное'))
|
||||
)
|
||||
|
||||
msg_status_choices = (
|
||||
('sended', 'Отправлено'),
|
||||
('seen', 'Просмотрено')
|
||||
('sended', _('Отправлено')),
|
||||
('seen', _('Просмотрено'))
|
||||
)
|
||||
|
||||
grp_msg_status = (
|
||||
('open', 'Открыт'),
|
||||
('answered', 'Отвечен'),
|
||||
('closed', 'Закрыт')
|
||||
('open', _('Открыт')),
|
||||
('answered', _('Отвечен')),
|
||||
('closed', _('Закрыт'))
|
||||
)
|
||||
|
||||
|
||||
grp_msg_department = (
|
||||
('support', 'Отдел: Техническая поддержка'),
|
||||
('finance', 'Отдел: Финансовый департамент'),
|
||||
('support', _('Отдел: Техническая поддержка')),
|
||||
('finance', _('Отдел: Финансовый департамент')),
|
||||
)
|
||||
|
||||
|
||||
class MsgGroup(BaseModel):
|
||||
from AuthApp.models import User
|
||||
|
||||
department = models.CharField(verbose_name='Отдел', default='support', choices=grp_msg_department)
|
||||
status = models.CharField(verbose_name='Статус', default='open', choices=grp_msg_status)
|
||||
department = models.CharField(verbose_name=_('Отдел'), default='support', choices=grp_msg_department)
|
||||
status = models.CharField(verbose_name=_('Статус'), default='open', choices=grp_msg_status)
|
||||
|
||||
text = models.TextField(verbose_name='Сообщение')
|
||||
text = models.TextField(verbose_name=_('Сообщение'))
|
||||
|
||||
owner = models.ForeignKey(User, verbose_name=_('Владелец'), related_name='rel_msgGroups_for_owner',
|
||||
on_delete=models.SET_NULL, null=True)
|
||||
manager = models.ForeignKey(User, verbose_name=_('Менеджер'), related_name='rel_msgGroups_for_manager',
|
||||
on_delete=models.SET_NULL, null=True)
|
||||
|
||||
def get_last_msg_txt(self):
|
||||
msg = self.rel_messages_for_group.all().order_by('-createDT').first()
|
||||
if not msg:
|
||||
return self.text
|
||||
|
||||
if msg.text:
|
||||
return msg.text
|
||||
elif msg.files:
|
||||
return msg.files[0]['file_name']
|
||||
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Тикет')
|
||||
verbose_name_plural = _('Тикеты')
|
||||
@@ -46,23 +58,23 @@ class MsgGroup(BaseModel):
|
||||
class Message(BaseModel):
|
||||
from AuthApp.models import User
|
||||
|
||||
msg_type = models.CharField(max_length=50, verbose_name='Тип сообщения', default='private', choices=msg_type_choices)
|
||||
msg_type = models.CharField(max_length=50, verbose_name=_('Тип сообщения'), default='private', choices=msg_type_choices)
|
||||
group = models.ForeignKey(
|
||||
MsgGroup, verbose_name='Группа сообщений', related_name='rel_messages_for_group',
|
||||
MsgGroup, verbose_name=_('Группа сообщений'), related_name='rel_messages_for_group',
|
||||
on_delete=models.SET_NULL, null=True)
|
||||
|
||||
sender = models.ForeignKey(
|
||||
User, verbose_name='Отправитель', on_delete=models.CASCADE, related_name='rel_messages_for_sender'
|
||||
User, verbose_name=_('Отправитель'), on_delete=models.CASCADE, related_name='rel_messages_for_sender'
|
||||
)
|
||||
receiver = models.ForeignKey(
|
||||
User, verbose_name='Получатель', on_delete=models.CASCADE, related_name='rel_messages_for_receiver'
|
||||
User, verbose_name=_('Получатель'), on_delete=models.CASCADE, related_name='rel_messages_for_receiver'
|
||||
)
|
||||
|
||||
text = models.TextField(verbose_name='Сообщение')
|
||||
text = models.TextField(verbose_name=_('Сообщение'))
|
||||
|
||||
status = models.CharField(verbose_name='Статус', default='sended', choices=msg_status_choices)
|
||||
status = models.CharField(verbose_name=_('Статус'), default='sended', choices=msg_status_choices)
|
||||
|
||||
files = models.JSONField(verbose_name='Прикрепленные файлы', default=dict)
|
||||
files = models.JSONField(verbose_name=_('Прикрепленные файлы'), default=dict)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Сообщение')
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from django import template
|
||||
from django.template.defaultfilters import stringfilter
|
||||
from django.conf import settings
|
||||
|
||||
register = template.Library()
|
||||
|
||||
@@ -10,9 +11,40 @@ register = template.Library()
|
||||
# from django.utils.html import mark_safe
|
||||
|
||||
# @register.filter('get_msg_side')
|
||||
|
||||
@register.simple_tag
|
||||
def get_ws_address():
|
||||
return settings.WS_ADDRESS
|
||||
|
||||
@register.simple_tag
|
||||
def get_filesize(size):
|
||||
if size:
|
||||
unit = 'B'
|
||||
if size / 1024 > 1:
|
||||
unit = 'KB'
|
||||
size = size / 1024
|
||||
if size / 1024 > 1:
|
||||
unit = 'MB'
|
||||
size = size / 1024
|
||||
if size / 1024 > 1:
|
||||
unit = 'GB'
|
||||
size = size / 1024
|
||||
if size / 1024 > 1:
|
||||
unit = 'TB'
|
||||
size = size / 1024
|
||||
size = round(size, 2)
|
||||
return f'{str(size)}{unit}'
|
||||
else:
|
||||
return ''
|
||||
|
||||
|
||||
@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:
|
||||
|
||||
11
ChatServiceApp/urls.py
Normal file
11
ChatServiceApp/urls.py
Normal file
@@ -0,0 +1,11 @@
|
||||
# coding=utf-8
|
||||
from django.urls import path
|
||||
# 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
|
||||
|
||||
urlpatterns = [
|
||||
path('get_file/<str:msg_id>/<str:file_name>', get_file_from_message, name='get_file_from_message'),
|
||||
]
|
||||
@@ -1,3 +1,26 @@
|
||||
from django.shortcuts import render
|
||||
import json
|
||||
|
||||
# Create your views here.
|
||||
from django.http import HttpResponse, Http404, FileResponse
|
||||
from django.template import loader, RequestContext
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from .models import *
|
||||
from django.conf import settings
|
||||
|
||||
def get_file_from_message(request, msg_id, file_name):
|
||||
from django.http import FileResponse
|
||||
|
||||
try:
|
||||
|
||||
msg = Message.objects.get(id=msg_id)
|
||||
|
||||
if request.user not in (msg.sender, msg.receiver):
|
||||
raise Http404
|
||||
|
||||
for file in msg.files:
|
||||
if file['file_name'] == file_name:
|
||||
f = open(f'chat_file_storage/{msg.id}/{file["file_name"]}', 'rb')
|
||||
|
||||
return FileResponse(f)
|
||||
|
||||
except Exception as e:
|
||||
raise Http404
|
||||
|
||||
8
ChatServiceApp/websocket_urls.py
Normal file
8
ChatServiceApp/websocket_urls.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from django.urls import re_path
|
||||
|
||||
from .websocket_views import *
|
||||
|
||||
websocket_urlpatterns = [
|
||||
re_path(r'ws/socket-server/', ChatConsumer.as_asgi()),
|
||||
# re_path(r'ws/chat/(?P<room_name>\w+)/$', consumers.ChatConsumer),
|
||||
]
|
||||
260
ChatServiceApp/websocket_views.py
Normal file
260
ChatServiceApp/websocket_views.py
Normal file
@@ -0,0 +1,260 @@
|
||||
import json
|
||||
from channels.generic.websocket import WebsocketConsumer, AsyncWebsocketConsumer, JsonWebsocketConsumer
|
||||
from asgiref.sync import async_to_sync, sync_to_async
|
||||
# from channels.auth import channel_session_user, channel_session_user_from_http
|
||||
from channels.layers import get_channel_layer
|
||||
from django.template.loader import render_to_string
|
||||
|
||||
|
||||
def send_to_support_managers_list_tickets_wo_manager(ticket, required_beep=False):
|
||||
from.funcs import get_tickets_wo_manager
|
||||
|
||||
# рассылаем всем менеджерам сообщение
|
||||
|
||||
Dict = {
|
||||
'ticket': ticket,
|
||||
'tickets_wo_manager': get_tickets_wo_manager()
|
||||
}
|
||||
tickets_wo_manager_html = render_to_string('widgets/w_tickets_wo_manager.html', Dict)
|
||||
|
||||
group_name = 'support_managers'
|
||||
Dict = {
|
||||
'type': 'update_chat',
|
||||
'tickets_wo_manager_html': tickets_wo_manager_html,
|
||||
'required_beep': required_beep,
|
||||
'group_name': group_name,
|
||||
}
|
||||
if ticket.manager:
|
||||
Dict.update({'ticket_manager': ticket.manager.id})
|
||||
|
||||
channel_layer = get_channel_layer()
|
||||
async_to_sync(channel_layer.group_send)(
|
||||
group_name,
|
||||
Dict
|
||||
)
|
||||
|
||||
# ---------------------
|
||||
return True
|
||||
|
||||
|
||||
def get_tickets_wo_manager_html(ticket, user, data):
|
||||
from .funcs import get_tickets_wo_manager
|
||||
|
||||
# если не менеджер - возвращаем None
|
||||
if not ticket or ticket.manager.id != user.id:
|
||||
return None
|
||||
|
||||
Dict = {
|
||||
'ticket': ticket,
|
||||
'tickets_wo_manager': get_tickets_wo_manager()
|
||||
}
|
||||
tickets_wo_manager_html = render_to_string('widgets/w_tickets_wo_manager.html', Dict)
|
||||
|
||||
return tickets_wo_manager_html
|
||||
|
||||
|
||||
def get_tickets_w_manager_html(ticket, user, data):
|
||||
from .funcs import get_tickets_for_manager
|
||||
|
||||
# если не менеджер - возвращаем None
|
||||
if not ticket or ticket.manager.id != user.id:
|
||||
return None
|
||||
|
||||
Dict = {
|
||||
'ticket': ticket,
|
||||
'tickets_for_manager': get_tickets_for_manager(user)
|
||||
}
|
||||
tickets_w_manager_html = render_to_string('widgets/w_tickets_w_manager.html', Dict)
|
||||
|
||||
return tickets_w_manager_html
|
||||
|
||||
|
||||
class ChatConsumer(WebsocketConsumer):
|
||||
|
||||
# def __init__(self, *args, **kwargs):
|
||||
# super().__init__(args, kwargs)
|
||||
# self.room_name = None
|
||||
|
||||
def disconnect(self, close_code):
|
||||
print("Closed websocket with code: ", close_code)
|
||||
|
||||
for gr in self.groups:
|
||||
async_to_sync(self.channel_layer.group_discard)(
|
||||
gr,
|
||||
self.channel_name
|
||||
)
|
||||
self.close()
|
||||
|
||||
def connect(self):
|
||||
print('ws connect')
|
||||
|
||||
user_group = f'user_{self.scope["user"].id}'
|
||||
|
||||
add_to_group = False
|
||||
if not self.groups or not user_group in self.groups or not self.channel_name in self.groups[user_group]:
|
||||
add_to_group = True
|
||||
|
||||
if add_to_group:
|
||||
if not self.groups:
|
||||
self.groups = {user_group: [self.channel_name]}
|
||||
elif not user_group in self.groups:
|
||||
self.groups[user_group].append(self.channel_name)
|
||||
else:
|
||||
self.groups.update({user_group: [self.channel_name]})
|
||||
|
||||
async_to_sync(self.channel_layer.group_add)(
|
||||
user_group,
|
||||
self.channel_name
|
||||
)
|
||||
|
||||
print(f'created group user_{self.scope["user"].id}')
|
||||
|
||||
if self.scope['user'].is_staff:
|
||||
async_to_sync(self.channel_layer.group_add)(
|
||||
f'support_managers',
|
||||
self.channel_name
|
||||
)
|
||||
print(f'add user {self.scope["user"].id} to group support_managers')
|
||||
|
||||
self.accept()
|
||||
|
||||
|
||||
|
||||
|
||||
def receive(self, text_data=None, bytes_data=None):
|
||||
if len(text_data) < 500:
|
||||
print(f'ws receive text_data = {text_data}')
|
||||
else:
|
||||
print(f'ws receive text_data size = {len(text_data)}')
|
||||
|
||||
import base64
|
||||
|
||||
from AuthApp.models import User
|
||||
from .models import Message, MsgGroup
|
||||
|
||||
|
||||
data = json.loads(text_data)
|
||||
|
||||
# if 'file' in data:
|
||||
# file_Dict = json.loads(data['file'])
|
||||
#
|
||||
# f = open(f'chat_file_storage/{file_Dict["file_name"]}', 'wb+')
|
||||
# head, content = file_Dict['file'].split(',')
|
||||
# content = base64.b64decode(content)
|
||||
# f.write(content)
|
||||
# f.close()
|
||||
|
||||
sender = data['sender']
|
||||
receiver = data['receiver']
|
||||
sender_obj = User.objects.get(id=sender)
|
||||
receiver_obj = User.objects.get(id=receiver)
|
||||
|
||||
|
||||
|
||||
from .funcs import send_msg, get_update_chat_Dict
|
||||
data.update({
|
||||
'cur_user': sender,
|
||||
'required_beep': False,
|
||||
})
|
||||
res = send_msg(data)
|
||||
if not res['msg'] or type(res['msg']) == str:
|
||||
data.update({'bad_manager': True})
|
||||
|
||||
ticket = None
|
||||
|
||||
if 'ticket_id' in data and data['ticket_id']:
|
||||
ticket = MsgGroup.objects.get(id=data['ticket_id'])
|
||||
# receiver_obj = User.objects.get(id=receiver)
|
||||
msgs = Message.objects.filter(
|
||||
receiver__id=sender, group__id=data['ticket_id']
|
||||
)
|
||||
msgs.update(status='seen')
|
||||
|
||||
if 'required_update_tickets_list_wo_managers' in res and res['required_update_tickets_list_wo_managers']:
|
||||
send_to_support_managers_list_tickets_wo_manager(ticket, required_beep=False)
|
||||
|
||||
Dict = get_update_chat_Dict(data)
|
||||
|
||||
|
||||
|
||||
group_name = f'user_{sender}'
|
||||
resDict = {
|
||||
'type': 'update_chat',
|
||||
'sender': sender,
|
||||
'receiver': receiver,
|
||||
'group_name': group_name,
|
||||
|
||||
}
|
||||
|
||||
if ticket:
|
||||
tickets_wo_manager_html = get_tickets_wo_manager_html(ticket, sender_obj, data)
|
||||
if tickets_wo_manager_html:
|
||||
resDict.update({'tickets_wo_manager_html': tickets_wo_manager_html})
|
||||
|
||||
tickets_w_manager_html = get_tickets_w_manager_html(ticket, sender_obj, data)
|
||||
if tickets_w_manager_html:
|
||||
resDict.update({'tickets_w_manager_html': tickets_w_manager_html})
|
||||
|
||||
|
||||
resDict.update(Dict)
|
||||
async_to_sync(self.channel_layer.group_send)(
|
||||
group_name,
|
||||
resDict
|
||||
)
|
||||
|
||||
group_name = f'user_{receiver}'
|
||||
# if group_name in self.channel_layer.groups.keys():
|
||||
data.update({
|
||||
'cur_user': receiver,
|
||||
'required_beep': True,
|
||||
})
|
||||
Dict = get_update_chat_Dict(data)
|
||||
|
||||
if 'support_chat_html' in Dict:
|
||||
msg_type = 'update_support_chat'
|
||||
else:
|
||||
msg_type = 'update_chat'
|
||||
|
||||
resDict = {
|
||||
'type': msg_type,
|
||||
'sender': receiver,
|
||||
'receiver': sender,
|
||||
'group_name': group_name,
|
||||
}
|
||||
|
||||
if ticket:
|
||||
tickets_wo_manager_html = get_tickets_wo_manager_html(ticket, receiver_obj, data)
|
||||
if tickets_wo_manager_html:
|
||||
resDict.update({'tickets_wo_manager_html': tickets_wo_manager_html})
|
||||
|
||||
tickets_w_manager_html = get_tickets_w_manager_html(ticket, receiver_obj, data)
|
||||
if tickets_w_manager_html:
|
||||
resDict.update({'tickets_w_manager_html': tickets_w_manager_html})
|
||||
|
||||
resDict.update(Dict)
|
||||
async_to_sync(self.channel_layer.group_send)(
|
||||
group_name,
|
||||
resDict
|
||||
)
|
||||
|
||||
|
||||
|
||||
def echo(self, data):
|
||||
print('ws echo')
|
||||
|
||||
self.send(text_data=json.dumps(data))
|
||||
|
||||
def update_support_chat(self, data):
|
||||
print(f'ws update_support_chat {data["group_name"]}')
|
||||
|
||||
self.send(text_data=json.dumps(data))
|
||||
|
||||
def update_chat(self, data):
|
||||
print(f'ws update_chat {data["group_name"]}')
|
||||
|
||||
self.send(text_data=json.dumps(data))
|
||||
|
||||
def ws_send_msg(self, data):
|
||||
print('ws ws_send_msg')
|
||||
|
||||
self.send(text_data=json.dumps(data))
|
||||
@@ -1,25 +1,47 @@
|
||||
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):
|
||||
|
||||
def get_fieldsets(self, request, obj=None):
|
||||
fieldsets = super(type(self), self).get_fieldsets(request, obj)
|
||||
if not request.user.is_superuser and obj.url and obj.url in ('main', 'spec_technics', 'works'):
|
||||
fieldsets[0][1]['fields'].pop(2)
|
||||
# fieldsets.insert(
|
||||
# 1, ('Промо-хэдер', {
|
||||
# 'classes': ['wide'],
|
||||
# 'fields': (
|
||||
# 'promo_header',
|
||||
# 'title', 'description', 'text',
|
||||
# 'picture',
|
||||
# )
|
||||
#
|
||||
# })
|
||||
# )
|
||||
return fieldsets
|
||||
fieldsets = [
|
||||
(None, {
|
||||
'classes': ['wide'],
|
||||
'fields': ('name',
|
||||
'url',
|
||||
'title', 'description', 'text',
|
||||
'picture',
|
||||
'order',
|
||||
)
|
||||
}),
|
||||
(_('Настройки'), {
|
||||
'classes': ['wide', 'collapse'],
|
||||
'fields': (
|
||||
'FAQ_title',
|
||||
)
|
||||
}),
|
||||
('SEO', {
|
||||
'classes': ['wide', 'collapse'],
|
||||
'fields': (
|
||||
'seo_title', 'seo_description', 'seo_keywords', 'seo_text',
|
||||
)
|
||||
}),
|
||||
]
|
||||
|
||||
|
||||
list_display = [
|
||||
'id',
|
||||
'name', 'url', 'title',
|
||||
'order', 'modifiedDT', 'createDT'
|
||||
]
|
||||
|
||||
list_display_links = ['id']
|
||||
list_editable = ['order']
|
||||
|
||||
list_filter = ['modifiedDT', 'createDT']
|
||||
search_fields = ['name', 'title']
|
||||
# filter_horizontal = ['options']
|
||||
|
||||
def has_delete_permission(self, request, obj=None):
|
||||
if request.user.is_superuser:
|
||||
@@ -30,46 +52,61 @@ class Admin_StaticPage(Admin_Trans_BaseModelViewPage):
|
||||
|
||||
admin.site.register(StaticPage,Admin_StaticPage)
|
||||
|
||||
class Admin_Block(Admin_BaseBlock):
|
||||
# class Admin_Block(Admin_Trans_BaseModel):
|
||||
# pass
|
||||
#
|
||||
# # def get_fieldsets(self, request, obj=None):
|
||||
# # fieldsets = super(type(self), self).get_fieldsets(request, obj)
|
||||
# # if not request.user.is_superuser and obj.name and obj.name in ('About US', 'machines', 'works'):
|
||||
# # fieldsets[0][1]['fields'].pop(0)
|
||||
# # fieldsets.insert(
|
||||
# # 1, (_('Контент'), {
|
||||
# # 'classes': ['wide'],
|
||||
# # 'fields': (
|
||||
# # 'title', 'description', 'text',
|
||||
# # 'picture',
|
||||
# # )
|
||||
# #
|
||||
# # })
|
||||
# # )
|
||||
# # return fieldsets
|
||||
# #
|
||||
# # def has_delete_permission(self, request, obj=None):
|
||||
# # if request.user.is_superuser:
|
||||
# # return True
|
||||
# #
|
||||
# # if obj.name in ('About US', 'machines', 'works'):
|
||||
# # return False
|
||||
#
|
||||
# admin.site.register(Block,Admin_Block)
|
||||
|
||||
def get_fieldsets(self, request, obj=None):
|
||||
fieldsets = super(type(self), self).get_fieldsets(request, obj)
|
||||
if not request.user.is_superuser and obj.name and obj.name in ('About US', 'machines', 'works'):
|
||||
fieldsets[0][1]['fields'].pop(0)
|
||||
fieldsets.insert(
|
||||
1, ('Контент', {
|
||||
'classes': ['wide'],
|
||||
'fields': (
|
||||
'title', 'description', 'text',
|
||||
'picture',
|
||||
)
|
||||
class Admin_Option(Admin_Trans_BaseModel):
|
||||
|
||||
})
|
||||
)
|
||||
return fieldsets
|
||||
# def get_fieldsets(self, request, obj=None):
|
||||
# fieldsets = super(type(self), self).get_fieldsets(request, obj)
|
||||
# fieldsets.insert(
|
||||
# 1, ('Контент', {
|
||||
# 'classes': ['wide'],
|
||||
# 'fields': (
|
||||
# 'opt_type', 'prefix', 'value', 'picture'
|
||||
# )
|
||||
#
|
||||
# })
|
||||
# )
|
||||
# return fieldsets
|
||||
|
||||
def has_delete_permission(self, request, obj=None):
|
||||
if request.user.is_superuser:
|
||||
return True
|
||||
|
||||
if obj.name in ('About US', 'machines', 'works'):
|
||||
return False
|
||||
fieldsets = [
|
||||
(_('Контент'), {
|
||||
'classes': ['wide'],
|
||||
'fields': (
|
||||
'name', 'opt_type', 'prefix', 'value', 'picture'
|
||||
)
|
||||
}),
|
||||
]
|
||||
|
||||
admin.site.register(Block,Admin_Block)
|
||||
|
||||
class Admin_Option(Admin_BaseModel):
|
||||
|
||||
def get_fieldsets(self, request, obj=None):
|
||||
fieldsets = super(type(self), self).get_fieldsets(request, obj)
|
||||
fieldsets.insert(
|
||||
1, ('Контент', {
|
||||
'classes': ['wide'],
|
||||
'fields': (
|
||||
'opt_type', 'prefix', 'value', 'picture'
|
||||
)
|
||||
|
||||
})
|
||||
)
|
||||
return fieldsets
|
||||
list_display = ['image_thumb', 'opt_type', 'name', 'value', 'prefix']
|
||||
list_editable = ['value', 'prefix']
|
||||
list_filter = ['opt_type']
|
||||
|
||||
admin.site.register(Option,Admin_Option)
|
||||
|
||||
51
GeneralApp/allauth_funcs.py
Normal file
51
GeneralApp/allauth_funcs.py
Normal file
@@ -0,0 +1,51 @@
|
||||
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
|
||||
from allauth.account.utils import user_field
|
||||
from django.conf import settings
|
||||
from allauth.account.adapter import DefaultAccountAdapter
|
||||
import requests
|
||||
from django.core.files import File
|
||||
from django.core.files.temp import NamedTemporaryFile
|
||||
|
||||
class MyAccountAdapter(DefaultAccountAdapter):
|
||||
|
||||
def get_login_redirect_url(self, request):
|
||||
path = super(MyAccountAdapter, self).get_login_redirect_url(request)
|
||||
|
||||
try:
|
||||
user = request.user
|
||||
user_profile = user.user_profile
|
||||
if user_profile and not user_profile.avatar:
|
||||
social_accounts = user.socialaccount_set.all()
|
||||
if social_accounts:
|
||||
for social_account in social_accounts:
|
||||
if 'picture' in social_account.extra_data and social_account.extra_data['picture']:
|
||||
r = requests.get(social_account.extra_data['picture'])
|
||||
|
||||
img_temp = NamedTemporaryFile()
|
||||
img_temp.write(r.content)
|
||||
img_temp.flush()
|
||||
user_profile.avatar.save(f'avatar_{user.id}.jpeg', File(img_temp), True)
|
||||
break
|
||||
|
||||
except Exception as e:
|
||||
msg = f'post_save create_user_profile Error = {str(e)}'
|
||||
print(msg)
|
||||
|
||||
return path
|
||||
|
||||
# class CustomSocialAccountAdapter(DefaultSocialAccountAdapter):
|
||||
# def populate_user(self, request, sociallogin, data):
|
||||
# from AuthApp.models import UserProfile
|
||||
#
|
||||
# user = super().populate_user(request, sociallogin, data)
|
||||
# try:
|
||||
# picture = sociallogin.account.extra_data['picture']
|
||||
# user_profile = UserProfile.objects.get_or_create(user=user)
|
||||
# with open(picture, 'rb') as fd:
|
||||
# user_profile.avatar.save(f'user_{user.id}_avatar.jpeg', fd.read(), True)
|
||||
# # user_field(user, "profile_photo", picture)
|
||||
# except Exception as e:
|
||||
# msg = f'CustomSocialAccountAdapter populate_user Error = {str(e)}'
|
||||
# print(msg)
|
||||
#
|
||||
# return user
|
||||
45
GeneralApp/funcs.py
Normal file
45
GeneralApp/funcs.py
Normal file
@@ -0,0 +1,45 @@
|
||||
from django.http import HttpResponse, Http404, FileResponse
|
||||
from django.conf import settings
|
||||
|
||||
def get_inter_Dict(user):
|
||||
|
||||
from SubscribesApp.funcs import get_cur_user_subscribe
|
||||
user_subscribe = get_cur_user_subscribe(user)
|
||||
|
||||
|
||||
Dict = {
|
||||
'user_subscribe': user_subscribe,
|
||||
'prod': True
|
||||
}
|
||||
|
||||
if settings.WS_ADDRESS == 'localhost:8000':
|
||||
Dict.update({'prod': False})
|
||||
|
||||
|
||||
from PushMessages.views import get_key_Dict
|
||||
Dict.update(get_key_Dict())
|
||||
|
||||
return Dict
|
||||
|
||||
def get_inter_http_respose(template_obj, context_Dict, request):
|
||||
|
||||
context_Dict.update(get_inter_Dict(request.user))
|
||||
|
||||
from PushMessages.views import send_push
|
||||
if request and 'page' in context_Dict:
|
||||
text = None
|
||||
title = None
|
||||
|
||||
if context_Dict['page'] == dict:
|
||||
if 'title' in context_Dict['page']:
|
||||
title = context_Dict['page']['title']
|
||||
if 'description' in context_Dict['page']:
|
||||
text = context_Dict['page']['description']
|
||||
else:
|
||||
title = getattr(context_Dict['page'], 'title', None)
|
||||
text = getattr(context_Dict['page'], 'description', None)
|
||||
|
||||
# if text and title and not request.user.is_anonymous:
|
||||
# send_push(user=request.user, title=title, text=text)
|
||||
|
||||
return HttpResponse(template_obj.render(context_Dict, request))
|
||||
44
GeneralApp/funcs_options.py
Normal file
44
GeneralApp/funcs_options.py
Normal file
@@ -0,0 +1,44 @@
|
||||
from .models import *
|
||||
|
||||
def get_options_by_opt_types(opt_types, only_vals=False):
|
||||
if type(opt_types) == str:
|
||||
kwargs = {'opt_type': opt_types}
|
||||
elif type(opt_types) == dict:
|
||||
kwargs = opt_types
|
||||
else:
|
||||
kwargs = {'opt_type__in': opt_types}
|
||||
|
||||
opts = Option.objects.filter(**kwargs)
|
||||
if opts and only_vals:
|
||||
res = {}
|
||||
opts = opts.values('opt_type', 'value', 'prefix')
|
||||
for item in opts:
|
||||
if item['opt_type'] == 'domain':
|
||||
|
||||
try:
|
||||
from django.contrib.sites.models import Site
|
||||
current_site = Site.objects.get_current()
|
||||
res.update({item['opt_type']: current_site.domain})
|
||||
continue
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
|
||||
if item['prefix']:
|
||||
res.update({item['opt_type']: f"{item['prefix']}{item['value']}"})
|
||||
else:
|
||||
res.update({item['opt_type']: f"{item['value']}"})
|
||||
return res
|
||||
|
||||
return opts
|
||||
|
||||
def get_first_option_value_by_opt_type(opt_type):
|
||||
opts = get_options_by_opt_types(opt_type)
|
||||
if opts:
|
||||
return opts[0].value
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_mail_send_options():
|
||||
opt_types = ['mail_server_url', 'mail_server_smtp_port', 'sender_mail_login', 'sender_mail_password', 'sender_email', 'project_name']
|
||||
|
||||
return get_options_by_opt_types(opt_types, only_vals=True)
|
||||
66
GeneralApp/init_options.py
Normal file
66
GeneralApp/init_options.py
Normal file
@@ -0,0 +1,66 @@
|
||||
from .models import *
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
|
||||
required_options_Dict = {
|
||||
'mail_server_url': {
|
||||
'name_ru': 'Адрес почтового сервера',
|
||||
'opt_type': 'mail_server_url',
|
||||
'value': '213.142.147.40',
|
||||
},
|
||||
'mail_server_smtp_port': {
|
||||
'name_ru': 'SMTP порт почтового сервера',
|
||||
'opt_type': 'mail_server_smtp_port',
|
||||
'value': 587,
|
||||
},
|
||||
'sender_mail_login': {
|
||||
'name_ru': 'email для отправки писем с сайта',
|
||||
'opt_type': 'sender_mail_login',
|
||||
'value': 'admin@tripwb.com',
|
||||
},
|
||||
'sender_email': {
|
||||
'name_ru': 'email для отправки',
|
||||
'opt_type': 'sender_email',
|
||||
'value': 'admin@tripwb.com',
|
||||
},
|
||||
'sender_mail_password': {
|
||||
'name_ru': 'пароль для отправки писем с сайта',
|
||||
'opt_type': 'sender_mail_password',
|
||||
'value': 't5Fdcah^gdajY',
|
||||
},
|
||||
'project_name': {
|
||||
'name_ru': 'Название проекта',
|
||||
'opt_type': 'project_name',
|
||||
'value': 'TWB',
|
||||
},
|
||||
'domain': {
|
||||
'name_ru': 'Адрес сайта',
|
||||
'opt_type': 'domain',
|
||||
'value': 'tripwb.com',
|
||||
},
|
||||
'support_email': {
|
||||
'name_ru': 'email техподдержки',
|
||||
'opt_type': 'support_email',
|
||||
'value': 'admin@tripwb.com',
|
||||
},
|
||||
'corp_email': {
|
||||
'name_ru': 'корпоративный email',
|
||||
'opt_type': 'corp_email',
|
||||
'value': 'admin@tripwb.com',
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
def init_options():
|
||||
options = Option.objects.all()
|
||||
option_types_list = options.values_list('opt_type', flat=True)
|
||||
|
||||
opts_for_create = []
|
||||
for opt_type, data_Dict in required_options_Dict.items():
|
||||
if not opt_type in option_types_list:
|
||||
opt = Option(**data_Dict)
|
||||
opts_for_create.append(opt)
|
||||
|
||||
Option.objects.bulk_create(opts_for_create)
|
||||
|
||||
return True
|
||||
@@ -0,0 +1,44 @@
|
||||
# Generated by Django 4.2.2 on 2023-08-31 13:21
|
||||
|
||||
import ckeditor.fields
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('GeneralApp', '0002_block_faq_title_en_block_faq_title_ru_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='staticpage',
|
||||
name='seo_description_en',
|
||||
field=models.CharField(blank=True, max_length=250, null=True, verbose_name='Description (150 знаков)'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='staticpage',
|
||||
name='seo_description_ru',
|
||||
field=models.CharField(blank=True, max_length=250, null=True, verbose_name='Description (150 знаков)'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='staticpage',
|
||||
name='seo_text_en',
|
||||
field=ckeditor.fields.RichTextField(blank=True, null=True, verbose_name='Текст SEO статьи'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='staticpage',
|
||||
name='seo_text_ru',
|
||||
field=ckeditor.fields.RichTextField(blank=True, null=True, verbose_name='Текст SEO статьи'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='staticpage',
|
||||
name='seo_title_en',
|
||||
field=models.CharField(blank=True, max_length=250, null=True, verbose_name='Title (80 знаков)'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='staticpage',
|
||||
name='seo_title_ru',
|
||||
field=models.CharField(blank=True, max_length=250, null=True, verbose_name='Title (80 знаков)'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,109 @@
|
||||
# Generated by Django 4.2.2 on 2023-09-22 13:29
|
||||
|
||||
import ckeditor_uploader.fields
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('GeneralApp', '0003_staticpage_seo_description_en_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='block',
|
||||
name='description',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, help_text='краткое описание страницы (до 240 символов)', null=True, verbose_name='Краткое описание'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='block',
|
||||
name='description_en',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, help_text='краткое описание страницы (до 240 символов)', null=True, verbose_name='Краткое описание'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='block',
|
||||
name='description_ru',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, help_text='краткое описание страницы (до 240 символов)', null=True, verbose_name='Краткое описание'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='block',
|
||||
name='seo_text',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, null=True, verbose_name='Текст SEO статьи'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='block',
|
||||
name='text',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, null=True, verbose_name='Полное описание'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='block',
|
||||
name='text_en',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, null=True, verbose_name='Полное описание'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='block',
|
||||
name='text_ru',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, null=True, verbose_name='Полное описание'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='faqitem',
|
||||
name='answer',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(verbose_name='Ответ'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='faqitem',
|
||||
name='answer_en',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(null=True, verbose_name='Ответ'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='faqitem',
|
||||
name='answer_ru',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(null=True, verbose_name='Ответ'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='staticpage',
|
||||
name='description',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, help_text='краткое описание страницы (до 240 символов)', null=True, verbose_name='Краткое описание'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='staticpage',
|
||||
name='description_en',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, help_text='краткое описание страницы (до 240 символов)', null=True, verbose_name='Краткое описание'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='staticpage',
|
||||
name='description_ru',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, help_text='краткое описание страницы (до 240 символов)', null=True, verbose_name='Краткое описание'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='staticpage',
|
||||
name='seo_text',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, null=True, verbose_name='Текст SEO статьи'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='staticpage',
|
||||
name='seo_text_en',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, null=True, verbose_name='Текст SEO статьи'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='staticpage',
|
||||
name='seo_text_ru',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, null=True, verbose_name='Текст SEO статьи'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='staticpage',
|
||||
name='text',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, null=True, verbose_name='Полное описание'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='staticpage',
|
||||
name='text_en',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, null=True, verbose_name='Полное описание'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='staticpage',
|
||||
name='text_ru',
|
||||
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, null=True, verbose_name='Полное описание'),
|
||||
),
|
||||
]
|
||||
@@ -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='Значение'),
|
||||
),
|
||||
]
|
||||
@@ -1,10 +1,11 @@
|
||||
from django.db import models
|
||||
from BaseModels.base_models import BaseModelViewPage, BaseModel
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from ckeditor.fields import RichTextField
|
||||
# from ckeditor.fields import RichTextField
|
||||
from ckeditor_uploader.fields import RichTextUploadingField
|
||||
|
||||
class StaticPage(BaseModelViewPage):
|
||||
promo_header = models.BooleanField(verbose_name='Промо-хэдер', default=False)
|
||||
promo_header = models.BooleanField(verbose_name=_('Промо-хэдер'), default=False)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Статическая страница')
|
||||
@@ -16,9 +17,9 @@ class Block(BaseModelViewPage):
|
||||
verbose_name_plural = _('Блоки на страницах')
|
||||
|
||||
class Option(BaseModel):
|
||||
opt_type = models.CharField(max_length=250, verbose_name='Тип', blank=True, null=True)
|
||||
prefix = models.CharField(max_length=250, verbose_name='Префикс', blank=True, null=True)
|
||||
value = models.CharField(max_length=250, verbose_name='Значение')
|
||||
opt_type = models.CharField(max_length=250, verbose_name=_('Тип'), blank=True, null=True)
|
||||
prefix = models.CharField(max_length=250, verbose_name=_('Префикс'), blank=True, null=True)
|
||||
value = models.CharField(max_length=250, verbose_name=_('Значение'))
|
||||
picture = models.ImageField(upload_to='uploads/', verbose_name=_('Миниатюра'), null=True, blank=True,
|
||||
help_text=u'')
|
||||
|
||||
@@ -35,8 +36,8 @@ class FAQitem(BaseModel):
|
||||
object_id = models.PositiveIntegerField()
|
||||
content_object = GenericForeignKey('content_type', 'object_id')
|
||||
|
||||
question = models.TextField(verbose_name='Вопрос')
|
||||
answer = RichTextField(verbose_name='Ответ')
|
||||
question = models.TextField(verbose_name=_('Вопрос'))
|
||||
answer = RichTextUploadingField(verbose_name=_('Ответ'))
|
||||
|
||||
def __str__(self):
|
||||
if self.question:
|
||||
|
||||
1
GeneralApp/templatetags/__init__.py
Normal file
1
GeneralApp/templatetags/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
__author__ = 'SDE'
|
||||
160
GeneralApp/templatetags/base_tags_extra.py
Normal file
160
GeneralApp/templatetags/base_tags_extra.py
Normal file
@@ -0,0 +1,160 @@
|
||||
__author__ = 'SDE'
|
||||
|
||||
from django import template
|
||||
from django.template.defaultfilters import stringfilter
|
||||
|
||||
register = template.Library()
|
||||
|
||||
from django.core.serializers import serialize
|
||||
from django.db.models.query import QuerySet
|
||||
# import simplejson
|
||||
from django.template import Library
|
||||
from django.utils.html import mark_safe
|
||||
|
||||
@register.filter('get_value_from_dict')
|
||||
def get_value_from_dict(dict_data, key):
|
||||
"""
|
||||
usage example {{ your_dict|get_value_from_dict:your_key }}
|
||||
"""
|
||||
|
||||
if key in dict_data:
|
||||
res = dict_data[key]
|
||||
return res
|
||||
|
||||
return False
|
||||
|
||||
|
||||
|
||||
@register.filter()
|
||||
def get_rows_count_by_cols_count(data, cols_count):
|
||||
rows_count = len(data) // cols_count
|
||||
if len(data) % cols_count:
|
||||
rows_count += 1
|
||||
return rows_count
|
||||
|
||||
@register.filter()
|
||||
def get_numbers_list(from_el, to_el):
|
||||
res = range(from_el, to_el+1)
|
||||
return res
|
||||
|
||||
|
||||
def val_type(value):
|
||||
res = type(value)
|
||||
return res.__name__
|
||||
register.filter('val_type', val_type)
|
||||
|
||||
@register.filter()
|
||||
def get_cols_table_data_for_row_when_cols3(value, row):
|
||||
el_count = 3
|
||||
from_el = (row-1) * el_count
|
||||
to_el = row * el_count
|
||||
part = list(value)[from_el:to_el]
|
||||
return part
|
||||
# register.filter('val_type', val_type)
|
||||
|
||||
|
||||
@register.filter
|
||||
@stringfilter
|
||||
def correct_for_tables(value):
|
||||
if value in ['None', '0.0']:
|
||||
return '-'
|
||||
return value
|
||||
|
||||
|
||||
@register.filter
|
||||
@stringfilter
|
||||
def del_bad_symbols(value):
|
||||
from BaseModels.functions import del_bad_symbols
|
||||
return del_bad_symbols(value)
|
||||
|
||||
|
||||
@register.filter
|
||||
@stringfilter
|
||||
def del_amp_symbols(value):
|
||||
from BaseModels.functions import del_nbsp
|
||||
return del_nbsp(value)
|
||||
|
||||
@register.filter
|
||||
@stringfilter
|
||||
def del_lang_from_path(value):
|
||||
path_list = value.split('/')
|
||||
path = '/' + '/'.join(path_list[2:])
|
||||
|
||||
# for i in path_list[1:]:
|
||||
# path.join(i + '/')
|
||||
return path
|
||||
|
||||
@register.filter
|
||||
@stringfilter
|
||||
def get_color_by_number(value, arg=None):
|
||||
|
||||
color = None
|
||||
try:
|
||||
val = float(value)
|
||||
|
||||
if not color and arg == u'%':
|
||||
|
||||
color = u'black'
|
||||
if val > 50:
|
||||
color = u'green'
|
||||
elif val <= 50 and val >= 25:
|
||||
color = u'#6c8107'
|
||||
elif val <= 25 and val >= 10:
|
||||
color = u'#a89803'
|
||||
elif val <= 10 and val >= 5:
|
||||
color = u'#e6a707'
|
||||
elif val <= 5 and val >= 0:
|
||||
color = u'#e67307'
|
||||
elif val <= 0:
|
||||
color = u'red'
|
||||
|
||||
|
||||
# val_range = val_max - val_min
|
||||
# # val_percent = (val_range * 100 / val) - 100
|
||||
# offset = -(val_min + -(val))
|
||||
# if val <0:
|
||||
# val = offset
|
||||
# if val > val_max:
|
||||
# val = val_max
|
||||
# elif val < 0:
|
||||
# val = 0
|
||||
#
|
||||
# color_range = 16711680 - 1211136
|
||||
# val_1unit = float(color_range) / float(val_range)
|
||||
# dec_color = 16711680 - int(val_1unit * val)
|
||||
|
||||
if not color:
|
||||
color = u'black'
|
||||
if val > 1000:
|
||||
color = u'green'
|
||||
elif val <= 1000 and val >= 500:
|
||||
color = u'#6c8107'
|
||||
elif val <= 500 and val >= 250:
|
||||
color = u'#a89803'
|
||||
elif val <= 250 and val >= 125:
|
||||
color = u'#e6a707'
|
||||
elif val <= 125 and val >= 50:
|
||||
color = u'#e67307'
|
||||
elif val <= 50:
|
||||
color = u'red'
|
||||
|
||||
# s = u'style="color: #{0}12;"'.format(str(hex(dec_color))[2:6])
|
||||
s = u'style="color: {0};"'.format(color)
|
||||
return s
|
||||
except:
|
||||
return u''
|
||||
|
||||
|
||||
# @register.filter
|
||||
# @stringfilter
|
||||
# def check_aprox_compare_strings(search_phrase, txt):
|
||||
# from ProductApp.search import get_highlight_string
|
||||
#
|
||||
# s = get_highlight_string(search_phrase, txt)
|
||||
#
|
||||
# return s
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ from .models import *
|
||||
|
||||
class StaticPage_TranslationOptions(TranslationOptions):
|
||||
fields = (
|
||||
'name', 'description', 'text', 'title', 'FAQ_title'
|
||||
'name', 'description', 'text', 'title', 'FAQ_title', 'seo_title', 'seo_description', 'seo_text'
|
||||
)
|
||||
translator.register(StaticPage, StaticPage_TranslationOptions)
|
||||
|
||||
@@ -14,6 +14,12 @@ class Block_TranslationOptions(TranslationOptions):
|
||||
)
|
||||
translator.register(Block, Block_TranslationOptions)
|
||||
|
||||
class Option_TranslationOptions(TranslationOptions):
|
||||
fields = (
|
||||
'name', 'value', 'prefix'
|
||||
)
|
||||
translator.register(Option, Option_TranslationOptions)
|
||||
|
||||
|
||||
class FAQitem_TranslationOptions(TranslationOptions):
|
||||
fields = (
|
||||
|
||||
@@ -6,4 +6,6 @@ from .views import *
|
||||
|
||||
urlpatterns = [
|
||||
path('', MainPage, name='main'),
|
||||
path('page/<str:url>/', StaticPageView, name='static_page'),
|
||||
path('test_code', test_code, name='test_code'),
|
||||
]
|
||||
@@ -5,28 +5,151 @@ 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 django.http.response import JsonResponse, HttpResponse
|
||||
from django.views.decorators.http import require_GET, require_POST
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.contrib.auth.models import User
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from webpush import send_user_notification
|
||||
import json
|
||||
|
||||
def test_code(request):
|
||||
from RoutesApp.funcs import get_city_by_type_transport_and_address_point
|
||||
from RoutesApp.models import Route
|
||||
from ReferenceDataApp.models import Airport, City
|
||||
|
||||
# import allauth
|
||||
# from allauth.socialaccount.models import SocialApp
|
||||
# apps = SocialApp.objects.all()
|
||||
# apps.delete()
|
||||
|
||||
from RoutesApp.search_matches import search_matches
|
||||
search_matches()
|
||||
|
||||
# try:
|
||||
# # body = request.body
|
||||
# # data = json.loads(body)
|
||||
# # if 'head' not in data or 'body' not in data or 'id' not in data:
|
||||
# # return JsonResponse(status=400, data={"message": "Invalid data format"})
|
||||
# # user_id = data['id']
|
||||
# user = request.user
|
||||
# payload = {'head': '123', 'body': 'qwerty'}
|
||||
# send_user_notification(user=user, payload=payload, ttl=1000)
|
||||
# return JsonResponse(status=200, data={"message": "Web push successful"})
|
||||
# except TypeError:
|
||||
# return JsonResponse(status=500, data={"message": "An error occurred"})
|
||||
|
||||
# routes = Route.objects.all()
|
||||
#
|
||||
# for route in routes:
|
||||
# print(route.id)
|
||||
# required_save = False
|
||||
# if not route.from_city:
|
||||
# route.from_city = get_city_by_type_transport_and_address_point(route.type_transport, route.from_address_point)
|
||||
# required_save = True
|
||||
#
|
||||
# if not route.to_city:
|
||||
# route.to_city = get_city_by_type_transport_and_address_point(route.type_transport,
|
||||
# route.to_address_point)
|
||||
# required_save = True
|
||||
#
|
||||
# if required_save:
|
||||
# route.save()
|
||||
|
||||
return HttpResponse('finished')
|
||||
|
||||
|
||||
|
||||
def Page404(request, exeption=None):
|
||||
|
||||
Dict = {}
|
||||
|
||||
t = loader.get_template('404.html')
|
||||
try:
|
||||
res = get_inter_http_respose(t, Dict, request)
|
||||
return HttpResponse(res, status=404)
|
||||
except Exception as e:
|
||||
return HttpResponse(str(e))
|
||||
|
||||
|
||||
|
||||
|
||||
def MainPage(request):
|
||||
from RoutesApp.forms import RouteForm
|
||||
|
||||
from ReferenceDataApp.funcs import parse_data, search_cities_in_db, search_airports_in_db
|
||||
res = search_airports_in_db('ang')
|
||||
res = parse_data()
|
||||
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')[:3]
|
||||
|
||||
Dict = {
|
||||
'page': page,
|
||||
'FAQ': page.FAQ_items.filter(enable=True)
|
||||
'FAQ': page.FAQ_items.filter(enable=True),
|
||||
'route_form': RouteForm(),
|
||||
'articles': arts,
|
||||
'owner_type': 'mover'
|
||||
}
|
||||
|
||||
|
||||
|
||||
breadcrumbs_Dict = {
|
||||
}
|
||||
Dict.update({'breadcrumbs': breadcrumbs_Dict})
|
||||
|
||||
t = loader.get_template('pages/p_main.html')
|
||||
return HttpResponse(t.render(Dict, request))
|
||||
return get_inter_http_respose(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
|
||||
|
||||
Dict = {}
|
||||
|
||||
if url == '':
|
||||
return MainPage(request)
|
||||
elif url == 'for_movers':
|
||||
Dict.update({
|
||||
'route_form': RouteForm(),
|
||||
'owner_type': 'customer',
|
||||
})
|
||||
elif url == 'for_customers':
|
||||
Dict.update({
|
||||
'route_form': RouteForm(),
|
||||
'owner_type': 'mover'
|
||||
})
|
||||
# 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()
|
||||
Dict.update({
|
||||
'subscribes': subscribes,
|
||||
})
|
||||
|
||||
try:
|
||||
page = StaticPage.objects.get(url=url)
|
||||
except StaticPage.DoesNotExist:
|
||||
raise Http404
|
||||
|
||||
|
||||
Dict.update({
|
||||
'page': page,
|
||||
})
|
||||
|
||||
t = loader.get_template('pages/p_static_page.html')
|
||||
return get_inter_http_respose(t, Dict, request)
|
||||
# return HttpResponse(t.render(Dict, request))
|
||||
|
||||
|
||||
|
||||
0
PushMessages/__init__.py
Normal file
0
PushMessages/__init__.py
Normal file
3
PushMessages/admin.py
Normal file
3
PushMessages/admin.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
6
PushMessages/apps.py
Normal file
6
PushMessages/apps.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class PushmessagesConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'PushMessages'
|
||||
0
PushMessages/migrations/__init__.py
Normal file
0
PushMessages/migrations/__init__.py
Normal file
3
PushMessages/models.py
Normal file
3
PushMessages/models.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.db import models
|
||||
|
||||
# Create your models here.
|
||||
3
PushMessages/tests.py
Normal file
3
PushMessages/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
16
PushMessages/urls.py
Normal file
16
PushMessages/urls.py
Normal file
@@ -0,0 +1,16 @@
|
||||
# coding=utf-8
|
||||
from django.urls import path, include
|
||||
# from AuthApp.js_views import *
|
||||
# from AuthApp.import_funcs import *
|
||||
from .views import *
|
||||
from django.contrib.auth import views
|
||||
from RoutesApp.js_views import new_route_view_ajax
|
||||
from django.views.generic import TemplateView
|
||||
|
||||
urlpatterns = [
|
||||
|
||||
path('send_push', send_push),
|
||||
path('webpush/', include('webpush.urls')),
|
||||
path('sw.js', TemplateView.as_view(template_name='sw.js', content_type='application/x-javascript')),
|
||||
|
||||
]
|
||||
49
PushMessages/views.py
Normal file
49
PushMessages/views.py
Normal file
@@ -0,0 +1,49 @@
|
||||
from django.http.response import JsonResponse, HttpResponse
|
||||
from django.views.decorators.http import require_GET, require_POST
|
||||
from django.contrib.auth.models import User
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from webpush import send_user_notification
|
||||
import json
|
||||
from django.shortcuts import render, get_object_or_404
|
||||
from django.conf import settings
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
|
||||
def get_key_Dict():
|
||||
webpush_settings = getattr(settings, 'WEBPUSH_SETTINGS', {})
|
||||
vapid_key = webpush_settings.get('VAPID_PUBLIC_KEY')
|
||||
Dict = {
|
||||
'vapid_key': vapid_key
|
||||
}
|
||||
return Dict
|
||||
|
||||
def send_push(user, title, text, url=None, button_name=None, img=None):
|
||||
try:
|
||||
# body = request.body
|
||||
# data = json.loads(body)
|
||||
#
|
||||
# if 'head' not in data or 'body' not in data or 'id' not in data:
|
||||
# return JsonResponse(status=400, data={"message": "Invalid data format"})
|
||||
#
|
||||
# user_id = data['id']
|
||||
# user = get_object_or_404(User, pk=user_id)
|
||||
Dict = {
|
||||
'head': title,
|
||||
'body': text,
|
||||
}
|
||||
if url:
|
||||
Dict['url'] = url
|
||||
if button_name:
|
||||
Dict['button_name'] = button_name
|
||||
else:
|
||||
Dict['button_name'] = _('Перейти'),
|
||||
|
||||
if img:
|
||||
Dict['img'] = img
|
||||
|
||||
# payload = {'head': data['head'], 'body': data['body']}
|
||||
send_user_notification(user=user, payload=Dict, ttl=1000)
|
||||
|
||||
return JsonResponse(status=200, data={"message": "Web push successful"})
|
||||
except TypeError:
|
||||
return JsonResponse(status=500, data={"message": "An error occurred"})
|
||||
3
README.md
Normal file
3
README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
celery -A TWB.celery:app worker -l info
|
||||
|
||||
celery -A TWB.celery:app beat -l info
|
||||
@@ -4,6 +4,15 @@ from .models import *
|
||||
from modeltranslation.admin import TranslationAdmin
|
||||
|
||||
class Admin_Country(Admin_Trans_BaseModel):
|
||||
fieldsets = [
|
||||
[None, {
|
||||
'classes': ['wide'],
|
||||
'fields': [
|
||||
'name', 'enable', 'short_code', 'code',
|
||||
]
|
||||
}]
|
||||
]
|
||||
|
||||
list_display = [
|
||||
'id', 'name', 'name_en', 'name_ru',
|
||||
'short_code', 'code',
|
||||
@@ -13,15 +22,37 @@ class Admin_Country(Admin_Trans_BaseModel):
|
||||
admin.site.register(Country, Admin_Country)
|
||||
|
||||
class Admin_City(Admin_Trans_BaseModel):
|
||||
fieldsets = [
|
||||
[None, {
|
||||
'classes': ['wide'],
|
||||
'fields': [
|
||||
'name', 'enable', 'country',
|
||||
]
|
||||
}]
|
||||
]
|
||||
|
||||
list_display = [
|
||||
'id', 'name', 'name_en', 'name_ru',
|
||||
'country',
|
||||
'enable', 'area_id', 'parsing_finished_DT',
|
||||
'order', 'modifiedDT', 'createDT']
|
||||
search_fields = ['id', 'name_en', 'name_ru', 'country__name']
|
||||
list_filter = ['country']
|
||||
admin.site.register(City, Admin_City)
|
||||
|
||||
class Admin_Airport(Admin_Trans_BaseModel):
|
||||
fieldsets = [
|
||||
[None, {
|
||||
'classes': ['wide'],
|
||||
'fields': [
|
||||
'name', 'enable',
|
||||
'city', 'iata_code', 'icao_code',
|
||||
'international_name',
|
||||
# 'area_id'
|
||||
]
|
||||
}]
|
||||
]
|
||||
|
||||
list_display = [
|
||||
'id', 'name', 'name_en', 'name_ru',
|
||||
'city', 'iata_code', 'icao_code',
|
||||
@@ -29,4 +60,9 @@ class Admin_Airport(Admin_Trans_BaseModel):
|
||||
'enable', 'area_id', 'parsing_finished_DT',
|
||||
'order', 'modifiedDT', 'createDT']
|
||||
search_fields = ['id', 'name_en', 'name_ru', 'city__name', 'city__country__name', 'iata_code', 'icao_code', 'international_name']
|
||||
list_filter = ['city__country']
|
||||
raw_id_fields = [
|
||||
'city'
|
||||
]
|
||||
|
||||
admin.site.register(Airport, Admin_Airport)
|
||||
@@ -57,6 +57,8 @@ def create_airports_by_airportsList(airportsList, city=None):
|
||||
if airport_Dict['iata']:
|
||||
kwargs.update({'iata_code': airport_Dict['iata']})
|
||||
airport = Airport.objects.get(**kwargs)
|
||||
except Airport.DoesNotExist:
|
||||
print(f' - - {airport_Dict["iata"]} не найден в БД > добавляем')
|
||||
except Exception as e:
|
||||
print(f'error = {str(e)}')
|
||||
|
||||
@@ -122,7 +124,7 @@ def parse_data():
|
||||
continue
|
||||
|
||||
except Country.DoesNotExist:
|
||||
pass
|
||||
print(f'{country_item["ISO3166-1"]} не найдена в БД > добавляем')
|
||||
except Exception as e:
|
||||
print(f'error = {str(e)}')
|
||||
|
||||
@@ -176,33 +178,45 @@ def parse_data():
|
||||
kwargs = {}
|
||||
if city_Dict['name:en']:
|
||||
kwargs.update({'name_en': city_Dict['name:en']})
|
||||
if city_Dict['name:ru']:
|
||||
kwargs.update({'name_ru': city_Dict['name:ru']})
|
||||
|
||||
if country:
|
||||
kwargs.update({'country': country})
|
||||
|
||||
try:
|
||||
city = City.objects.get(**kwargs)
|
||||
except City.DoesNotExist:
|
||||
print(f' - {city_Dict["name:en"]} не найдена в БД > добавляем')
|
||||
except Exception as e:
|
||||
print(f'error = {str(e)}')
|
||||
cities = City.objects.filter(**kwargs)
|
||||
if cities:
|
||||
city = cities[0]
|
||||
cities.exclude(id=city.id).delete()
|
||||
else:
|
||||
print(f'error = {str(e)}')
|
||||
|
||||
# собираем данные
|
||||
city_kwargs = {
|
||||
'country': country,
|
||||
|
||||
# 'name_ru': city_Dict['name:ru'],
|
||||
# 'name_en': city_Dict['name:en'],
|
||||
|
||||
'geo_lat': str(city_Dict['@lat']),
|
||||
'geo_lon': str(city_Dict['@lon']),
|
||||
}
|
||||
|
||||
if city_Dict['name:ru']:
|
||||
kwargs.update({'name_ru': city_Dict['name:ru']})
|
||||
|
||||
city_kwargs.update(kwargs)
|
||||
|
||||
if 'area_id' in city_Dict:
|
||||
city_kwargs.update({'area_id': city_Dict['area_id']})
|
||||
|
||||
if not city:
|
||||
|
||||
city_kwargs = {
|
||||
'country': country,
|
||||
|
||||
# 'name_ru': city_Dict['name:ru'],
|
||||
# 'name_en': city_Dict['name:en'],
|
||||
|
||||
'geo_lat': str(city_Dict['@lat']),
|
||||
'geo_lon': str(city_Dict['@lon']),
|
||||
}
|
||||
|
||||
city_kwargs.update(kwargs)
|
||||
|
||||
if 'area_id' in city_Dict:
|
||||
city_kwargs.update({'area_id': city_Dict['area_id']})
|
||||
|
||||
city = City.objects.create(**city_kwargs)
|
||||
|
||||
else:
|
||||
City.objects.filter(id=city.id).update(**city_kwargs)
|
||||
|
||||
|
||||
if 'airports' in city_Dict:
|
||||
|
||||
@@ -13,6 +13,7 @@ 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
|
||||
|
||||
def get_address_point_ajax(request):
|
||||
from .funcs import search_cities_in_db, search_airports_in_db
|
||||
@@ -54,7 +55,7 @@ def get_address_point_ajax(request):
|
||||
else:
|
||||
item['city_name'] = item['name']
|
||||
item['country_name'] = item['country__name']
|
||||
item['fullname'] = f'{item["country_name"]} / {item["city_name"]}'
|
||||
item['fullname'] = f'{item["city_name"]} / {item["country_name"]}'
|
||||
html = f"{html}{render_to_string('widgets/w_ac_input_address_point.html', item)}"
|
||||
i += 1
|
||||
|
||||
|
||||
0
ReferenceDataApp/management/__init__.py
Normal file
0
ReferenceDataApp/management/__init__.py
Normal file
0
ReferenceDataApp/management/commands/__init__.py
Normal file
0
ReferenceDataApp/management/commands/__init__.py
Normal file
9
ReferenceDataApp/management/commands/parse.py
Normal file
9
ReferenceDataApp/management/commands/parse.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from datetime import datetime
|
||||
from BaseModels.mailSender import techSendMail
|
||||
from ...funcs import parse_data
|
||||
|
||||
class Command(BaseCommand):
|
||||
|
||||
def handle(self, *args, **options):
|
||||
parse_data()
|
||||
@@ -3,21 +3,21 @@ from BaseModels.base_models import BaseModel
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
class Country(BaseModel):
|
||||
international_name = models.CharField(max_length=250, verbose_name='Международное название', blank=True, null=True)
|
||||
official_name = models.CharField(max_length=250, verbose_name='Официальное название', blank=True, null=True)
|
||||
international_name = models.CharField(max_length=250, verbose_name=_('Международное название'), blank=True, null=True)
|
||||
official_name = models.CharField(max_length=250, verbose_name=_('Официальное название'), blank=True, null=True)
|
||||
|
||||
short_code = models.CharField(max_length=2, verbose_name='Код страны по ISO3166-1:alpha2')
|
||||
code = models.CharField(max_length=3, verbose_name='Код страны по ISO3166-1:alpha3')
|
||||
num_code = models.CharField(max_length=3, verbose_name='Код страны по ISO3166-1:numeric', blank=True, null=True)
|
||||
short_code = models.CharField(max_length=2, verbose_name=_('Код страны по ISO3166-1:alpha2'))
|
||||
code = models.CharField(max_length=3, verbose_name=_('Код страны по ISO3166-1:alpha3'))
|
||||
num_code = models.CharField(max_length=3, verbose_name=_('Код страны по ISO3166-1:numeric'), blank=True, null=True)
|
||||
|
||||
flag_img_url = models.URLField(verbose_name='Ссылка на изображение флага', blank=True, null=True)
|
||||
flag_img_url = models.URLField(verbose_name=_('Ссылка на изображение флага'), blank=True, null=True)
|
||||
|
||||
geo_lat = models.CharField(max_length=20, verbose_name='GPS широта', blank=True, null=True)
|
||||
geo_lon = models.CharField(max_length=20, verbose_name='GPS долгота', blank=True, null=True)
|
||||
geo_lat = models.CharField(max_length=20, verbose_name=_('GPS широта'), blank=True, null=True)
|
||||
geo_lon = models.CharField(max_length=20, verbose_name=_('GPS долгота'), blank=True, null=True)
|
||||
|
||||
area_id = models.BigIntegerField(blank=True, null=True)
|
||||
|
||||
parsing_finished_DT = models.DateTimeField(verbose_name='Дата и время завершения парсинга', blank=True, null=True)
|
||||
parsing_finished_DT = models.DateTimeField(verbose_name=_('Дата и время завершения парсинга'), blank=True, null=True)
|
||||
|
||||
def __str__(self):
|
||||
if self.name:
|
||||
@@ -39,14 +39,14 @@ class Country(BaseModel):
|
||||
class City(BaseModel):
|
||||
|
||||
country = models.ForeignKey(
|
||||
Country, verbose_name='Страна', related_name='rel_cities_for_country', on_delete=models.CASCADE)
|
||||
Country, verbose_name=_('Страна'), related_name='rel_cities_for_country', on_delete=models.CASCADE)
|
||||
|
||||
geo_lat = models.CharField(max_length=20, verbose_name='GPS широта', blank=True, null=True)
|
||||
geo_lon = models.CharField(max_length=20, verbose_name='GPS долгота', blank=True, null=True)
|
||||
geo_lat = models.CharField(max_length=20, verbose_name=_('GPS широта'), blank=True, null=True)
|
||||
geo_lon = models.CharField(max_length=20, verbose_name=_('GPS долгота'), blank=True, null=True)
|
||||
|
||||
area_id = models.BigIntegerField(blank=True, null=True)
|
||||
|
||||
parsing_finished_DT = models.DateTimeField(verbose_name='Дата и время завершения парсинга', blank=True, null=True)
|
||||
parsing_finished_DT = models.DateTimeField(verbose_name=_('Дата и время завершения парсинга'), blank=True, null=True)
|
||||
|
||||
def __str__(self):
|
||||
if self.name:
|
||||
@@ -54,6 +54,14 @@ class City(BaseModel):
|
||||
else:
|
||||
return f'{self.id}'
|
||||
|
||||
def get_country_n_city_str(self):
|
||||
country = _('Неизвестно')
|
||||
city = self.name
|
||||
if self.country:
|
||||
country = self.country
|
||||
|
||||
return f'{city} / {country}'
|
||||
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Город')
|
||||
@@ -64,20 +72,20 @@ class City(BaseModel):
|
||||
class Airport(BaseModel):
|
||||
|
||||
city = models.ForeignKey(
|
||||
City, verbose_name='Город', related_name='rel_airports_for_city', on_delete=models.CASCADE,
|
||||
City, verbose_name=_('Город'), related_name='rel_airports_for_city', on_delete=models.CASCADE,
|
||||
blank=True, null=True)
|
||||
|
||||
international_name = models.CharField(max_length=250, verbose_name='Международное название', blank=True, null=True)
|
||||
international_name = models.CharField(max_length=250, verbose_name=_('Международное название'), blank=True, null=True)
|
||||
|
||||
iata_code = models.CharField(max_length=3, verbose_name='IATA')
|
||||
icao_code = models.CharField(max_length=4, verbose_name='ICAO')
|
||||
|
||||
geo_lat = models.CharField(max_length=20, verbose_name='GPS широта', blank=True, null=True)
|
||||
geo_lon = models.CharField(max_length=20, verbose_name='GPS долгота', blank=True, null=True)
|
||||
geo_lat = models.CharField(max_length=20, verbose_name=_('GPS широта'), blank=True, null=True)
|
||||
geo_lon = models.CharField(max_length=20, verbose_name=_('GPS долгота'), blank=True, null=True)
|
||||
|
||||
area_id = models.BigIntegerField(blank=True, null=True)
|
||||
|
||||
parsing_finished_DT = models.DateTimeField(verbose_name='Дата и время завершения парсинга', blank=True, null=True)
|
||||
parsing_finished_DT = models.DateTimeField(verbose_name=_('Дата и время завершения парсинга'), blank=True, null=True)
|
||||
|
||||
def __str__(self):
|
||||
if self.name:
|
||||
|
||||
@@ -4,12 +4,16 @@ from django.contrib import admin
|
||||
|
||||
class Admin_Route(Admin_Trans_BaseModel):
|
||||
list_display = [
|
||||
'id', 'type_transport', 'cargo_type',
|
||||
'departure_DT', 'from_address_point', 'from_place',
|
||||
'arrival_DT', 'to_place', 'owner',
|
||||
'id', 'owner_type', 'receive_msg_by_email', 'type_transport', 'cargo_type',
|
||||
'departure_DT', 'from_city', 'from_place',
|
||||
'arrival_DT', 'to_city', 'to_place', 'owner',
|
||||
'order', 'modifiedDT', 'createDT'
|
||||
]
|
||||
|
||||
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']
|
||||
raw_id_fields = ['from_city', 'to_city']
|
||||
|
||||
admin.site.register(Route,Admin_Route)
|
||||
|
||||
@@ -6,6 +6,47 @@ from django.core.exceptions import ValidationError
|
||||
from .models import *
|
||||
|
||||
|
||||
def routeForm_assign_choices_by_type_transport(form, type_transport):
|
||||
if type_transport == 'avia':
|
||||
transfer_location_choices = (
|
||||
('airport', _('В аэропорту')),
|
||||
('city', _('По городу')),
|
||||
('other', _('По договоренности'))
|
||||
)
|
||||
|
||||
cargo_type_choices = (
|
||||
('cargo', _('Груз')),
|
||||
('parcel', _('Бандероль')),
|
||||
('package', _('Посылка')),
|
||||
('letter', _('Письмо\Документ'))
|
||||
)
|
||||
|
||||
else:
|
||||
transfer_location_choices = (
|
||||
('city', _('По городу')),
|
||||
('other', _('По договоренности'))
|
||||
)
|
||||
|
||||
cargo_type_choices = (
|
||||
('passenger', _('Пассажир')),
|
||||
('cargo', _('Груз')),
|
||||
('parcel', _('Бандероль')),
|
||||
('package', _('Посылка')),
|
||||
('letter', _('Письмо\Документ'))
|
||||
)
|
||||
|
||||
form.fields['from_place'].choices = transfer_location_choices
|
||||
form.fields['to_place'].choices = transfer_location_choices
|
||||
form.fields['cargo_type'].choices = cargo_type_choices
|
||||
|
||||
form.base_fields['from_place'].choices = transfer_location_choices
|
||||
form.base_fields['to_place'].choices = transfer_location_choices
|
||||
form.base_fields['cargo_type'].choices = cargo_type_choices
|
||||
|
||||
return form
|
||||
|
||||
|
||||
|
||||
class RouteForm(forms.ModelForm):
|
||||
from_address_point_txt = forms.CharField(required=True)
|
||||
to_address_point_txt = forms.CharField(required=True)
|
||||
@@ -24,6 +65,22 @@ class RouteForm(forms.ModelForm):
|
||||
|
||||
try:
|
||||
|
||||
if 'phone' in cleaned_data and 'phone' in cleaned_data:
|
||||
from BaseModels.validators.form_field_validators import get_phone_valid_error
|
||||
error = get_phone_valid_error(cleaned_data["phone"])
|
||||
if error:
|
||||
self.add_error('phone', error)
|
||||
|
||||
if 'extra_phone' in cleaned_data and 'extra_phone' in cleaned_data:
|
||||
from BaseModels.validators.form_field_validators import get_phone_valid_error
|
||||
error = get_phone_valid_error(cleaned_data["extra_phone"])
|
||||
if error:
|
||||
self.add_error('extra_phone', error)
|
||||
|
||||
if 'departure_DT' in cleaned_data and 'arrival_DT' in cleaned_data and cleaned_data['arrival_DT'] < cleaned_data['departure_DT']:
|
||||
self.add_error('arrival_DT', _('Указана неверная дата прибытия'))
|
||||
|
||||
|
||||
if 'from_place' in self.data and self.data['from_place'] not in [item[0] for item in self.fields['from_place'].choices]:
|
||||
cleaned_data['from_place'] = self.fields['from_place'].choices[0][0]
|
||||
if 'from_place' in self.errors and self.errors['from_place'].data[0].code == 'invalid_choice':
|
||||
|
||||
@@ -1,5 +1,144 @@
|
||||
from .models import *
|
||||
def get_routes_Dict(user=None):
|
||||
from .forms import *
|
||||
from django.utils.translation import gettext as _
|
||||
from django.template.loader import render_to_string
|
||||
from datetime import datetime
|
||||
|
||||
elements_on_page = 25
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def get_profile_new_route_page_html(request, data):
|
||||
|
||||
form = RouteForm()
|
||||
Dict = {
|
||||
'form': form
|
||||
}
|
||||
|
||||
|
||||
try:
|
||||
|
||||
errors_off = True
|
||||
|
||||
if 'from_address_point' in data:
|
||||
del data['from_address_point']
|
||||
if 'from_address_point_txt' in data:
|
||||
del data['from_address_point_txt']
|
||||
|
||||
if 'to_address_point' in data:
|
||||
del data['to_address_point']
|
||||
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:
|
||||
form = routeForm_assign_choices_by_type_transport(form, data['type_transport'])
|
||||
|
||||
# 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)}'})
|
||||
print(str(e))
|
||||
|
||||
html = render_to_string('blocks/profile/b_new_route.html', Dict, request=request)
|
||||
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_city_by_type_transport_and_address_point(type_transport, address_point):
|
||||
from ReferenceDataApp.models import Airport, City
|
||||
|
||||
try:
|
||||
if type_transport == 'avia':
|
||||
return Airport.objects.get(id=address_point).city
|
||||
else:
|
||||
return City.objects.get(id=address_point)
|
||||
except Exception as e:
|
||||
msg = f'get_city_by_type_transport_and_address_point Error = {str(e)}, type_transport = {type_transport}, address_point = {address_point}'
|
||||
print(msg)
|
||||
return None
|
||||
|
||||
|
||||
def get_profile_my_routes_page_content_html(request):
|
||||
routes_Dict = get_routes_Dict(request.user)
|
||||
if 'errors' in routes_Dict:
|
||||
msg = f'get_my_routes_page_content_html errors = {str(routes_Dict)}'
|
||||
print(msg)
|
||||
return msg
|
||||
|
||||
html = render_to_string('blocks/profile/b_my_routes.html', routes_Dict, request=request)
|
||||
return html
|
||||
|
||||
|
||||
def get_routes_Dict(user=None, data=None):
|
||||
from ReferenceDataApp.models import Airport, Country, City
|
||||
|
||||
# if not user and user.is_authenticated:
|
||||
@@ -15,10 +154,97 @@ def get_routes_Dict(user=None):
|
||||
'owner': user
|
||||
})
|
||||
|
||||
routes = Route.objects.filter(**kwargs).order_by('-modifiedDT')
|
||||
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 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 in (
|
||||
'departure_DT', 'arrival_DT'
|
||||
):
|
||||
dates = val.split(' - ')
|
||||
kwargs.update({
|
||||
f'{key}__date__gte': datetime.strptime(dates[0], '%d.%m.%Y'),
|
||||
f'{key}__date__lte': datetime.strptime(dates[1], '%d.%m.%Y').replace(hour=23, minute=59, second=59)
|
||||
})
|
||||
|
||||
if key not in (
|
||||
'from_address_point_txt', 'to_address_point_txt', 'csrfmiddlewaretoken', 'sort', 'weight',
|
||||
'from_el', 'to_el', 'from_address_point', 'to_address_point', 'type_transport',
|
||||
'departure_DT', 'arrival_DT'
|
||||
):
|
||||
kwargs.update({key: val})
|
||||
|
||||
if key == 'from_address_point':
|
||||
city = get_city_by_type_transport_and_address_point(type_transport, val)
|
||||
kwargs.update({f'from_city': city})
|
||||
|
||||
res_Dict.update({
|
||||
'from_address_point_txt': city.get_country_n_city_str()
|
||||
})
|
||||
|
||||
if key == 'to_address_point':
|
||||
city = get_city_by_type_transport_and_address_point(type_transport, val)
|
||||
kwargs.update({f'to_city': city})
|
||||
res_Dict.update({
|
||||
'to_address_point_txt': city.get_country_n_city_str()
|
||||
})
|
||||
|
||||
if key == 'from_el':
|
||||
from_el = int(val)
|
||||
if key == 'to_el':
|
||||
to_el = int(val)
|
||||
|
||||
routes = Route.objects.filter(**kwargs).order_by('-departure_DT', '-arrival_DT', '-modifiedDT')
|
||||
routes_count = routes.count()
|
||||
|
||||
if from_el and to_el:
|
||||
routes = routes[from_el:to_el]
|
||||
elif from_el:
|
||||
routes = routes[from_el:]
|
||||
elif to_el:
|
||||
routes = routes[:to_el]
|
||||
else:
|
||||
to_el = elements_on_page
|
||||
routes = routes[:to_el]
|
||||
|
||||
last_block = False
|
||||
if not to_el or to_el >= routes_count:
|
||||
last_block = True
|
||||
|
||||
if routes_count - to_el > elements_on_page:
|
||||
next_page_els_count = elements_on_page
|
||||
else:
|
||||
next_page_els_count = routes_count - to_el
|
||||
|
||||
try:
|
||||
|
||||
for route in routes:
|
||||
@@ -40,9 +266,12 @@ def get_routes_Dict(user=None):
|
||||
msg = f'get_routes_for_user get route Error = {str(e)}'
|
||||
print(msg)
|
||||
|
||||
res_Dict = {
|
||||
'routes': routes
|
||||
}
|
||||
res_Dict.update({
|
||||
'routes': routes,
|
||||
'last_block': last_block,
|
||||
'last_el': to_el,
|
||||
'next_page_els_count': next_page_els_count
|
||||
})
|
||||
return res_Dict
|
||||
|
||||
|
||||
|
||||
@@ -9,6 +9,9 @@ urlpatterns = [
|
||||
path('create_or_change_route/', create_or_change_route_ajax, name='create_or_change_route_ajax'),
|
||||
|
||||
path('edit_route/', edit_route_ajax, name='edit_route_ajax'),
|
||||
path('del_route/', del_route_ajax, name='del_route_ajax'),
|
||||
|
||||
path('get_routes/', get_my_routes_ajax, name='get_my_routes_ajax'),
|
||||
path('find_routes/', find_routes_ajax, name='find_routes_ajax'),
|
||||
|
||||
path('get_routes/', get_routes_ajax, name='get_routes_ajax'),
|
||||
]
|
||||
@@ -14,7 +14,40 @@ from datetime import datetime
|
||||
from django.template.loader import render_to_string
|
||||
from django.urls import reverse
|
||||
from .forms import *
|
||||
from .funcs import get_routes_Dict
|
||||
from .funcs import *
|
||||
|
||||
|
||||
def del_route_ajax(request):
|
||||
if request.method != 'POST':
|
||||
raise Http404
|
||||
|
||||
try:
|
||||
|
||||
data = json.loads(request.body)
|
||||
if not 'route_id' in data:
|
||||
msg = f'Недостаточно данных'
|
||||
return JsonResponse({'errors': msg})
|
||||
|
||||
route = Route.objects.filter(id=data['route_id']).delete()
|
||||
|
||||
routes_Dict = get_routes_Dict(request.user)
|
||||
if 'errors' in routes_Dict:
|
||||
return JsonResponse(routes_Dict, status=400)
|
||||
|
||||
html = render_to_string('blocks/profile/b_my_routes.html', routes_Dict, request=request)
|
||||
|
||||
res_Dict = {
|
||||
'html': html
|
||||
}
|
||||
|
||||
return JsonResponse(res_Dict)
|
||||
|
||||
except Exception as e:
|
||||
# form.errors.append({'__all__': f'Ошибка: {str(e)}'})
|
||||
msg = f'Ошибка del_route_ajax = {str(e)}'
|
||||
print(msg)
|
||||
return JsonResponse({'errors': msg})
|
||||
|
||||
|
||||
|
||||
def edit_route_ajax(request):
|
||||
@@ -34,6 +67,8 @@ def edit_route_ajax(request):
|
||||
route = Route.objects.get(id=data['route_id'])
|
||||
|
||||
form = RouteForm(instance=route)
|
||||
form = routeForm_assign_choices_by_type_transport(form, route.type_transport)
|
||||
|
||||
route_address_points_Dict = route.get_address_points()
|
||||
form.initial.update({
|
||||
'from_address_point_txt': route_address_points_Dict['from_address_point_txt'],
|
||||
@@ -57,14 +92,17 @@ def edit_route_ajax(request):
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def new_route_view_ajax(request):
|
||||
if request.method != 'POST':
|
||||
raise Http404
|
||||
|
||||
form = RouteForm()
|
||||
Dict = {
|
||||
'form': form
|
||||
}
|
||||
# form = RouteForm()
|
||||
# Dict = {
|
||||
# 'form': form
|
||||
# }
|
||||
try:
|
||||
|
||||
errors_off = True
|
||||
@@ -74,79 +112,64 @@ def new_route_view_ajax(request):
|
||||
data = json.loads(request.body)
|
||||
# show_errors = False
|
||||
|
||||
if 'from_address_point' in data:
|
||||
del data['from_address_point']
|
||||
if 'from_address_point_txt' in data:
|
||||
del data['from_address_point_txt']
|
||||
|
||||
if 'to_address_point' in data:
|
||||
del data['to_address_point']
|
||||
if 'to_address_point_txt' in data:
|
||||
del data['to_address_point_txt']
|
||||
|
||||
if 'type_transport' in data:
|
||||
if data['type_transport'] == 'avia':
|
||||
transfer_location_choices = (
|
||||
('airport', _('В аэропорту')),
|
||||
('city', _('По городу')),
|
||||
('other', _('По договоренности'))
|
||||
)
|
||||
|
||||
cargo_type_choices = (
|
||||
('passenger', _('Пассажир')),
|
||||
('cargo', _('Груз')),
|
||||
('parcel', _('Бандероль')),
|
||||
('package', _('Посылка')),
|
||||
('letter', _('Письмо\Документ'))
|
||||
)
|
||||
html = get_profile_new_route_page_html(request, data)
|
||||
|
||||
|
||||
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 = CreateRouteForm(initial=data)
|
||||
|
||||
# if not form.is_valid():
|
||||
# pass
|
||||
|
||||
Dict = {
|
||||
'form': form,
|
||||
'errors_off': errors_off
|
||||
}
|
||||
|
||||
# print(form)
|
||||
except Exception as e:
|
||||
# form.errors.append({'__all__': f'Ошибка: {str(e)}'})
|
||||
print(str(e))
|
||||
msg = f'new_route_view_ajax Error = {str(e)}'
|
||||
print(msg)
|
||||
html = msg
|
||||
|
||||
html = render_to_string('blocks/profile/b_new_route.html', Dict, request=request)
|
||||
|
||||
# html = render_to_string('blocks/profile/b_new_route.html', Dict, request=request)
|
||||
return JsonResponse({'html': html}, status=200)
|
||||
|
||||
|
||||
def get_routes_ajax(request):
|
||||
def find_routes_ajax(request):
|
||||
|
||||
|
||||
if request.method != 'POST':
|
||||
raise Http404
|
||||
|
||||
try:
|
||||
|
||||
|
||||
data = request.POST.dict()
|
||||
if not data and request.body:
|
||||
data = json.loads(request.body)
|
||||
|
||||
if not 'owner_type' in data:
|
||||
data['owner_type'] = 'mover'
|
||||
routes_Dict = get_routes_Dict(data=data)
|
||||
if 'errors' in routes_Dict:
|
||||
return JsonResponse(routes_Dict, status=400)
|
||||
|
||||
if routes_Dict['routes']:
|
||||
html = render_to_string('blocks/b_search_routes.html', routes_Dict, request=request)
|
||||
else:
|
||||
html = render_to_string('templates_js_translate/not_found_find_routes.html', routes_Dict, request=request)
|
||||
|
||||
res_Dict = {
|
||||
'html': html,
|
||||
'last_block': routes_Dict['last_block'],
|
||||
'next_page_els_count': routes_Dict['next_page_els_count'],
|
||||
# 'form': RouteForm(initial=data)
|
||||
}
|
||||
|
||||
return JsonResponse(res_Dict)
|
||||
|
||||
except Exception as e:
|
||||
|
||||
errors_Dict = {
|
||||
'errors': {
|
||||
'all__': f'ошибка в запросе = {str(e)}'
|
||||
}
|
||||
}
|
||||
return JsonResponse(errors_Dict, status=400)
|
||||
|
||||
|
||||
def get_my_routes_ajax(request):
|
||||
|
||||
|
||||
if request.method != 'POST':
|
||||
@@ -178,6 +201,7 @@ def get_routes_ajax(request):
|
||||
|
||||
|
||||
def create_or_change_route_ajax(request, route_id=None):
|
||||
from ReferenceDataApp.models import Airport, City
|
||||
|
||||
if request.method != 'POST':
|
||||
raise Http404
|
||||
@@ -187,6 +211,8 @@ def create_or_change_route_ajax(request, route_id=None):
|
||||
try:
|
||||
|
||||
data = request.POST
|
||||
if not data:
|
||||
data = json.loads(request.body)
|
||||
|
||||
route = None
|
||||
if route_id:
|
||||
@@ -206,9 +232,20 @@ 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 and data['owner_type']:
|
||||
obj.owner_type = data['owner_type']
|
||||
|
||||
if obj.from_address_point:
|
||||
obj.from_city = get_city_by_type_transport_and_address_point(obj.type_transport, obj.from_address_point)
|
||||
|
||||
if obj.to_address_point:
|
||||
obj.to_city = get_city_by_type_transport_and_address_point(obj.type_transport, obj.to_address_point)
|
||||
|
||||
obj.owner = request.user
|
||||
obj.save()
|
||||
|
||||
route_id = obj.id
|
||||
|
||||
routes_Dict = get_routes_Dict(request.user)
|
||||
|
||||
if 'errors' in routes_Dict:
|
||||
@@ -220,7 +257,8 @@ def create_or_change_route_ajax(request, route_id=None):
|
||||
html = render_to_string('blocks/profile/b_my_routes.html', routes_Dict, request=request)
|
||||
|
||||
res_Dict = {
|
||||
'html': html
|
||||
'html': html,
|
||||
'route_id': route_id
|
||||
}
|
||||
|
||||
return JsonResponse(res_Dict)
|
||||
|
||||
0
RoutesApp/management/__init__.py
Normal file
0
RoutesApp/management/__init__.py
Normal file
0
RoutesApp/management/commands/__init__.py
Normal file
0
RoutesApp/management/commands/__init__.py
Normal file
36
RoutesApp/management/commands/every_1hour_start.py
Normal file
36
RoutesApp/management/commands/every_1hour_start.py
Normal file
@@ -0,0 +1,36 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from datetime import datetime
|
||||
from BaseModels.mailSender import techSendMail
|
||||
from GeneralApp.funcs_options import get_options_by_opt_types, get_mail_send_options
|
||||
|
||||
class Command(BaseCommand):
|
||||
|
||||
def handle(self, *args, **options):
|
||||
mail_sets = get_mail_send_options()
|
||||
|
||||
log = ''
|
||||
log_begin_DT = datetime.now()
|
||||
msg = str(log_begin_DT)
|
||||
print('-------------')
|
||||
print(msg)
|
||||
|
||||
try:
|
||||
from ...search_matches import search_matches
|
||||
msg = search_matches()
|
||||
if msg:
|
||||
print(msg)
|
||||
except Exception as e:
|
||||
msg = f'every_1hour_start search_matches fail = {str(e)}'
|
||||
print(msg)
|
||||
techSendMail(mail_sets, msg, title='every_1hour_start search_matches')
|
||||
|
||||
|
||||
|
||||
if msg:
|
||||
techSendMail(mail_sets, str(msg), title='every_1hour_start get_competitors_prices')
|
||||
|
||||
|
||||
|
||||
print(f'- processing time = {str(datetime.now() - log_begin_DT)} -')
|
||||
|
||||
|
||||
13
RoutesApp/management/commands/fix_code.py
Normal file
13
RoutesApp/management/commands/fix_code.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from datetime import datetime
|
||||
|
||||
class Command(BaseCommand):
|
||||
|
||||
def handle(self, *args, **options):
|
||||
|
||||
# from B2BApp.funcs import assign_contracts_for_orders_by_tmp_data
|
||||
# log = assign_contracts_for_orders_by_tmp_data()
|
||||
from GeneralApp.views import test_code
|
||||
test_code(None)
|
||||
|
||||
self.stdout.write(u'fix_code end')
|
||||
25
RoutesApp/migrations/0005_route_from_city_route_to_city.py
Normal file
25
RoutesApp/migrations/0005_route_from_city_route_to_city.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# Generated by Django 4.2.2 on 2023-08-29 18:02
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('ReferenceDataApp', '0005_remove_airport_parsing_finished_and_more'),
|
||||
('RoutesApp', '0004_alter_route_type_transport'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='route',
|
||||
name='from_city',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='rel_routes_for_cityFrom', to='ReferenceDataApp.city', verbose_name='Город отправки'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='route',
|
||||
name='to_city',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='rel_routes_for_cityTo', to='ReferenceDataApp.city', verbose_name='Город получения'),
|
||||
),
|
||||
]
|
||||
@@ -24,13 +24,14 @@ cargo_type_choices = (
|
||||
)
|
||||
|
||||
owner_type_choices = (
|
||||
('customer', 'Заказчик'),
|
||||
('mover', 'Перевозчик')
|
||||
('customer', _('Заказчик')),
|
||||
('mover', _('Перевозчик'))
|
||||
)
|
||||
|
||||
|
||||
class Route(BaseModel):
|
||||
from django.contrib.auth.models import User
|
||||
from ReferenceDataApp.models import City
|
||||
|
||||
owner_type = models.CharField(
|
||||
choices=owner_type_choices, default='customer', verbose_name=_('Тип опреации'))
|
||||
@@ -41,8 +42,14 @@ class Route(BaseModel):
|
||||
arrival_DT = models.DateTimeField(default=True, verbose_name=_('Дата и время прибытия'))
|
||||
from_address_point = models.IntegerField(verbose_name=_('Пункт выезда'))
|
||||
to_address_point = models.IntegerField(verbose_name=_('Пункт приезда'))
|
||||
# from_city = forms.CharField(required=True)
|
||||
# to_city = forms.CharField(required=True)
|
||||
from_city = models.ForeignKey(
|
||||
City, verbose_name=_('Город отправки'), related_name='rel_routes_for_cityFrom', on_delete=models.SET_NULL,
|
||||
null=True, blank=True
|
||||
)
|
||||
to_city = models.ForeignKey(
|
||||
City, verbose_name=_('Город получения'), related_name='rel_routes_for_cityTo', on_delete=models.SET_NULL,
|
||||
null=True, blank=True
|
||||
)
|
||||
from_place = models.CharField(choices=transfer_location_choices, default='other',
|
||||
verbose_name=_('Откуда можете забрать?'))
|
||||
to_place = models.CharField(choices=transfer_location_choices, default='other',
|
||||
@@ -67,6 +74,21 @@ class Route(BaseModel):
|
||||
verbose_name_plural = _(u'Маршруты')
|
||||
ordering = ('name',)
|
||||
|
||||
def from_country_n_city_str(self):
|
||||
res = _('Неизвестно')
|
||||
if self.from_city:
|
||||
res = self.from_city.get_country_n_city_str()
|
||||
|
||||
return res
|
||||
|
||||
def to_country_n_city_str(self):
|
||||
res = _('Неизвестно')
|
||||
if self.to_city:
|
||||
res = self.to_city.get_country_n_city_str()
|
||||
|
||||
return res
|
||||
|
||||
|
||||
def get_address_points(self):
|
||||
from ReferenceDataApp.models import Airport, City
|
||||
|
||||
@@ -89,8 +111,8 @@ class Route(BaseModel):
|
||||
to_address_point_Dict = to_address_point_objs.values(
|
||||
'id', 'name', 'country__name')[0]
|
||||
|
||||
from_address_point_txt = f'{from_address_point_Dict["country__name"]} / {from_address_point_Dict["name"]}'
|
||||
to_address_point_txt = f'{to_address_point_Dict["country__name"]} / {to_address_point_Dict["name"]}'
|
||||
from_address_point_txt = f'{from_address_point_Dict["name"]} / {from_address_point_Dict["country__name"]}'
|
||||
to_address_point_txt = f'{to_address_point_Dict["name"]} / {to_address_point_Dict["country__name"]}'
|
||||
|
||||
return {
|
||||
'from_address_point_obj': from_address_point_objs[0],
|
||||
|
||||
145
RoutesApp/search_matches.py
Normal file
145
RoutesApp/search_matches.py
Normal file
@@ -0,0 +1,145 @@
|
||||
from .models import *
|
||||
from datetime import datetime, timedelta
|
||||
from django.utils.translation import gettext as _
|
||||
from django.template.loader import render_to_string
|
||||
from GeneralApp.funcs_options import get_options_by_opt_types, get_mail_send_options
|
||||
from BaseModels.mailSender import admin_send_mail_by_SMTPlib, techSendMail
|
||||
|
||||
|
||||
|
||||
def get_Dict_for_send_msgs(kwargs, search_owner_type):
|
||||
print('get_Dict_for_send_msgs')
|
||||
|
||||
Dict = {
|
||||
'search_owner_type': search_owner_type
|
||||
}
|
||||
sets = get_options_by_opt_types(['domain', 'project_name'], only_vals=True)
|
||||
Dict.update(sets)
|
||||
|
||||
|
||||
Dict.update({'logo': f'{sets["domain"]}/static/img/svg/LogoMobile.svg', })
|
||||
|
||||
find_routes_page_url = f'{sets["domain"]}/routes/route_search_results/?'
|
||||
kwargs_list = [f'{key}={value}' for key, value in kwargs.items()]
|
||||
kwargs_list.append(f'owner_type={search_owner_type}')
|
||||
find_routes_page_url += f'{"&".join(kwargs_list)}'
|
||||
|
||||
Dict.update({'find_routes_page_url': find_routes_page_url})
|
||||
|
||||
return Dict
|
||||
|
||||
|
||||
|
||||
def send_push_message_for_found_matches_routes(route, data_Dict):
|
||||
print(f'send_push_message_for_found_matches_routes to route id = {route.id}')
|
||||
|
||||
if not route.owner.is_authenticated:
|
||||
return None
|
||||
|
||||
from PushMessages.views import send_push
|
||||
title = 'Мы нашли исполнителя по Вашему объявлению!'
|
||||
text = 'Для просмотра результата нажмите на кнопку ниже'
|
||||
send_push(route.owner, title, text, url=data_Dict['find_routes_page_url'], button_name=_('Перейти к найденному'))
|
||||
return None
|
||||
|
||||
|
||||
|
||||
def send_mail_found_matches_routes(route, data_Dict):
|
||||
print(f'send_mail_found_matches_routes to route id = {route.id}')
|
||||
|
||||
Dict = {
|
||||
'route': route,
|
||||
}
|
||||
Dict.update(data_Dict)
|
||||
|
||||
html = render_to_string('mail/m_found_matched_routes.html', Dict)
|
||||
|
||||
|
||||
mail_sets = get_mail_send_options()
|
||||
to = [route.owner.email, 'web@syncsystems.net']
|
||||
subject = _('Мы нашли исполнителя по Вашему объявлению!')
|
||||
res = admin_send_mail_by_SMTPlib(
|
||||
mail_sets,
|
||||
subject=subject,
|
||||
from_email=mail_sets['sender_email'], to=to,
|
||||
html_content=html
|
||||
)
|
||||
|
||||
return res
|
||||
|
||||
|
||||
def search_matches(for_routes=None):
|
||||
print('search_matches')
|
||||
|
||||
log = ''
|
||||
|
||||
try:
|
||||
if not for_routes:
|
||||
for_routes = Route.objects.filter(
|
||||
createDT__gte=datetime.now() - timedelta(hours=1),
|
||||
receive_msg_by_email=True
|
||||
)
|
||||
|
||||
check_fields = [
|
||||
'type_transport', 'departure_DT', 'arrival_DT', 'from_address_point', 'to_address_point',
|
||||
'from_place', 'to_place', 'cargo_type', 'weight'
|
||||
]
|
||||
|
||||
if for_routes:
|
||||
msg = f'last hour create routes count = {for_routes.count()}'
|
||||
else:
|
||||
msg = f'last hour not create routes'
|
||||
print(msg)
|
||||
|
||||
for route in for_routes:
|
||||
kwargs = {}
|
||||
params = {}
|
||||
|
||||
for field_name in check_fields:
|
||||
field_val = getattr(route, field_name, None)
|
||||
if field_val:
|
||||
if type(field_val) == datetime:
|
||||
params.update({f"{field_name}": f'{field_val.strftime("%d.%m.%Y")} - {field_val.strftime("%d.%m.%Y")}'})
|
||||
kwargs.update({f"{field_name}__date": field_val.date()})
|
||||
elif field_name == 'weight':
|
||||
# print(field_name)
|
||||
params.update({f"{field_name}": field_val})
|
||||
if route.owner_type == 'mover':
|
||||
kwargs.update({f"{field_name}__lte": field_val})
|
||||
else:
|
||||
kwargs.update({f"{field_name}__gte": field_val})
|
||||
else:
|
||||
kwargs.update({field_name: field_val})
|
||||
params.update({field_name: field_val})
|
||||
|
||||
found_routes = Route.objects.exclude(
|
||||
id=route.id,
|
||||
).exclude(
|
||||
owner=route.owner
|
||||
).exclude(
|
||||
owner_type=route.owner_type
|
||||
).filter(
|
||||
**kwargs
|
||||
# ).count(
|
||||
)
|
||||
|
||||
if found_routes:
|
||||
msg = f'found routes for send messages = {found_routes.count()}'
|
||||
|
||||
data_Dict = get_Dict_for_send_msgs(params, found_routes[0].owner_type)
|
||||
msg = send_push_message_for_found_matches_routes(route, data_Dict)
|
||||
if msg:
|
||||
log += msg
|
||||
msg = send_mail_found_matches_routes(route, data_Dict)
|
||||
if msg:
|
||||
log += msg
|
||||
|
||||
except Exception as e:
|
||||
msg = f'<br>\n! search_matches Error = {str(e)}'
|
||||
print(msg)
|
||||
log += msg
|
||||
|
||||
mail_sets = get_mail_send_options()
|
||||
techSendMail(mail_sets, log, title='search_matches fail')
|
||||
|
||||
return log
|
||||
@@ -10,16 +10,51 @@ from BaseModels.mailSender import techSendMail
|
||||
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
|
||||
|
||||
|
||||
|
||||
|
||||
def route_search_results_View(request):
|
||||
|
||||
Dict = {}
|
||||
data = None
|
||||
|
||||
routes = get_routes_Dict()
|
||||
if routes:
|
||||
if request.GET:
|
||||
data = request.GET.dict()
|
||||
|
||||
routes_Dict = get_routes_Dict(data=data)
|
||||
if routes_Dict:
|
||||
Dict = {
|
||||
'routes': routes['routes']
|
||||
'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)})
|
||||
|
||||
title = _('Результат поиска маршрутов')
|
||||
if 'from_address_point_txt' in data:
|
||||
title = f'{title} из {data["from_address_point_txt"]}'
|
||||
if 'to_address_point_txt' in data:
|
||||
title = f'{title} в {data["to_address_point_txt"]}'
|
||||
|
||||
Dict.update({
|
||||
'page': {
|
||||
'title': title,
|
||||
'description': title,
|
||||
'keywords': title,
|
||||
}
|
||||
})
|
||||
|
||||
t = loader.get_template('pages/p_results_find_route.html')
|
||||
return HttpResponse(t.render(Dict, request))
|
||||
return get_inter_http_respose(t, Dict, request)
|
||||
# return HttpResponse(t.render(Dict, request))
|
||||
|
||||
0
SubscribesApp/__init__.py
Normal file
0
SubscribesApp/__init__.py
Normal file
93
SubscribesApp/admin.py
Normal file
93
SubscribesApp/admin.py
Normal file
@@ -0,0 +1,93 @@
|
||||
from sets.admin import *
|
||||
from .models import *
|
||||
from django.contrib import admin
|
||||
|
||||
class Admin_Subscribe(Admin_Trans_BaseModel):
|
||||
fieldsets = (
|
||||
(None, {
|
||||
'classes': ['wide'],
|
||||
'fields': ('name', 'enable',
|
||||
('price'),
|
||||
'options',
|
||||
'period_name', 'period',
|
||||
'order',
|
||||
'bg_color', 'text_color'
|
||||
)
|
||||
}),
|
||||
)
|
||||
|
||||
list_display = [
|
||||
'id',
|
||||
'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']
|
||||
filter_horizontal = ['options']
|
||||
|
||||
admin.site.register(Subscribe,Admin_Subscribe)
|
||||
|
||||
|
||||
class Admin_SubscribeOption(Admin_Trans_BaseModel):
|
||||
fieldsets = (
|
||||
(None, {
|
||||
'classes': ['wide'],
|
||||
'fields': ('name',
|
||||
'order',
|
||||
'enable'
|
||||
)
|
||||
}),
|
||||
)
|
||||
|
||||
list_display = [
|
||||
'id', 'enable',
|
||||
'name',
|
||||
'order', 'modifiedDT', 'createDT'
|
||||
]
|
||||
list_editable = ['enable']
|
||||
|
||||
list_display_links = ['id']
|
||||
|
||||
list_filter = ['modifiedDT', 'createDT']
|
||||
search_fields = ['name']
|
||||
|
||||
admin.site.register(SubscribeOption,Admin_SubscribeOption)
|
||||
|
||||
|
||||
class Admin_SubscribeForUser(Admin_Trans_BaseModel):
|
||||
fieldsets = (
|
||||
(None, {
|
||||
'classes': ['wide'],
|
||||
'fields': ('name',
|
||||
'user', 'subscribe',
|
||||
'last_paid_DT',
|
||||
'paid_period_from_DT', 'paid_period_to_DT',
|
||||
'auto_continue', 'receive_finish_subscribe_msg',
|
||||
'order'
|
||||
)
|
||||
}),
|
||||
)
|
||||
|
||||
list_display = [
|
||||
'id',
|
||||
'name', 'user', 'subscribe',
|
||||
'last_paid_DT', 'paid_period_from_DT', 'paid_period_to_DT',
|
||||
'auto_continue', 'receive_finish_subscribe_msg',
|
||||
'order', 'modifiedDT', 'createDT'
|
||||
]
|
||||
|
||||
list_display_links = ['id']
|
||||
|
||||
list_filter = [
|
||||
'subscribe', 'last_paid_DT', 'paid_period_from_DT', 'paid_period_to_DT',
|
||||
'auto_continue', 'receive_finish_subscribe_msg',
|
||||
'modifiedDT', 'createDT'
|
||||
]
|
||||
search_fields = ['name']
|
||||
|
||||
admin.site.register(SubscribeForUser,Admin_SubscribeForUser)
|
||||
6
SubscribesApp/apps.py
Normal file
6
SubscribesApp/apps.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class SubscribesappConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'SubscribesApp'
|
||||
57
SubscribesApp/funcs.py
Normal file
57
SubscribesApp/funcs.py
Normal file
@@ -0,0 +1,57 @@
|
||||
from .models import *
|
||||
from django.template.loader import render_to_string
|
||||
|
||||
def get_cur_user_subscribe(user):
|
||||
|
||||
user_subscribe = None
|
||||
try:
|
||||
user_subscribe = SubscribeForUser.objects.get(user=user)
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
return user_subscribe
|
||||
|
||||
|
||||
def get_subsribes_w_options():
|
||||
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)
|
||||
|
||||
return subscribes, all_options
|
||||
|
||||
|
||||
def get_profile_subscribe_page_content_html(request):
|
||||
|
||||
try:
|
||||
|
||||
# data = json.loads(request.body)
|
||||
# all_options = SubscribeOption.objects.filter(enable=True)
|
||||
subscribes, all_options = get_subsribes_w_options()
|
||||
|
||||
subscribe_for_user = SubscribeForUser.objects.filter(user=request.user)
|
||||
if not subscribe_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_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)
|
||||
|
||||
# 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)
|
||||
|
||||
Dict = {
|
||||
'subscribe_for_user': subscribe_for_user,
|
||||
'subscribes': subscribes
|
||||
}
|
||||
|
||||
html = render_to_string(tpl_name, Dict, request=request)
|
||||
return html
|
||||
|
||||
except Exception as e:
|
||||
msg = f'show_cur_subscribe_ajax Error = {str(e)}'
|
||||
return msg
|
||||
17
SubscribesApp/js_urls.py
Normal file
17
SubscribesApp/js_urls.py
Normal file
@@ -0,0 +1,17 @@
|
||||
# coding=utf-8
|
||||
from django.urls import path
|
||||
# from AuthApp.js_views import *
|
||||
# from AuthApp.import_funcs import *
|
||||
from .js_views import *
|
||||
from django.contrib.auth import views
|
||||
from RoutesApp.js_views import new_route_view_ajax
|
||||
|
||||
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('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'),
|
||||
# # path('update_chat/', update_chat_ajax2, name='update_chat_ajax'),
|
||||
# path('show_chat_w_user/', show_chat_w_user_ajax, name='show_chat_w_user_ajax'),
|
||||
]
|
||||
112
SubscribesApp/js_views.py
Normal file
112
SubscribesApp/js_views.py
Normal file
@@ -0,0 +1,112 @@
|
||||
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.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 django.template.loader import render_to_string
|
||||
from django.urls import reverse
|
||||
from .funcs import *
|
||||
import json
|
||||
from datetime import datetime, time, timedelta
|
||||
from channels.layers import get_channel_layer
|
||||
from asgiref.sync import async_to_sync
|
||||
|
||||
|
||||
|
||||
@login_required(login_url='/profile/login/')
|
||||
def subscribe_now_ajax(request):
|
||||
|
||||
if request.method != 'POST':
|
||||
raise Http404
|
||||
|
||||
try:
|
||||
|
||||
data = json.loads(request.body)
|
||||
|
||||
subscribe = Subscribe.objects.get(id=data['subscribe_id'])
|
||||
|
||||
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(user=request.user)
|
||||
if subscribe_for_user:
|
||||
subscribe_for_user.update(**kwargs)
|
||||
subscribe_for_user = subscribe_for_user[0]
|
||||
else:
|
||||
subscribe_for_user = SubscribeForUser.objects.create(**kwargs)
|
||||
|
||||
if not subscribe_for_user:
|
||||
tpl_name = 'blocks/profile/b_subscribe_variants.html'
|
||||
else:
|
||||
tpl_name = 'blocks/profile/b_subscribe_current.html'
|
||||
|
||||
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)
|
||||
|
||||
Dict = {
|
||||
'subscribe_for_user': subscribe_for_user,
|
||||
'subscribes': subscribes
|
||||
}
|
||||
|
||||
html = render_to_string(tpl_name, Dict, request=request)
|
||||
return JsonResponse({'html': html}, status=200)
|
||||
|
||||
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/')
|
||||
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)
|
||||
|
||||
# try:
|
||||
#
|
||||
# # data = json.loads(request.body)
|
||||
# all_options = SubscribeOption.objects.filter(enable=True)
|
||||
#
|
||||
# subscribe_for_user = SubscribeForUser.objects.filter(user=request.user)
|
||||
# if not subscribe_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_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)
|
||||
#
|
||||
# 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)
|
||||
#
|
||||
# Dict = {
|
||||
# 'subscribe_for_user': subscribe_for_user,
|
||||
# 'subscribes': subscribes
|
||||
# }
|
||||
#
|
||||
# html = render_to_string(tpl_name, Dict, request=request)
|
||||
# return JsonResponse({'html': html}, status=200)
|
||||
#
|
||||
# except Exception as e:
|
||||
# msg = f'show_cur_subscribe_ajax Error = {str(e)}'
|
||||
# return JsonResponse({'error': msg}, status=400)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user