mirror of
https://github.com/mailcow/mailcow-dockerized.git
synced 2026-06-13 01:50:34 +00:00
Compare commits
639 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dd50bbca9b | |||
| f3f5471ef7 | |||
| 516c8ea66c | |||
| 48310034e5 | |||
| be35a88f8c | |||
| e67b512499 | |||
| 0cf59159cd | |||
| e7a929a947 | |||
| dabf4d4383 | |||
| 13bdd4ad0b | |||
| 3281b97ea9 | |||
| 8070db96e9 | |||
| 82c80a9682 | |||
| 136cc2e3ff | |||
| eefce62f01 | |||
| 240b2c63f6 | |||
| 355da03fba | |||
| 55d57c552d | |||
| a56e5eb2fe | |||
| e7817fab78 | |||
| 714b8417f4 | |||
| ffb68c8848 | |||
| 7a5be0ccbf | |||
| c2927af554 | |||
| 24cea0cf22 | |||
| f4351c119f | |||
| f40b6b5b65 | |||
| bff96eb1ae | |||
| de9564c4c9 | |||
| 614aa1e49e | |||
| b368c299d9 | |||
| 01a61d4e62 | |||
| 174fcd7167 | |||
| dca85f2ffb | |||
| 8ad5acb020 | |||
| 287118c3a7 | |||
| 78621a1f50 | |||
| 116859e0ba | |||
| c4827e908c | |||
| 41d56a867a | |||
| 9f4dd1d172 | |||
| 948d23f56d | |||
| 50e9a3ec8a | |||
| 0dbd6be010 | |||
| 2b4189b1a4 | |||
| 4bf81975dc | |||
| ea040f4412 | |||
| c246648949 | |||
| 125aaa5b7d | |||
| aa7888c37d | |||
| f1e1232849 | |||
| bb7c7bcff6 | |||
| e5cf35aff8 | |||
| 65585e286d | |||
| 99bcfb8c4b | |||
| d98fd74968 | |||
| 7875185e1f | |||
| a8d50955ee | |||
| bfd5329363 | |||
| ea1eb48596 | |||
| f1bb23ba2a | |||
| 5160eff294 | |||
| 118984dfff | |||
| 87214fef70 | |||
| f1f9626b5b | |||
| 3a13c93022 | |||
| 83bd66db98 | |||
| 13175b4e6c | |||
| ecefbf2166 | |||
| a763dda068 | |||
| 698b2bf988 | |||
| a71cc759f6 | |||
| 802d304579 | |||
| faf8da1365 | |||
| ce546e8a90 | |||
| f4731eecdb | |||
| 6704377402 | |||
| 827cb00837 | |||
| 299a342a62 | |||
| 8614d63ace | |||
| 77f04d10c7 | |||
| 6d8c978d17 | |||
| d55994b66a | |||
| ff4f2ae0b6 | |||
| 0b00f15811 | |||
| bed5218550 | |||
| 86b67a9a7b | |||
| 73370de1f9 | |||
| 524aba0964 | |||
| 64528d8e0e | |||
| 31b5faa729 | |||
| 17977a2fff | |||
| 3e007eeaae | |||
| a96b209e1b | |||
| 05b897f43e | |||
| 738dcac60d | |||
| b3bbeee5e2 | |||
| 782eae4d4c | |||
| f2f5e212f5 | |||
| ff7102468e | |||
| 118cb1017a | |||
| 360bb6f306 | |||
| d8e314db1a | |||
| fd14c51f85 | |||
| 57a5a9baeb | |||
| 65c74c75c7 | |||
| e82f3b3975 | |||
| d7323213b8 | |||
| fbc33da734 | |||
| 210815d4cf | |||
| 1e672ae349 | |||
| 19fabd0e64 | |||
| ef392ef6ba | |||
| 046e658984 | |||
| a46db9e0df | |||
| 17f3cc3ad8 | |||
| 3236a10cf5 | |||
| a4eb6d5f1b | |||
| a09661fc83 | |||
| f52ab69a5b | |||
| 9d1b620dcf | |||
| 3ebd801b3d | |||
| 05181f1888 | |||
| 6875baf64c | |||
| 0cdb1e638d | |||
| da415e5c6b | |||
| c46a1c1e2f | |||
| b79a1530fb | |||
| a6a7ab45f8 | |||
| c8f69ffe77 | |||
| 79982e0e8d | |||
| bc937ed2db | |||
| 8ca028eb2e | |||
| df17e6b75e | |||
| f880e1834d | |||
| 4dd1b97e38 | |||
| 074e3fcd6e | |||
| aeb433cc39 | |||
| eb9d360c0a | |||
| abfad4e025 | |||
| 3f40fada1b | |||
| a9871d05b2 | |||
| 39e46d2e0b | |||
| e9091cbb8c | |||
| cb340d78e1 | |||
| 996b2db514 | |||
| 548d7b9833 | |||
| 96dbbf4db6 | |||
| 4f14462af7 | |||
| 1e08b4ece6 | |||
| 177ebe26de | |||
| 6fd9efc30a | |||
| da72184fda | |||
| 6f212a41d8 | |||
| 52314d1a35 | |||
| 3028a18a37 | |||
| a2b31cb28d | |||
| 26a5fcf989 | |||
| 509086ef54 | |||
| 963510ed22 | |||
| 2c0f8cda50 | |||
| 50d2671d75 | |||
| b73d879f3c | |||
| 725a5fe5b9 | |||
| 65ca42ca42 | |||
| b22ff59f7b | |||
| 58527857d9 | |||
| 6306c4555c | |||
| 922603f906 | |||
| f8d45de749 | |||
| b6760e19b7 | |||
| 6ce25f38e1 | |||
| 5cb7f726bc | |||
| a334f33b35 | |||
| cb1602c2de | |||
| b503271aba | |||
| 008e5651f8 | |||
| 5e3aab12a7 | |||
| 8026b6c874 | |||
| 51b80f6fa1 | |||
| 75fdeb2843 | |||
| 2b1d927de4 | |||
| e5d788497a | |||
| b173e2ef86 | |||
| 042676fff7 | |||
| 44d53146af | |||
| 3d48c2427a | |||
| a9046d8f35 | |||
| b4a1b81aec | |||
| 90eb0ea27a | |||
| 4f01b9fd25 | |||
| 174b5c8f7f | |||
| 3912fcb238 | |||
| ef70457a48 | |||
| 8c4dbaec4f | |||
| 645e8f426c | |||
| bae1d1c047 | |||
| ce4fb069d5 | |||
| 9444000d46 | |||
| eacd9ac240 | |||
| cf38d6ca69 | |||
| 905993d66e | |||
| b8656763ec | |||
| 0d7fe2e347 | |||
| 33bd871a63 | |||
| 772122b255 | |||
| 9fb346751c | |||
| 10e560c5b2 | |||
| cb058e91a3 | |||
| ba9f2bc376 | |||
| fb7e234120 | |||
| 27e7407407 | |||
| 623397d20a | |||
| 7d46de33d8 | |||
| 8c80cecdfb | |||
| 5470b51cc7 | |||
| 8e0b1d8aee | |||
| e53f431273 | |||
| 8e0ee67108 | |||
| 3d82d9af1b | |||
| 8a0bd23985 | |||
| 2834459b22 | |||
| 000894dabd | |||
| 494620cdea | |||
| a502eb239d | |||
| caf775093e | |||
| 4387e4764f | |||
| 3b8e17c21f | |||
| f28e18e676 | |||
| b4bab1d5b9 | |||
| c4d5072e5c | |||
| 852bf750ca | |||
| 47359c4113 | |||
| 15f2c4c769 | |||
| e74af0db89 | |||
| a0174c61e8 | |||
| 5b30dce609 | |||
| 8f6099e3e4 | |||
| 7c44375223 | |||
| 72e204f8fd | |||
| b5f5b53e37 | |||
| 1c15133a52 | |||
| 7c9c2c35f8 | |||
| 5ff62d8f22 | |||
| 9806e568c0 | |||
| b4bb4e2938 | |||
| 4427173a6c | |||
| db66fe33fa | |||
| de7b809229 | |||
| cf5fa96a93 | |||
| a40df1ff87 | |||
| a161aa2c92 | |||
| cad0f25345 | |||
| 2ed453a400 | |||
| 452d8a686f | |||
| 9e76b6ee70 | |||
| 45e97b3753 | |||
| ecc16c69e6 | |||
| 90f77f6d5c | |||
| 0c11cf747a | |||
| 6d36475ed3 | |||
| fee6ff43bf | |||
| 57cd5ec818 | |||
| 02512e0f4f | |||
| 555f4a8a6d | |||
| 3633766544 | |||
| e98a984417 | |||
| bc9141753f | |||
| 1f9f4157a6 | |||
| 778a3ed551 | |||
| 5ea4305185 | |||
| ef311f22bf | |||
| e202530afb | |||
| 85deeaf806 | |||
| 825c8a6abe | |||
| cdc8f63b4b | |||
| 9db9818ede | |||
| 4f7ee669d3 | |||
| 77f9947613 | |||
| a8eb3b6ac5 | |||
| 575eab1cf0 | |||
| 7a23e4fd4e | |||
| 77e6124b00 | |||
| b16b276f36 | |||
| a3ddb58566 | |||
| be7252f620 | |||
| 4f380debb5 | |||
| f34d3620b1 | |||
| 70e99447f9 | |||
| db8af3d1e0 | |||
| 7f70b0f703 | |||
| 2e10cc8e79 | |||
| 047d9143c0 | |||
| 047c4aa3a0 | |||
| 925b220905 | |||
| 6708059227 | |||
| 1f3d9d4e1c | |||
| 0dcfac8f15 | |||
| ad8b7f0894 | |||
| 55f810b23f | |||
| 65eddee63e | |||
| a7a0eef125 | |||
| 5d35af9d69 | |||
| ea21bca7df | |||
| a3c0737ba8 | |||
| 7b57b3392c | |||
| 492451bfee | |||
| 9747995510 | |||
| ad9112010f | |||
| a4ec2d1d86 | |||
| b7f07951f6 | |||
| 0e3363e61c | |||
| 4322c98f73 | |||
| edcf789126 | |||
| b985ba4f0e | |||
| 67c0405274 | |||
| 9b32151ab5 | |||
| a1e8077f45 | |||
| 956e4e2aa7 | |||
| b51a659515 | |||
| 44a6f09a09 | |||
| 4c10525078 | |||
| c9ab8b2eff | |||
| 4bf38bf00f | |||
| 7c7c67948e | |||
| 263cb96786 | |||
| b6e3e7a658 | |||
| ceaf1423f4 | |||
| c2e0a275e1 | |||
| c8620a066d | |||
| 9598b503ec | |||
| 1ca566f670 | |||
| 94f4ec8b96 | |||
| 7aab2c55ff | |||
| 6abb4d34c1 | |||
| c8ccf080f3 | |||
| 0342ae926c | |||
| be08742653 | |||
| 528f7da5ef | |||
| 7d72ae3449 | |||
| 753cde0b85 | |||
| 223ba44b61 | |||
| cd02483b19 | |||
| f724662874 | |||
| bee762737e | |||
| 83efd3e506 | |||
| 2278a6cc73 | |||
| 586b60b276 | |||
| f07b9ea304 | |||
| 09dca5d76c | |||
| 65bb808441 | |||
| 83b79edb42 | |||
| b8ec244d92 | |||
| 5b924614aa | |||
| 43103add47 | |||
| 124d5d6bb2 | |||
| 58fde558f7 | |||
| 8b314acfcf | |||
| 1c0eab9893 | |||
| 514079fe96 | |||
| c62daa0c59 | |||
| 1a05101f50 | |||
| 47fb46c837 | |||
| d29580aa02 | |||
| d0fc62ef13 | |||
| b14c0e4c11 | |||
| e26d5b8ba5 | |||
| 8987ebca36 | |||
| d3cd21956a | |||
| 43ec12f4f0 | |||
| 40cf2c85e6 | |||
| 6195b7c334 | |||
| b149da28c8 | |||
| e5cb2dd00e | |||
| c9b883dff5 | |||
| ad43253a90 | |||
| 979de67c2b | |||
| 8416caf798 | |||
| 80d9dfe420 | |||
| 385570c1e8 | |||
| d82cfc6c62 | |||
| 27e9210d52 | |||
| fdf52dcb17 | |||
| 1ff220ccf8 | |||
| 8a49b50f33 | |||
| 1b6e5b7116 | |||
| 536ab34955 | |||
| f7369f0611 | |||
| 14bc105d43 | |||
| 2efb4365bf | |||
| c1b86fc782 | |||
| 52e92cc0db | |||
| 3af2f636a5 | |||
| 6fb967cf79 | |||
| 0dab215e27 | |||
| 03c49ea1f8 | |||
| 6ec136e63f | |||
| bba5671eaf | |||
| 88d7593d89 | |||
| bd23b80d45 | |||
| f96e0c4071 | |||
| cbd8e40f14 | |||
| 2d2c033ba7 | |||
| 496c68d2af | |||
| c505943e8b | |||
| 2841c09c1f | |||
| 11700d7ecb | |||
| 18444bd284 | |||
| 9d3a89d362 | |||
| 33eb2c8801 | |||
| 2d0ab4a1b8 | |||
| 2fec7ccd58 | |||
| a835419168 | |||
| 052959f435 | |||
| 4ce16d1ea4 | |||
| c1c7167ace | |||
| 3d538d4f14 | |||
| 7969e7116d | |||
| 4f58f2caee | |||
| 263baa81c0 | |||
| 092890b6ab | |||
| db7d7ea288 | |||
| 452daf5d5e | |||
| d373164e13 | |||
| cd7715fa0e | |||
| af9c3a8565 | |||
| dd6b8c44a4 | |||
| 499273dbb7 | |||
| 6612b892b7 | |||
| 89cea31475 | |||
| 872fa07213 | |||
| 36e4ee7738 | |||
| a139eb9bce | |||
| 7166696aa2 | |||
| 537a7908f1 | |||
| 560df58bb4 | |||
| 5629d47cb6 | |||
| 3fe776ee69 | |||
| 37b4ff811d | |||
| 7384aab2f4 | |||
| 581be02e53 | |||
| 71db83efce | |||
| 7ae7f25580 | |||
| 4ce05d4d4d | |||
| fdb56de0a8 | |||
| df56d73cec | |||
| 4ba0e155f3 | |||
| 304655f7ff | |||
| 6210f06bc0 | |||
| 09ae37410e | |||
| 351c803623 | |||
| 6a027b70e7 | |||
| 5d14baa43a | |||
| 141b397c82 | |||
| fd853cfc6f | |||
| 63f718178e | |||
| cdd2adbc73 | |||
| 74baf20feb | |||
| 958112af6b | |||
| 08d0f9448e | |||
| 7bcc8bd3a2 | |||
| 0eb2545773 | |||
| 714511b0a8 | |||
| cb6a5d4069 | |||
| c9700773f4 | |||
| 2229f87d9b | |||
| d360503443 | |||
| 838182a8b4 | |||
| 967cfedbb3 | |||
| a36645a282 | |||
| 3368a70f88 | |||
| cd1715ba52 | |||
| 0bc2a16093 | |||
| a21b3cd606 | |||
| 1c479684fc | |||
| c9dbc7c7b7 | |||
| c41dc9d8c0 | |||
| 1db5841424 | |||
| e53b068902 | |||
| 2bd436dfd8 | |||
| d13be25f45 | |||
| 6efd9dc5f9 | |||
| f13530d8a1 | |||
| 1edd4012e4 | |||
| 4390c9855a | |||
| 4d53216c05 | |||
| 8a86fa491e | |||
| 040206859f | |||
| d06119a21d | |||
| c27ad97287 | |||
| b1658c0f83 | |||
| 3e6a241c69 | |||
| 05b8609073 | |||
| 552f09f48a | |||
| 97df5c3b9c | |||
| 8d9102aa08 | |||
| 160dceff3e | |||
| 33e5ad2b5c | |||
| 998cb642a9 | |||
| 07ac195fea | |||
| 7d5990bf0f | |||
| 4ec982163e | |||
| 3c9502f241 | |||
| 63cecb2fd8 | |||
| 3029a2d33d | |||
| fa0d2a959d | |||
| 0ece065cb0 | |||
| f79cac3292 | |||
| 7a20a9941e | |||
| 24cc960379 | |||
| 353df6413f | |||
| fb7e00c158 | |||
| a0567beee5 | |||
| b68eae16e5 | |||
| 9a812edee4 | |||
| 43d2a6e135 | |||
| 5839e22796 | |||
| ee844c81d2 | |||
| b6cb3b026c | |||
| df33ebb2a0 | |||
| d2a6838958 | |||
| 96b8054e6b | |||
| dfdd2dadb4 | |||
| d0528b7883 | |||
| f40e682800 | |||
| f4dc01d1ec | |||
| 187ddedf96 | |||
| 5613134fed | |||
| e454ed4e39 | |||
| 1e2125653e | |||
| 835a726d2a | |||
| 0539cc6d8c | |||
| 549ff7d100 | |||
| 456b528785 | |||
| 003a6342a5 | |||
| fb10764167 | |||
| 9e1554f5c7 | |||
| 42c82be8f5 | |||
| 76ec0e888b | |||
| 892c99fa23 | |||
| 28da482ef2 | |||
| 936f07336c | |||
| 224a59ab4b | |||
| 96c8e01a3b | |||
| 88bd7bff1e | |||
| 7075b9f0c0 | |||
| b19666f7e0 | |||
| e663f3db72 | |||
| fd1ffdba80 | |||
| a12538b3a8 | |||
| cdff1ba37b | |||
| f6a51f6b6f | |||
| 6c5ab7800e | |||
| 7e26a2ab98 | |||
| 4e6c398c8c | |||
| d4e829465b | |||
| 1ade37312e | |||
| 372e381a85 | |||
| 374cc64601 | |||
| 1cf25572a3 | |||
| ba45f70a30 | |||
| 5e56566de6 | |||
| a2ccf7ef03 | |||
| 654dbf8198 | |||
| 53a5254897 | |||
| 45dd0611d9 | |||
| e62069d3db | |||
| 5088636d5f | |||
| 003d70990e | |||
| c433daf024 | |||
| 051d08b499 | |||
| b980e7af29 | |||
| 4d0799dead | |||
| d3dca1ddc2 | |||
| 9b8039440c | |||
| eea5c9df2f | |||
| aa9aff800c | |||
| 0b3b5e230b | |||
| db0d91beb1 | |||
| 4758033445 | |||
| 1e48fb8cda | |||
| 1d8da117d6 | |||
| 635fa795d2 | |||
| c1792df819 | |||
| 36944f8073 | |||
| 4d59cb0351 | |||
| fd7269d455 | |||
| b375e6a250 | |||
| 48589d20e2 | |||
| be9cbcf5ac | |||
| b04faddac4 | |||
| e925187dda | |||
| 06f380a17a | |||
| 67882414e1 | |||
| 2b149fb8ea | |||
| 3166bd5df5 | |||
| e911452d0c | |||
| deac5ad2fe | |||
| f097267bcd | |||
| 161130c116 | |||
| a03b8f28ae | |||
| 6d3798ad08 | |||
| 70921b8d15 | |||
| b185f83fc3 | |||
| bb9ae02ccc | |||
| 880a68d563 | |||
| d52323df2d | |||
| 769e08843b | |||
| 60af295c0a | |||
| e7fe52a625 | |||
| 49c506eed9 | |||
| 21fadf6df2 | |||
| 5fcccbc97d | |||
| 3ef2b6cfa2 | |||
| 84b4269c75 | |||
| 7692685122 | |||
| b820096656 | |||
| a0c09af67e | |||
| a2d57d43d1 | |||
| eddaf7a975 | |||
| bdd8b4a5ab | |||
| 98bc947d00 | |||
| 24275ffdbf | |||
| 5541f84c3c | |||
| 4907f702c8 | |||
| 412e1188b0 | |||
| 6d6b673cf2 | |||
| a1ffaae3d5 | |||
| f3f6fb8908 | |||
| a1a96bfabb | |||
| c520f21d28 | |||
| b1314bd9a3 | |||
| 6521ccd425 | |||
| df33f1a130 | |||
| 4c6a2055c2 | |||
| f09a3df870 | |||
| ea1a412749 | |||
| db82327d9a | |||
| ea1a02bd7d |
-120
@@ -1,120 +0,0 @@
|
|||||||
---
|
|
||||||
kind: pipeline
|
|
||||||
name: integration-testing
|
|
||||||
|
|
||||||
platform:
|
|
||||||
os: linux
|
|
||||||
arch: amd64
|
|
||||||
|
|
||||||
clone:
|
|
||||||
disable: true
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: prepare-tests
|
|
||||||
pull: default
|
|
||||||
image: timovibritannia/ansible
|
|
||||||
commands:
|
|
||||||
- git clone https://github.com/mailcow/mailcow-integration-tests.git --branch $(curl -sL https://api.github.com/repos/mailcow/mailcow-integration-tests/releases/latest | jq -r '.tag_name') --single-branch .
|
|
||||||
- chmod +x ci.sh
|
|
||||||
- chmod +x ci-ssh.sh
|
|
||||||
- chmod +x ci-piprequierments.sh
|
|
||||||
- ./ci.sh
|
|
||||||
- wget -O group_vars/all/secrets.yml $SECRETS_DOWNLOAD_URL --quiet
|
|
||||||
environment:
|
|
||||||
SECRETS_DOWNLOAD_URL:
|
|
||||||
from_secret: SECRETS_DOWNLOAD_URL
|
|
||||||
VAULT_PW:
|
|
||||||
from_secret: VAULT_PW
|
|
||||||
when:
|
|
||||||
branch:
|
|
||||||
- master
|
|
||||||
- staging
|
|
||||||
event:
|
|
||||||
- push
|
|
||||||
|
|
||||||
- name: lint
|
|
||||||
pull: default
|
|
||||||
image: timovibritannia/ansible
|
|
||||||
commands:
|
|
||||||
- ansible-lint ./
|
|
||||||
when:
|
|
||||||
branch:
|
|
||||||
- master
|
|
||||||
- staging
|
|
||||||
event:
|
|
||||||
- push
|
|
||||||
|
|
||||||
- name: create-server
|
|
||||||
pull: default
|
|
||||||
image: timovibritannia/ansible
|
|
||||||
commands:
|
|
||||||
- ./ci-piprequierments.sh
|
|
||||||
- ansible-playbook mailcow-start-server.yml --diff
|
|
||||||
- ./ci-ssh.sh
|
|
||||||
environment:
|
|
||||||
ANSIBLE_HOST_KEY_CHECKING: false
|
|
||||||
ANSIBLE_FORCE_COLOR: true
|
|
||||||
when:
|
|
||||||
branch:
|
|
||||||
- master
|
|
||||||
- staging
|
|
||||||
event:
|
|
||||||
- push
|
|
||||||
|
|
||||||
- name: setup-server
|
|
||||||
pull: default
|
|
||||||
image: timovibritannia/ansible
|
|
||||||
commands:
|
|
||||||
- sleep 120
|
|
||||||
- ./ci-piprequierments.sh
|
|
||||||
- ansible-playbook mailcow-setup-server.yml --private-key /drone/src/id_ssh_rsa --diff
|
|
||||||
environment:
|
|
||||||
ANSIBLE_HOST_KEY_CHECKING: false
|
|
||||||
ANSIBLE_FORCE_COLOR: true
|
|
||||||
when:
|
|
||||||
branch:
|
|
||||||
- master
|
|
||||||
- staging
|
|
||||||
event:
|
|
||||||
- push
|
|
||||||
|
|
||||||
- name: run-tests
|
|
||||||
pull: default
|
|
||||||
image: timovibritannia/ansible
|
|
||||||
commands:
|
|
||||||
- ./ci-piprequierments.sh
|
|
||||||
- ansible-playbook mailcow-integration-tests.yml --private-key /drone/src/id_ssh_rsa --diff
|
|
||||||
environment:
|
|
||||||
ANSIBLE_HOST_KEY_CHECKING: false
|
|
||||||
ANSIBLE_FORCE_COLOR: true
|
|
||||||
when:
|
|
||||||
branch:
|
|
||||||
- master
|
|
||||||
- staging
|
|
||||||
event:
|
|
||||||
- push
|
|
||||||
|
|
||||||
- name: delete-server
|
|
||||||
pull: default
|
|
||||||
image: timovibritannia/ansible
|
|
||||||
commands:
|
|
||||||
- ./ci-piprequierments.sh
|
|
||||||
- ansible-playbook mailcow-delete-server.yml --diff
|
|
||||||
environment:
|
|
||||||
ANSIBLE_HOST_KEY_CHECKING: false
|
|
||||||
ANSIBLE_FORCE_COLOR: true
|
|
||||||
when:
|
|
||||||
branch:
|
|
||||||
- master
|
|
||||||
- staging
|
|
||||||
event:
|
|
||||||
- push
|
|
||||||
status:
|
|
||||||
- failure
|
|
||||||
- success
|
|
||||||
|
|
||||||
---
|
|
||||||
kind: signature
|
|
||||||
hmac: f6619243fe2a27563291c9f2a46d93ffbc3b6dced9a05f23e64b555ce03a31e5
|
|
||||||
|
|
||||||
...
|
|
||||||
+1
-1
@@ -1 +1 @@
|
|||||||
custom: https://mailcow.github.io/mailcow-dockerized-docs/#help-mailcow
|
custom: ["https://www.servercow.de/mailcow?lang=en#sal"]
|
||||||
|
|||||||
@@ -1,60 +0,0 @@
|
|||||||
---
|
|
||||||
name: 🐞 Bug Report
|
|
||||||
about: Report a reproducible bug for mailcow. (NOT to be used for support questions.)
|
|
||||||
labels: bug
|
|
||||||
---
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Please DO NOT delete this template or use it for support questions.
|
|
||||||
You are welcome to visit us on our community channels listed at https://mailcow.github.io/mailcow-dockerized-docs/#community-support
|
|
||||||
For official support, please check https://mailcow.github.io/mailcow-dockerized-docs/#commercial-support
|
|
||||||
-->
|
|
||||||
|
|
||||||
**Prior to placing the issue, please check following:** *(fill out each checkbox with an `X` once done)*
|
|
||||||
- [ ] I understand that not following or deleting the below instructions will result in immediate closure and/or deletion of my issue.
|
|
||||||
- [ ] I have understood that this bug report is dedicated for bugs, and not for support-related inquiries.
|
|
||||||
- [ ] I have understood that answers are voluntary and community-driven, and not commercial support.
|
|
||||||
- [ ] I have verified that my issue has not been already answered in the past. I also checked previous [issues](https://github.com/mailcow/mailcow-dockerized/issues).
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
<!--
|
|
||||||
This should be a clear and concise description of what the bug is. What EXACTLY does happen?
|
|
||||||
If applicable, add screenshots to help explain your problem. Very useful for bugs in mailcow UI.
|
|
||||||
Write your detailed description below.
|
|
||||||
|
|
||||||
Also mention on which commit/date your mailcow instance was last updated.
|
|
||||||
-->
|
|
||||||
|
|
||||||
## Logs
|
|
||||||
<!--
|
|
||||||
Please take a look at the [official documentation](https://mailcow.github.io/mailcow-dockerized-docs/debug-logs/) and post the last
|
|
||||||
few lines of logs, when the error occurs. For example, docker container logs of affected containers.
|
|
||||||
-->
|
|
||||||
|
|
||||||
## Reproduction
|
|
||||||
<!--
|
|
||||||
It is really helpful to know how exactly you are able to reproduce the reported issue.
|
|
||||||
Have you tried to fix the issue? What did you try?
|
|
||||||
What are the exact steps to get the above described behavior?
|
|
||||||
Screenshots can be added, if helpful. Add the text below.
|
|
||||||
-->
|
|
||||||
|
|
||||||
## System information
|
|
||||||
<!--
|
|
||||||
In this stage we would kindly ask you to attach general system information about your setup.
|
|
||||||
Please carefully read the questions and instructions below.
|
|
||||||
-->
|
|
||||||
|
|
||||||
| Question | Answer |
|
|
||||||
| --- | --- |
|
|
||||||
| My operating system | I_DO_REPLY_HERE |
|
|
||||||
| Is Apparmor, SELinux or similar active? | I_DO_REPLY_HERE |
|
|
||||||
| Virtualization technlogy (KVM, VMware, Xen, etc - **LXC and OpenVZ are not supported** | I_DO_REPLY_HERE |
|
|
||||||
| Server/VM specifications (Memory, CPU Cores) | I_DO_REPLY_HERE |
|
|
||||||
| Docker Version (`docker version`) | I_DO_REPLY_HERE |
|
|
||||||
| Docker-Compose Version (`docker-compose version`) | I_DO_REPLY_HERE |
|
|
||||||
| Reverse proxy (custom solution) | I_DO_REPLY_HERE |
|
|
||||||
|
|
||||||
- Output of `git diff origin/master`, any other changes to the code? If so, **please post them**.
|
|
||||||
- All third-party firewalls and custom iptables rules are unsupported. *Please check the Docker docs about how to use Docker with your own ruleset*. Nevertheless, iptabels output can help us to help you: `iptables -L -vn`, `ip6tables -L -vn`, `iptables -L -vn -t nat` and `ip6tables -L -vn -t nat`.
|
|
||||||
- DNS problems? Please run `docker exec -it $(docker ps -qf name=acme-mailcow) dig +short stackoverflow.com @172.22.1.254` (set the IP accordingly, if you changed the internal mailcow network) and post the output.
|
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
name: 🐞 Bug Report
|
||||||
|
description: Report a reproducible bug for mailcow. (NOT to be used for support questions.)
|
||||||
|
labels: ["bug"]
|
||||||
|
body:
|
||||||
|
- type: checkboxes
|
||||||
|
attributes:
|
||||||
|
label: Contribution guidelines
|
||||||
|
description: Please read the contribution guidelines before proceeding.
|
||||||
|
options:
|
||||||
|
- label: I've read the [contribution guidelines](https://github.com/mailcow/mailcow-dockerized/blob/master/CONTRIBUTING.md) and wholeheartedly agree
|
||||||
|
required: true
|
||||||
|
- type: checkboxes
|
||||||
|
attributes:
|
||||||
|
label: I've found a bug and checked that ...
|
||||||
|
description: Prior to placing the issue, please check following:** *(fill out each checkbox with an `X` once done)*
|
||||||
|
options:
|
||||||
|
- label: ... I understand that not following the below instructions will result in immediate closure and/or deletion of my issue.
|
||||||
|
required: true
|
||||||
|
- label: ... I have understood that this bug report is dedicated for bugs, and not for support-related inquiries.
|
||||||
|
required: true
|
||||||
|
- label: ... I have understood that answers are voluntary and community-driven, and not commercial support.
|
||||||
|
required: true
|
||||||
|
- label: ... I have verified that my issue has not been already answered in the past. I also checked previous [issues](https://github.com/mailcow/mailcow-dockerized/issues).
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Description
|
||||||
|
description: Please provide a brief description of the bug in 1-2 sentences. If applicable, add screenshots to help explain your problem. Very useful for bugs in mailcow UI.
|
||||||
|
render: plain text
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: "Logs:"
|
||||||
|
description: "Please take a look at the [official documentation](https://docs.mailcow.email/troubleshooting/debug-logs/) and post the last few lines of logs, when the error occurs. For example, docker container logs of affected containers. This will be automatically formatted into code, so no need for backticks."
|
||||||
|
render: plain text
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: "Steps to reproduce:"
|
||||||
|
description: "Please describe the steps to reproduce the bug. Screenshots can be added, if helpful."
|
||||||
|
render: plain text
|
||||||
|
placeholder: |-
|
||||||
|
1. ...
|
||||||
|
2. ...
|
||||||
|
3. ...
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
## System information
|
||||||
|
### In this stage we would kindly ask you to attach general system information about your setup.
|
||||||
|
- type: dropdown
|
||||||
|
attributes:
|
||||||
|
label: "Which branch are you using?"
|
||||||
|
description: "#### `git rev-parse --abbrev-ref HEAD`"
|
||||||
|
multiple: false
|
||||||
|
options:
|
||||||
|
- master
|
||||||
|
- nightly
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
attributes:
|
||||||
|
label: "Operating System:"
|
||||||
|
placeholder: "e.g. Ubuntu 22.04 LTS"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
attributes:
|
||||||
|
label: "Server/VM specifications:"
|
||||||
|
placeholder: "Memory, CPU Cores"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
attributes:
|
||||||
|
label: "Is Apparmor, SELinux or similar active?"
|
||||||
|
placeholder: "yes/no"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
attributes:
|
||||||
|
label: "Virtualization technology:"
|
||||||
|
placeholder: "KVM, VMware, Xen, etc - **LXC and OpenVZ are not supported**"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
attributes:
|
||||||
|
label: "Docker version:"
|
||||||
|
description: "#### `docker version`"
|
||||||
|
placeholder: "20.10.21"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
attributes:
|
||||||
|
label: "docker-compose version or docker compose version:"
|
||||||
|
description: "#### `docker-compose version` or `docker compose version`"
|
||||||
|
placeholder: "v2.12.2"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
attributes:
|
||||||
|
label: "mailcow version:"
|
||||||
|
description: "#### ```git describe --tags `git rev-list --tags --max-count=1` ```"
|
||||||
|
placeholder: "2022-08"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
attributes:
|
||||||
|
label: "Reverse proxy:"
|
||||||
|
placeholder: "e.g. Nginx/Traefik"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: "Logs of git diff:"
|
||||||
|
description: "#### Output of `git diff origin/master`, any other changes to the code? If so, **please post them**:"
|
||||||
|
render: plain text
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: "Logs of iptables -L -vn:"
|
||||||
|
description: "#### Output of `iptables -L -vn`"
|
||||||
|
render: plain text
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: "Logs of ip6tables -L -vn:"
|
||||||
|
description: "#### Output of `ip6tables -L -vn`"
|
||||||
|
render: plain text
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: "Logs of iptables -L -vn -t nat:"
|
||||||
|
description: "#### Output of `iptables -L -vn -t nat`"
|
||||||
|
render: plain text
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: "Logs of ip6tables -L -vn -t nat:"
|
||||||
|
description: "#### Output of `ip6tables -L -vn -t nat`"
|
||||||
|
render: plain text
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: "DNS check:"
|
||||||
|
description: "#### Output of `docker exec -it $(docker ps -qf name=acme-mailcow) dig +short stackoverflow.com @172.22.1.254` (set the IP accordingly, if you changed the internal mailcow network)"
|
||||||
|
render: plain text
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
---
|
|
||||||
name: 💡 Feature Request
|
|
||||||
about: Suggest an idea for mailcow.
|
|
||||||
labels: enhancement
|
|
||||||
---
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Please note that the mailcow team and its contributors do have finite
|
|
||||||
resources and that we can not work on all filed feature requests.
|
|
||||||
|
|
||||||
However making us aware about certain ideas can help us improving
|
|
||||||
mailcow together.
|
|
||||||
|
|
||||||
We're also happy to help you getting a specific feature implemented.
|
|
||||||
-->
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
A clear and concise description of what the problem is.
|
|
||||||
For example: I'm always frustrated when [...]
|
|
||||||
|
|
||||||
## Motivation
|
|
||||||
|
|
||||||
What are you about to solve or improve with this idea?
|
|
||||||
What would be the benefit for most users?
|
|
||||||
|
|
||||||
## Additional context
|
|
||||||
|
|
||||||
Add any other context or screenshots about the feature request.
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
name: 💡 Feature Request
|
||||||
|
description: Suggest an idea for mailcow.
|
||||||
|
labels: ["enhancement"]
|
||||||
|
body:
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Summary
|
||||||
|
description: Please describe your idea in a reasonable amount of detail.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Motivation
|
||||||
|
description: Please describe how your idea would benefit you and other users.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Additional context
|
||||||
|
description: Add any other context or screenshots about the feature request.
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
## :memo: Brief description
|
||||||
|
<!-- Diff summary - START -->
|
||||||
|
<!-- Diff summary - END -->
|
||||||
|
|
||||||
|
|
||||||
|
## :computer: Commits
|
||||||
|
<!-- Diff commits - START -->
|
||||||
|
<!-- Diff commits - END -->
|
||||||
|
|
||||||
|
|
||||||
|
## :file_folder: Modified files
|
||||||
|
<!-- Diff files - START -->
|
||||||
|
<!-- Diff files - END -->
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"enabled": true,
|
||||||
|
"timezone": "Europe/Berlin",
|
||||||
|
"dependencyDashboard": false,
|
||||||
|
"dependencyDashboardTitle": "Renovate Dashboard",
|
||||||
|
"commitBody": "Signed-off-by: milkmaker <milkmaker@mailcow.de>",
|
||||||
|
"rebaseWhen": "auto",
|
||||||
|
"assignees": [
|
||||||
|
"@magiccc"
|
||||||
|
],
|
||||||
|
"baseBranches": ["staging"],
|
||||||
|
"enabledManagers": ["github-actions"]
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 71 KiB |
@@ -0,0 +1,33 @@
|
|||||||
|
name: Check PRs if on staging
|
||||||
|
on:
|
||||||
|
pull_request_target:
|
||||||
|
types: [opened, edited]
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
is_not_staging:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event.pull_request.base.ref != 'staging' #check if the target branch is not staging
|
||||||
|
steps:
|
||||||
|
- name: Send message
|
||||||
|
uses: thollander/actions-comment-pull-request@main
|
||||||
|
with:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.CHECKIFPRISSTAGING_ACTION_PAT }}
|
||||||
|
message: |
|
||||||
|
Thanks for contributing!
|
||||||
|
|
||||||
|
I noticed that you didn't select `staging` as your base branch. Please change the base branch to `staging`.
|
||||||
|
See the attached picture on how to change the base branch to `staging`:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- name: Fail #we want to see failed checks in the PR
|
||||||
|
if: ${{ success() }} #set exit code to 1 even if commenting somehow failed
|
||||||
|
run: exit 1
|
||||||
|
|
||||||
|
is_staging:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event.pull_request.base.ref == 'staging' #check if the target branch is staging
|
||||||
|
steps:
|
||||||
|
- name: Success
|
||||||
|
run: exit 0
|
||||||
@@ -14,7 +14,7 @@ jobs:
|
|||||||
pull-requests: write
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- name: Mark/Close Stale Issues and Pull Requests 🗑️
|
- name: Mark/Close Stale Issues and Pull Requests 🗑️
|
||||||
uses: actions/stale@v4
|
uses: actions/stale@v6.0.1
|
||||||
with:
|
with:
|
||||||
repo-token: ${{ secrets.STALE_ACTION_PAT }}
|
repo-token: ${{ secrets.STALE_ACTION_PAT }}
|
||||||
days-before-stale: 60
|
days-before-stale: 60
|
||||||
@@ -30,6 +30,7 @@ jobs:
|
|||||||
stale-issue-label: "stale"
|
stale-issue-label: "stale"
|
||||||
stale-pr-label: "stale"
|
stale-pr-label: "stale"
|
||||||
exempt-draft-pr: "true"
|
exempt-draft-pr: "true"
|
||||||
|
close-issue-reason: "not_planned"
|
||||||
operations-per-run: "250"
|
operations-per-run: "250"
|
||||||
ascending: "true"
|
ascending: "true"
|
||||||
#DRY-RUN
|
#DRY-RUN
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
name: Build mailcow Docker Images
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "master", "staging" ]
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read # to fetch code (actions/checkout)
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
docker_image_builds:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
images:
|
||||||
|
- "acme-mailcow"
|
||||||
|
- "clamd-mailcow"
|
||||||
|
- "dockerapi-mailcow"
|
||||||
|
- "dovecot-mailcow"
|
||||||
|
- "netfilter-mailcow"
|
||||||
|
- "olefy-mailcow"
|
||||||
|
- "php-fpm-mailcow"
|
||||||
|
- "postfix-mailcow"
|
||||||
|
- "rspamd-mailcow"
|
||||||
|
- "sogo-mailcow"
|
||||||
|
- "solr-mailcow"
|
||||||
|
- "unbound-mailcow"
|
||||||
|
- "watchdog-mailcow"
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Setup Docker
|
||||||
|
run: |
|
||||||
|
curl -sSL https://get.docker.com/ | CHANNEL=stable sudo sh
|
||||||
|
sudo service docker start
|
||||||
|
- name: Prepair Image Builds
|
||||||
|
run: |
|
||||||
|
cp helper-scripts/docker-compose.override.yml.d/BUILD_FLAGS/docker-compose.override.yml docker-compose.override.yml
|
||||||
|
- name: Build Docker Images
|
||||||
|
run: |
|
||||||
|
docker compose build ${image}
|
||||||
|
env:
|
||||||
|
image: ${{ matrix.images }}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
name: mailcow Integration Tests
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "master", "staging" ]
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
integration_tests:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Setup Ansible
|
||||||
|
run: |
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install python3 python3-pip git
|
||||||
|
sudo pip3 install ansible
|
||||||
|
- name: Prepair Test Environment
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/mailcow/mailcow-integration-tests.git --branch $(curl -sL https://api.github.com/repos/mailcow/mailcow-integration-tests/releases/latest | jq -r '.tag_name') --single-branch .
|
||||||
|
./fork_check.sh
|
||||||
|
./ci.sh
|
||||||
|
./ci-pip-requirements.sh
|
||||||
|
env:
|
||||||
|
VAULT_PW: ${{ secrets.MAILCOW_TESTS_VAULT_PW }}
|
||||||
|
VAULT_FILE: ${{ secrets.MAILCOW_TESTS_VAULT_FILE }}
|
||||||
|
- name: Start Integration Test Server
|
||||||
|
run: |
|
||||||
|
./fork_check.sh
|
||||||
|
ansible-playbook mailcow-start-server.yml --diff
|
||||||
|
env:
|
||||||
|
PY_COLORS: '1'
|
||||||
|
ANSIBLE_FORCE_COLOR: '1'
|
||||||
|
ANSIBLE_HOST_KEY_CHECKING: 'false'
|
||||||
|
- name: Setup Integration Test Server
|
||||||
|
run: |
|
||||||
|
./fork_check.sh
|
||||||
|
sleep 30
|
||||||
|
ansible-playbook mailcow-setup-server.yml --private-key id_ssh_rsa --diff
|
||||||
|
env:
|
||||||
|
PY_COLORS: '1'
|
||||||
|
ANSIBLE_FORCE_COLOR: '1'
|
||||||
|
ANSIBLE_HOST_KEY_CHECKING: 'false'
|
||||||
|
- name: Run Integration Tests
|
||||||
|
run: |
|
||||||
|
./fork_check.sh
|
||||||
|
ansible-playbook mailcow-integration-tests.yml --private-key id_ssh_rsa --diff
|
||||||
|
env:
|
||||||
|
PY_COLORS: '1'
|
||||||
|
ANSIBLE_FORCE_COLOR: '1'
|
||||||
|
ANSIBLE_HOST_KEY_CHECKING: 'false'
|
||||||
|
- name: Delete Integration Test Server
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
./fork_check.sh
|
||||||
|
ansible-playbook mailcow-delete-server.yml --diff
|
||||||
|
env:
|
||||||
|
PY_COLORS: '1'
|
||||||
|
ANSIBLE_FORCE_COLOR: '1'
|
||||||
|
ANSIBLE_HOST_KEY_CHECKING: 'false'
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
name: Create PR to merge to nightly from staging
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- staging
|
||||||
|
jobs:
|
||||||
|
action-pull-request:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Run the Action
|
||||||
|
uses: devops-infra/action-pull-request@v0.5.3
|
||||||
|
with:
|
||||||
|
github_token: ${{ secrets.PRTONIGHTLY_ACTION_PAT }}
|
||||||
|
title: Automatic PR to nightly from ${{ github.event.repository.updated_at}}
|
||||||
|
assignee: DerLinkman
|
||||||
|
source_branch: staging
|
||||||
|
target_branch: nightly
|
||||||
|
reviewer: DerLinkman
|
||||||
|
label: upstream
|
||||||
|
template: .github/ISSUE_TEMPLATE/pr_to_nighty_template.yml
|
||||||
|
get_diff: true
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
name: Build mailcow backup image
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
# At 00:00 on Sunday
|
||||||
|
- cron: "0 0 * * 0"
|
||||||
|
workflow_dispatch: # Allow to run workflow manually
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
docker_image_build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v2
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v2
|
||||||
|
|
||||||
|
- name: Login to Docker Hub
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.BACKUPIMAGEBUILD_ACTION_DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.BACKUPIMAGEBUILD_ACTION_DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Build and push
|
||||||
|
uses: docker/build-push-action@v3
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: data/Dockerfiles/backup/Dockerfile
|
||||||
|
push: true
|
||||||
|
tags: mailcow/backup:latest
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
name: "Tweet trigger release"
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
tweet:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: "Get Release Tag"
|
||||||
|
run: |
|
||||||
|
RELEASE_TAG=$(curl https://api.github.com/repos/mailcow/mailcow-dockerized/releases/latest | jq -r '.tag_name')
|
||||||
|
- name: Tweet-trigger-publish-release
|
||||||
|
uses: mugi111/tweet-trigger-release@v1.1
|
||||||
|
with:
|
||||||
|
consumer_key: ${{ secrets.CONSUMER_KEY }}
|
||||||
|
consumer_secret: ${{ secrets.CONSUMER_SECRET }}
|
||||||
|
access_token_key: ${{ secrets.ACCESS_TOKEN_KEY }}
|
||||||
|
access_token_secret: ${{ secrets.ACCESS_TOKEN_SECRET }}
|
||||||
|
tweet_body: 'A new mailcow update has just been released! Checkout the GitHub Page for changelog and more informations: https://github.com/mailcow/mailcow-dockerized/releases/latest'
|
||||||
-16
@@ -1,16 +0,0 @@
|
|||||||
sudo: required
|
|
||||||
services:
|
|
||||||
- docker
|
|
||||||
script:
|
|
||||||
- echo 'Europe/Berlin' | MAILCOW_HOSTNAME=build.mailcow ./generate_config.sh
|
|
||||||
- docker-compose pull --ignore-pull-failures --parallel
|
|
||||||
- docker-compose build
|
|
||||||
- docker login --username=$DOCKER_HUB_USERNAME --password=$DOCKER_HUB_PASSWORD
|
|
||||||
- docker-compose push
|
|
||||||
branches:
|
|
||||||
only:
|
|
||||||
- master_disabled
|
|
||||||
env:
|
|
||||||
global:
|
|
||||||
- secure: MpxpTwD7f0CNEVLitSpVmocK7O9r+BwFE1deEHK4AlQo/oc9cOlhGe1EL3mx9zbglPmjlDg/8kMUGv6vSirIabfBo9Szjps76bHckFr9lr2Ykkg0e29oC8pgPpSXD1eY/1ZIN/FvIkxpUFLETo1okS/j9q/A0DCGFmti0n3EoMORsgRz9CpNAiEh0zpSd6+euPAGHuczuCrDuO84my9bIOCjA/+aPunHNeXiuM8yIM2SxCSyGtIKT0+jvquIvLF58VxivysXBlRfhDn8fhB09nXA2Ru/derYQACfcmNSn9Pd4bDpebPJW5B9H/XA8xjb58uKinUlncbAMB/QnxoT75j9YRWJZRSQ+34XNYP6ZgK9soZ2TC6djQyEKTUu45Kp/1s+poSn42m9jytJJTmmK0KxsZTRcC8JD5nrjIMZWPUNNTwC5L4+I7ZRWg2WooK3LNyq1Ng8Hn6W77wSgsvAJw2HD3Lx58AprGUhHuBeaIZRuSN9aKwZrl9vKQJLqPnOp/nF2EC6kot5HYYtcotGtETXPUDih21gWD5ZM2BqVqYfQQnJnNMgeYmMdj6QQuTFqhuNJf7hXRIRkTnD3j1gDOLKQZazW0+N2JE8XWDFwi6fKScDsxT85lJti9HmzHa7+k4RVHmUYuDgRoPuzUgjWHvPsiz3/Z8WQ9JYpH84S8w=
|
|
||||||
- secure: fWzZisT6nGDNL4lf6tXB07eFG2drgBakHxzdF/NFVvzuP861RFR6omuL+ED0PgXrEHDJBxaBLv52je8irmUXrAH1CNr7T8DWiZo/h5h609Uzr+38T1NnIu4krL0Wo6/CDwlLKnzqTq9yBIZLQSHVJmo8AOpo1JPIi2ajodqj9ZfmAxDQTQl+G6zvQjtqIkYHsHY7A44Rto0f14ykn7w2S82Jn6Ry89VNI5V1WEO3sMpM/XekNP/HokNcRIuntL/0+kuLvTJ5akGoTjBQxSnSW95opzPeGky74HRU2obExJYqKvF0VfVJRNAqejwjIiFIbbjqV0Sk5391kFuhuBErQQDM1bOHGdxZ41HsJH29qNWIl7C33Yl10qERoqecgsJ1N/bS2ZEmWqm/zQh5GClCXPvYmzEqMYsMGM3vjbKdjDlc1Wh2w/eFclsXN9LSXh1mc35rtj46frcT6e5Kof87AIfC9hTgDvk9kAsyjaHMkSHSZthbZXCIcsD8qriNm5UqfFBYD79mPIP1S2YMQ2jscCsjHOZgYVrcm0kzDF21J1w6H0Lo7d1jw37LYlegBdtLQ9gYgqY2D5m+nxWuVoD5FZmpR+5JGtK+ootyLFF8aiFoHXd4op1JCxRLjgkmnZKXzw3kTQSpE7oa7CgzchtQmK2nqcqla1b5Qk7ilVcjooo=
|
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
# mailcow: dockerized - 🐮 + 🐋 = 💕
|
# mailcow: dockerized - 🐮 + 🐋 = 💕
|
||||||
[](https://drone.mailcow.email/mailcow/mailcow-dockerized) [](https://drone.mailcow.email/mailcow/mailcow-dockerized) [](https://translate.mailcow.email/engage/mailcow-dockerized/)
|
|
||||||
|
[](https://github.com/mailcow/mailcow-dockerized/actions/workflows/integration_tests.yml)
|
||||||
|
[](https://translate.mailcow.email/engage/mailcow-dockerized/)
|
||||||
[](https://twitter.com/mailcow_email)
|
[](https://twitter.com/mailcow_email)
|
||||||
|
|
||||||
## Want to support mailcow?
|
## Want to support mailcow?
|
||||||
@@ -32,3 +34,9 @@ Telegram desktop clients are available for [multiple platforms](https://desktop.
|
|||||||
|
|
||||||
**Important**: mailcow makes use of various open-source software. Please assure you agree with their license before using mailcow.
|
**Important**: mailcow makes use of various open-source software. Please assure you agree with their license before using mailcow.
|
||||||
Any part of mailcow itself is released under **GNU General Public License, Version 3**.
|
Any part of mailcow itself is released under **GNU General Public License, Version 3**.
|
||||||
|
|
||||||
|
mailcow is a registered word mark of The Infrastructure Company GmbH, Parkstr. 42, 47877 Willich, Germany.
|
||||||
|
|
||||||
|
The project is managed and maintained by The Infrastructure Company GmbH.
|
||||||
|
|
||||||
|
Originated from @andryyy (André)
|
||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
# Security Policies and Procedures
|
||||||
|
|
||||||
|
This document outlines security procedures and general policies for the _mailcow: dockerized_ project as found on [mailcow-dockerized](https://github.com/mailcow/mailcow-dockerized).
|
||||||
|
|
||||||
|
* [Reporting a Vulnerability](#reporting-a-vulnerability)
|
||||||
|
* [Disclosure Policy](#disclosure-policy)
|
||||||
|
* [Comments on this Policy](#comments-on-this-policy)
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
The mailcow team and community take all security vulnerabilities
|
||||||
|
seriously. Thank you for improving the security of our open source
|
||||||
|
software. We appreciate your efforts and responsible disclosure and will
|
||||||
|
make every effort to acknowledge your contributions.
|
||||||
|
|
||||||
|
Report security vulnerabilities by emailing the mailcow team at:
|
||||||
|
|
||||||
|
info at servercow.de
|
||||||
|
|
||||||
|
mailcow team will acknowledge your email as soon as possible, and will
|
||||||
|
send a more detailed response afterwards indicating the next steps in
|
||||||
|
handling your report. After the initial reply to your report, the mailcow
|
||||||
|
team will endeavor to keep you informed of the progress towards a fix and
|
||||||
|
full announcement, and may ask for additional information or guidance.
|
||||||
|
|
||||||
|
Report security vulnerabilities in third-party modules to the person or
|
||||||
|
team maintaining the module.
|
||||||
|
|
||||||
|
## Disclosure Policy
|
||||||
|
|
||||||
|
When the mailcow team receives a security bug report, they will assign it
|
||||||
|
to a primary handler. This person will coordinate the fix and release
|
||||||
|
process, involving the following steps:
|
||||||
|
|
||||||
|
* Confirm the problem and determine the affected versions.
|
||||||
|
* Audit code to find any potential similar problems.
|
||||||
|
* Prepare fixes for all releases still under maintenance.
|
||||||
|
|
||||||
|
## Comments on this Policy
|
||||||
|
|
||||||
|
If you have suggestions on how this process could be improved please submit a
|
||||||
|
pull request.
|
||||||
Regular → Executable
@@ -1,4 +1,4 @@
|
|||||||
FROM alpine:3.15
|
FROM alpine:3.17
|
||||||
|
|
||||||
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
|
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
FROM debian:bullseye-slim
|
||||||
|
|
||||||
|
RUN apt update && apt install pigz
|
||||||
@@ -1,60 +1,21 @@
|
|||||||
FROM debian:bullseye-slim
|
FROM clamav/clamav:1.0_base
|
||||||
|
|
||||||
LABEL maintainer "André Peters <andre.peters@servercow.de>"
|
LABEL maintainer "André Peters <andre.peters@servercow.de>"
|
||||||
|
|
||||||
ARG CLAMAV=0.103.5
|
RUN apk upgrade --no-cache \
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
&& apk add --update --no-cache \
|
||||||
ca-certificates \
|
|
||||||
zlib1g-dev \
|
|
||||||
libcurl4-openssl-dev \
|
|
||||||
libncurses5-dev \
|
|
||||||
libzip-dev \
|
|
||||||
libpcre2-dev \
|
|
||||||
libxml2-dev \
|
|
||||||
libssl-dev \
|
|
||||||
build-essential \
|
|
||||||
libjson-c-dev \
|
|
||||||
curl \
|
|
||||||
bash \
|
|
||||||
wget \
|
|
||||||
tzdata \
|
|
||||||
dnsutils \
|
|
||||||
rsync \
|
rsync \
|
||||||
dos2unix \
|
bind-tools \
|
||||||
netcat \
|
bash
|
||||||
&& rm -rf /var/lib/apt/lists/* \
|
|
||||||
&& wget -O - https://www.clamav.net/downloads/production/clamav-${CLAMAV}.tar.gz | tar xfvz - \
|
|
||||||
&& cd clamav-${CLAMAV} \
|
|
||||||
&& ./configure \
|
|
||||||
--prefix=/usr \
|
|
||||||
--libdir=/usr/lib \
|
|
||||||
--sysconfdir=/etc/clamav \
|
|
||||||
--mandir=/usr/share/man \
|
|
||||||
--infodir=/usr/share/info \
|
|
||||||
--disable-llvm \
|
|
||||||
--with-user=clamav \
|
|
||||||
--with-group=clamav \
|
|
||||||
--with-dbdir=/var/lib/clamav \
|
|
||||||
--enable-clamdtop \
|
|
||||||
--enable-bigstack \
|
|
||||||
--with-pcre \
|
|
||||||
&& make -j4 \
|
|
||||||
&& make install \
|
|
||||||
&& make clean \
|
|
||||||
&& cd .. && rm -rf clamav-${CLAMAV} \
|
|
||||||
&& apt-get -y --auto-remove purge build-essential \
|
|
||||||
&& apt-get -y purge zlib1g-dev \
|
|
||||||
libncurses5-dev \
|
|
||||||
libzip-dev \
|
|
||||||
libpcre2-dev \
|
|
||||||
libxml2-dev \
|
|
||||||
libssl-dev \
|
|
||||||
libjson-c-dev \
|
|
||||||
&& addgroup --system --gid 700 clamav \
|
|
||||||
&& adduser --system --no-create-home --home /var/lib/clamav --uid 700 --gid 700 --disabled-login clamav \
|
|
||||||
&& rm -rf /tmp/* /var/tmp/*
|
|
||||||
|
|
||||||
COPY clamd.sh ./
|
# init
|
||||||
COPY tini /sbin/tini
|
COPY clamd.sh /clamd.sh
|
||||||
|
RUN chmod +x /sbin/tini
|
||||||
|
|
||||||
CMD ["/sbin/tini", "-g", "--", "/clamd.sh"]
|
# healthcheck
|
||||||
|
COPY healthcheck.sh /healthcheck.sh
|
||||||
|
RUN chmod +x /healthcheck.sh
|
||||||
|
HEALTHCHECK --start-period=6m CMD "/healthcheck.sh"
|
||||||
|
|
||||||
|
ENTRYPOINT []
|
||||||
|
CMD ["/sbin/tini", "-g", "--", "/clamd.sh"]
|
||||||
Executable
+9
@@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [[ "${SKIP_CLAMD}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||||
|
echo "SKIP_CLAMD=y, skipping ClamAV..."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# run clamd healthcheck
|
||||||
|
/usr/local/bin/clamdcheck.sh
|
||||||
Binary file not shown.
@@ -1,4 +1,4 @@
|
|||||||
FROM alpine:3.15
|
FROM alpine:3.17
|
||||||
|
|
||||||
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
|
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
|
||||||
|
|
||||||
@@ -8,11 +8,14 @@ RUN apk add --update --no-cache python3 \
|
|||||||
py3-pip \
|
py3-pip \
|
||||||
openssl \
|
openssl \
|
||||||
tzdata \
|
tzdata \
|
||||||
|
py3-psutil \
|
||||||
&& pip3 install --upgrade pip \
|
&& pip3 install --upgrade pip \
|
||||||
docker \
|
fastapi \
|
||||||
flask \
|
uvicorn \
|
||||||
flask-restful
|
aiodocker \
|
||||||
|
redis
|
||||||
|
|
||||||
|
COPY docker-entrypoint.sh /app/
|
||||||
COPY dockerapi.py /app/
|
COPY dockerapi.py /app/
|
||||||
|
|
||||||
CMD ["python3", "-u", "/app/dockerapi.py"]
|
ENTRYPOINT ["/bin/sh", "/app/docker-entrypoint.sh"]
|
||||||
|
|||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
`openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes \
|
||||||
|
-keyout /app/dockerapi_key.pem \
|
||||||
|
-out /app/dockerapi_cert.pem \
|
||||||
|
-subj /CN=dockerapi/O=mailcow \
|
||||||
|
-addext subjectAltName=DNS:dockerapi`
|
||||||
|
|
||||||
|
`uvicorn --host 0.0.0.0 --port 443 --ssl-certfile=/app/dockerapi_cert.pem --ssl-keyfile=/app/dockerapi_key.pem dockerapi:app`
|
||||||
@@ -1,419 +1,623 @@
|
|||||||
#!/usr/bin/env python3
|
from fastapi import FastAPI, Response, Request
|
||||||
|
import aiodocker
|
||||||
from flask import Flask
|
import psutil
|
||||||
from flask_restful import Resource, Api
|
import sys
|
||||||
from flask import jsonify
|
import re
|
||||||
from flask import Response
|
|
||||||
from flask import request
|
|
||||||
from threading import Thread
|
|
||||||
import docker
|
|
||||||
import uuid
|
|
||||||
import signal
|
|
||||||
import time
|
import time
|
||||||
import os
|
import os
|
||||||
import re
|
import json
|
||||||
import sys
|
import asyncio
|
||||||
import ssl
|
import redis
|
||||||
import socket
|
from datetime import datetime
|
||||||
import subprocess
|
|
||||||
import traceback
|
|
||||||
|
|
||||||
docker_client = docker.DockerClient(base_url='unix://var/run/docker.sock', version='auto')
|
|
||||||
app = Flask(__name__)
|
|
||||||
api = Api(app)
|
|
||||||
|
|
||||||
class containers_get(Resource):
|
containerIds_to_update = []
|
||||||
def get(self):
|
host_stats_isUpdating = False
|
||||||
containers = {}
|
app = FastAPI()
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/host/stats")
|
||||||
|
async def get_host_update_stats():
|
||||||
|
global host_stats_isUpdating
|
||||||
|
|
||||||
|
if host_stats_isUpdating == False:
|
||||||
|
print("start host stats task")
|
||||||
|
asyncio.create_task(get_host_stats())
|
||||||
|
host_stats_isUpdating = True
|
||||||
|
|
||||||
|
while True:
|
||||||
|
if redis_client.exists('host_stats'):
|
||||||
|
break
|
||||||
|
print("wait for host_stats results")
|
||||||
|
await asyncio.sleep(1.5)
|
||||||
|
|
||||||
|
|
||||||
|
print("host stats pulled")
|
||||||
|
stats = json.loads(redis_client.get('host_stats'))
|
||||||
|
return Response(content=json.dumps(stats, indent=4), media_type="application/json")
|
||||||
|
|
||||||
|
@app.get("/containers/{container_id}/json")
|
||||||
|
async def get_container(container_id : str):
|
||||||
|
if container_id and container_id.isalnum():
|
||||||
try:
|
try:
|
||||||
for container in docker_client.containers.list(all=True):
|
for container in (await async_docker_client.containers.list()):
|
||||||
containers.update({container.attrs['Id']: container.attrs})
|
if container._id == container_id:
|
||||||
return containers
|
container_info = await container.show()
|
||||||
|
return Response(content=json.dumps(container_info, indent=4), media_type="application/json")
|
||||||
|
|
||||||
|
res = {
|
||||||
|
"type": "danger",
|
||||||
|
"msg": "no container found"
|
||||||
|
}
|
||||||
|
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return jsonify(type='danger', msg=str(e))
|
res = {
|
||||||
|
"type": "danger",
|
||||||
|
"msg": str(e)
|
||||||
|
}
|
||||||
|
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||||
|
else:
|
||||||
|
res = {
|
||||||
|
"type": "danger",
|
||||||
|
"msg": "no or invalid id defined"
|
||||||
|
}
|
||||||
|
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||||
|
|
||||||
class container_get(Resource):
|
@app.get("/containers/json")
|
||||||
def get(self, container_id):
|
async def get_containers():
|
||||||
if container_id and container_id.isalnum():
|
containers = {}
|
||||||
try:
|
try:
|
||||||
for container in docker_client.containers.list(all=True, filters={"id": container_id}):
|
for container in (await async_docker_client.containers.list()):
|
||||||
return container.attrs
|
container_info = await container.show()
|
||||||
except Exception as e:
|
containers.update({container_info['Id']: container_info})
|
||||||
return jsonify(type='danger', msg=str(e))
|
return Response(content=json.dumps(containers, indent=4), media_type="application/json")
|
||||||
else:
|
except Exception as e:
|
||||||
return jsonify(type='danger', msg='no or invalid id defined')
|
res = {
|
||||||
|
"type": "danger",
|
||||||
|
"msg": str(e)
|
||||||
|
}
|
||||||
|
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||||
|
|
||||||
class container_post(Resource):
|
@app.post("/containers/{container_id}/{post_action}")
|
||||||
def post(self, container_id, post_action):
|
async def post_containers(container_id : str, post_action : str, request: Request):
|
||||||
if container_id and container_id.isalnum() and post_action:
|
try :
|
||||||
try:
|
request_json = await request.json()
|
||||||
"""Dispatch container_post api call"""
|
except Exception as err:
|
||||||
if post_action == 'exec':
|
request_json = {}
|
||||||
if not request.json or not 'cmd' in request.json:
|
|
||||||
return jsonify(type='danger', msg='cmd is missing')
|
|
||||||
if not request.json or not 'task' in request.json:
|
|
||||||
return jsonify(type='danger', msg='task is missing')
|
|
||||||
|
|
||||||
api_call_method_name = '__'.join(['container_post', str(post_action), str(request.json['cmd']), str(request.json['task']) ])
|
if container_id and container_id.isalnum() and post_action:
|
||||||
else:
|
try:
|
||||||
api_call_method_name = '__'.join(['container_post', str(post_action) ])
|
"""Dispatch container_post api call"""
|
||||||
|
if post_action == 'exec':
|
||||||
|
if not request_json or not 'cmd' in request_json:
|
||||||
|
res = {
|
||||||
|
"type": "danger",
|
||||||
|
"msg": "cmd is missing"
|
||||||
|
}
|
||||||
|
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||||
|
if not request_json or not 'task' in request_json:
|
||||||
|
res = {
|
||||||
|
"type": "danger",
|
||||||
|
"msg": "task is missing"
|
||||||
|
}
|
||||||
|
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||||
|
|
||||||
api_call_method = getattr(self, api_call_method_name, lambda container_id: jsonify(type='danger', msg='container_post - unknown api call'))
|
api_call_method_name = '__'.join(['container_post', str(post_action), str(request_json['cmd']), str(request_json['task']) ])
|
||||||
|
else:
|
||||||
|
api_call_method_name = '__'.join(['container_post', str(post_action) ])
|
||||||
|
|
||||||
|
docker_utils = DockerUtils(async_docker_client)
|
||||||
|
api_call_method = getattr(docker_utils, api_call_method_name, lambda container_id: Response(content=json.dumps({'type': 'danger', 'msg':'container_post - unknown api call' }, indent=4), media_type="application/json"))
|
||||||
|
|
||||||
|
|
||||||
print("api call: %s, container_id: %s" % (api_call_method_name, container_id))
|
print("api call: %s, container_id: %s" % (api_call_method_name, container_id))
|
||||||
return api_call_method(container_id)
|
return await api_call_method(container_id, request_json)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("error - container_post: %s" % str(e))
|
print("error - container_post: %s" % str(e))
|
||||||
return jsonify(type='danger', msg=str(e))
|
res = {
|
||||||
|
"type": "danger",
|
||||||
|
"msg": str(e)
|
||||||
|
}
|
||||||
|
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
return jsonify(type='danger', msg='invalid container id or missing action')
|
res = {
|
||||||
|
"type": "danger",
|
||||||
|
"msg": "invalid container id or missing action"
|
||||||
|
}
|
||||||
|
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||||
|
|
||||||
|
@app.post("/container/{container_id}/stats/update")
|
||||||
|
async def post_container_update_stats(container_id : str):
|
||||||
|
global containerIds_to_update
|
||||||
|
|
||||||
|
# start update task for container if no task is running
|
||||||
|
if container_id not in containerIds_to_update:
|
||||||
|
asyncio.create_task(get_container_stats(container_id))
|
||||||
|
containerIds_to_update.append(container_id)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
if redis_client.exists(container_id + '_stats'):
|
||||||
|
break
|
||||||
|
await asyncio.sleep(1.5)
|
||||||
|
|
||||||
|
stats = json.loads(redis_client.get(container_id + '_stats'))
|
||||||
|
return Response(content=json.dumps(stats, indent=4), media_type="application/json")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class DockerUtils:
|
||||||
|
def __init__(self, docker_client):
|
||||||
|
self.docker_client = docker_client
|
||||||
|
|
||||||
# api call: container_post - post_action: stop
|
# api call: container_post - post_action: stop
|
||||||
def container_post__stop(self, container_id):
|
async def container_post__stop(self, container_id, request_json):
|
||||||
for container in docker_client.containers.list(all=True, filters={"id": container_id}):
|
for container in (await self.docker_client.containers.list()):
|
||||||
container.stop()
|
if container._id == container_id:
|
||||||
return jsonify(type='success', msg='command completed successfully')
|
await container.stop()
|
||||||
|
res = {
|
||||||
|
'type': 'success',
|
||||||
|
'msg': 'command completed successfully'
|
||||||
|
}
|
||||||
|
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||||
|
|
||||||
# api call: container_post - post_action: start
|
# api call: container_post - post_action: start
|
||||||
def container_post__start(self, container_id):
|
async def container_post__start(self, container_id, request_json):
|
||||||
for container in docker_client.containers.list(all=True, filters={"id": container_id}):
|
for container in (await self.docker_client.containers.list()):
|
||||||
container.start()
|
if container._id == container_id:
|
||||||
return jsonify(type='success', msg='command completed successfully')
|
await container.start()
|
||||||
|
res = {
|
||||||
|
'type': 'success',
|
||||||
|
'msg': 'command completed successfully'
|
||||||
|
}
|
||||||
|
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||||
|
|
||||||
|
|
||||||
# api call: container_post - post_action: restart
|
# api call: container_post - post_action: restart
|
||||||
def container_post__restart(self, container_id):
|
async def container_post__restart(self, container_id, request_json):
|
||||||
for container in docker_client.containers.list(all=True, filters={"id": container_id}):
|
for container in (await self.docker_client.containers.list()):
|
||||||
container.restart()
|
if container._id == container_id:
|
||||||
return jsonify(type='success', msg='command completed successfully')
|
await container.restart()
|
||||||
|
res = {
|
||||||
|
'type': 'success',
|
||||||
|
'msg': 'command completed successfully'
|
||||||
|
}
|
||||||
|
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||||
|
|
||||||
|
|
||||||
# api call: container_post - post_action: top
|
# api call: container_post - post_action: top
|
||||||
def container_post__top(self, container_id):
|
async def container_post__top(self, container_id, request_json):
|
||||||
for container in docker_client.containers.list(all=True, filters={"id": container_id}):
|
for container in (await self.docker_client.containers.list()):
|
||||||
return jsonify(type='success', msg=container.top())
|
if container._id == container_id:
|
||||||
|
ps_exec = await container.exec("ps")
|
||||||
|
async with ps_exec.start(detach=False) as stream:
|
||||||
|
ps_return = await stream.read_out()
|
||||||
|
|
||||||
|
exec_details = await ps_exec.inspect()
|
||||||
# api call: container_post - post_action: stats
|
if exec_details["ExitCode"] == None or exec_details["ExitCode"] == 0:
|
||||||
def container_post__stats(self, container_id):
|
res = {
|
||||||
for container in docker_client.containers.list(all=True, filters={"id": container_id}):
|
'type': 'success',
|
||||||
for stat in container.stats(decode=True, stream=True):
|
'msg': ps_return.data.decode('utf-8')
|
||||||
return jsonify(type='success', msg=stat )
|
}
|
||||||
|
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||||
|
else:
|
||||||
|
res = {
|
||||||
|
'type': 'danger',
|
||||||
|
'msg': ''
|
||||||
|
}
|
||||||
|
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||||
|
|
||||||
|
|
||||||
# api call: container_post - post_action: exec - cmd: mailq - task: delete
|
# api call: container_post - post_action: exec - cmd: mailq - task: delete
|
||||||
def container_post__exec__mailq__delete(self, container_id):
|
async def container_post__exec__mailq__delete(self, container_id, request_json):
|
||||||
if 'items' in request.json:
|
if 'items' in request_json:
|
||||||
r = re.compile("^[0-9a-fA-F]+$")
|
r = re.compile("^[0-9a-fA-F]+$")
|
||||||
filtered_qids = filter(r.match, request.json['items'])
|
filtered_qids = filter(r.match, request_json['items'])
|
||||||
if filtered_qids:
|
if filtered_qids:
|
||||||
flagged_qids = ['-d %s' % i for i in filtered_qids]
|
flagged_qids = ['-d %s' % i for i in filtered_qids]
|
||||||
sanitized_string = str(' '.join(flagged_qids));
|
sanitized_string = str(' '.join(flagged_qids))
|
||||||
|
|
||||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
for container in (await self.docker_client.containers.list()):
|
||||||
postsuper_r = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postsuper " + sanitized_string])
|
if container._id == container_id:
|
||||||
return exec_run_handler('generic', postsuper_r)
|
postsuper_r_exec = await container.exec(["/bin/bash", "-c", "/usr/sbin/postsuper " + sanitized_string])
|
||||||
|
return await exec_run_handler('generic', postsuper_r_exec)
|
||||||
|
|
||||||
# api call: container_post - post_action: exec - cmd: mailq - task: hold
|
# api call: container_post - post_action: exec - cmd: mailq - task: hold
|
||||||
def container_post__exec__mailq__hold(self, container_id):
|
async def container_post__exec__mailq__hold(self, container_id, request_json):
|
||||||
if 'items' in request.json:
|
if 'items' in request_json:
|
||||||
r = re.compile("^[0-9a-fA-F]+$")
|
r = re.compile("^[0-9a-fA-F]+$")
|
||||||
filtered_qids = filter(r.match, request.json['items'])
|
filtered_qids = filter(r.match, request_json['items'])
|
||||||
if filtered_qids:
|
if filtered_qids:
|
||||||
flagged_qids = ['-h %s' % i for i in filtered_qids]
|
flagged_qids = ['-h %s' % i for i in filtered_qids]
|
||||||
sanitized_string = str(' '.join(flagged_qids));
|
sanitized_string = str(' '.join(flagged_qids))
|
||||||
|
|
||||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
for container in (await self.docker_client.containers.list()):
|
||||||
postsuper_r = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postsuper " + sanitized_string])
|
if container._id == container_id:
|
||||||
return exec_run_handler('generic', postsuper_r)
|
postsuper_r_exec = await container.exec(["/bin/bash", "-c", "/usr/sbin/postsuper " + sanitized_string])
|
||||||
|
return await exec_run_handler('generic', postsuper_r_exec)
|
||||||
|
|
||||||
# api call: container_post - post_action: exec - cmd: mailq - task: cat
|
# api call: container_post - post_action: exec - cmd: mailq - task: cat
|
||||||
def container_post__exec__mailq__cat(self, container_id):
|
async def container_post__exec__mailq__cat(self, container_id, request_json):
|
||||||
if 'items' in request.json:
|
if 'items' in request_json:
|
||||||
r = re.compile("^[0-9a-fA-F]+$")
|
r = re.compile("^[0-9a-fA-F]+$")
|
||||||
filtered_qids = filter(r.match, request.json['items'])
|
filtered_qids = filter(r.match, request_json['items'])
|
||||||
if filtered_qids:
|
if filtered_qids:
|
||||||
sanitized_string = str(' '.join(filtered_qids));
|
sanitized_string = str(' '.join(filtered_qids))
|
||||||
|
|
||||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
for container in (await self.docker_client.containers.list()):
|
||||||
postcat_return = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postcat -q " + sanitized_string], user='postfix')
|
if container._id == container_id:
|
||||||
if not postcat_return:
|
postcat_exec = await container.exec(["/bin/bash", "-c", "/usr/sbin/postcat -q " + sanitized_string], user='postfix')
|
||||||
postcat_return = 'err: invalid'
|
return await exec_run_handler('utf8_text_only', postcat_exec)
|
||||||
return exec_run_handler('utf8_text_only', postcat_return)
|
|
||||||
|
|
||||||
# api call: container_post - post_action: exec - cmd: mailq - task: unhold
|
# api call: container_post - post_action: exec - cmd: mailq - task: unhold
|
||||||
def container_post__exec__mailq__unhold(self, container_id):
|
async def container_post__exec__mailq__unhold(self, container_id, request_json):
|
||||||
if 'items' in request.json:
|
if 'items' in request_json:
|
||||||
r = re.compile("^[0-9a-fA-F]+$")
|
r = re.compile("^[0-9a-fA-F]+$")
|
||||||
filtered_qids = filter(r.match, request.json['items'])
|
filtered_qids = filter(r.match, request_json['items'])
|
||||||
if filtered_qids:
|
if filtered_qids:
|
||||||
flagged_qids = ['-H %s' % i for i in filtered_qids]
|
flagged_qids = ['-H %s' % i for i in filtered_qids]
|
||||||
sanitized_string = str(' '.join(flagged_qids));
|
sanitized_string = str(' '.join(flagged_qids))
|
||||||
|
|
||||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
for container in (await self.docker_client.containers.list()):
|
||||||
postsuper_r = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postsuper " + sanitized_string])
|
if container._id == container_id:
|
||||||
return exec_run_handler('generic', postsuper_r)
|
postsuper_r_exec = await container.exec(["/bin/bash", "-c", "/usr/sbin/postsuper " + sanitized_string])
|
||||||
|
return await exec_run_handler('generic', postsuper_r_exec)
|
||||||
|
|
||||||
|
|
||||||
# api call: container_post - post_action: exec - cmd: mailq - task: deliver
|
# api call: container_post - post_action: exec - cmd: mailq - task: deliver
|
||||||
def container_post__exec__mailq__deliver(self, container_id):
|
async def container_post__exec__mailq__deliver(self, container_id, request_json):
|
||||||
if 'items' in request.json:
|
if 'items' in request_json:
|
||||||
r = re.compile("^[0-9a-fA-F]+$")
|
r = re.compile("^[0-9a-fA-F]+$")
|
||||||
filtered_qids = filter(r.match, request.json['items'])
|
filtered_qids = filter(r.match, request_json['items'])
|
||||||
if filtered_qids:
|
if filtered_qids:
|
||||||
flagged_qids = ['-i %s' % i for i in filtered_qids]
|
flagged_qids = ['-i %s' % i for i in filtered_qids]
|
||||||
|
|
||||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
for container in (await self.docker_client.containers.list()):
|
||||||
for i in flagged_qids:
|
if container._id == container_id:
|
||||||
postqueue_r = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postqueue " + i], user='postfix')
|
for i in flagged_qids:
|
||||||
# todo: check each exit code
|
postsuper_r_exec = await container.exec(["/bin/bash", "-c", "/usr/sbin/postqueue " + i], user='postfix')
|
||||||
return jsonify(type='success', msg=str("Scheduled immediate delivery"))
|
async with postsuper_r_exec.start(detach=False) as stream:
|
||||||
|
postsuper_r_return = await stream.read_out()
|
||||||
|
# todo: check each exit code
|
||||||
|
res = {
|
||||||
|
'type': 'success',
|
||||||
|
'msg': 'Scheduled immediate delivery'
|
||||||
|
}
|
||||||
|
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||||
|
|
||||||
|
|
||||||
# api call: container_post - post_action: exec - cmd: mailq - task: list
|
# api call: container_post - post_action: exec - cmd: mailq - task: list
|
||||||
def container_post__exec__mailq__list(self, container_id):
|
async def container_post__exec__mailq__list(self, container_id, request_json):
|
||||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
for container in (await self.docker_client.containers.list()):
|
||||||
mailq_return = container.exec_run(["/usr/sbin/postqueue", "-j"], user='postfix')
|
if container._id == container_id:
|
||||||
return exec_run_handler('utf8_text_only', mailq_return)
|
mailq_exec = await container.exec(["/usr/sbin/postqueue", "-j"], user='postfix')
|
||||||
|
return await exec_run_handler('utf8_text_only', mailq_exec)
|
||||||
|
|
||||||
|
|
||||||
# api call: container_post - post_action: exec - cmd: mailq - task: flush
|
# api call: container_post - post_action: exec - cmd: mailq - task: flush
|
||||||
def container_post__exec__mailq__flush(self, container_id):
|
async def container_post__exec__mailq__flush(self, container_id, request_json):
|
||||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
for container in (await self.docker_client.containers.list()):
|
||||||
postqueue_r = container.exec_run(["/usr/sbin/postqueue", "-f"], user='postfix')
|
if container._id == container_id:
|
||||||
return exec_run_handler('generic', postqueue_r)
|
postsuper_r_exec = await container.exec(["/usr/sbin/postqueue", "-f"], user='postfix')
|
||||||
|
return await exec_run_handler('generic', postsuper_r_exec)
|
||||||
|
|
||||||
|
|
||||||
# api call: container_post - post_action: exec - cmd: mailq - task: super_delete
|
# api call: container_post - post_action: exec - cmd: mailq - task: super_delete
|
||||||
def container_post__exec__mailq__super_delete(self, container_id):
|
async def container_post__exec__mailq__super_delete(self, container_id, request_json):
|
||||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
for container in (await self.docker_client.containers.list()):
|
||||||
postsuper_r = container.exec_run(["/usr/sbin/postsuper", "-d", "ALL"])
|
if container._id == container_id:
|
||||||
return exec_run_handler('generic', postsuper_r)
|
postsuper_r_exec = await container.exec(["/usr/sbin/postsuper", "-d", "ALL"])
|
||||||
|
return await exec_run_handler('generic', postsuper_r_exec)
|
||||||
|
|
||||||
|
|
||||||
# api call: container_post - post_action: exec - cmd: system - task: fts_rescan
|
# api call: container_post - post_action: exec - cmd: system - task: fts_rescan
|
||||||
def container_post__exec__system__fts_rescan(self, container_id):
|
async def container_post__exec__system__fts_rescan(self, container_id, request_json):
|
||||||
if 'username' in request.json:
|
if 'username' in request_json:
|
||||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
for container in (await self.docker_client.containers.list()):
|
||||||
rescan_return = container.exec_run(["/bin/bash", "-c", "/usr/bin/doveadm fts rescan -u '" + request.json['username'].replace("'", "'\\''") + "'"], user='vmail')
|
if container._id == container_id:
|
||||||
if rescan_return.exit_code == 0:
|
rescan_exec = await container.exec(["/bin/bash", "-c", "/usr/bin/doveadm fts rescan -u '" + request_json['username'].replace("'", "'\\''") + "'"], user='vmail')
|
||||||
return jsonify(type='success', msg='fts_rescan: rescan triggered')
|
async with rescan_exec.start(detach=False) as stream:
|
||||||
else:
|
rescan_return = await stream.read_out()
|
||||||
return jsonify(type='warning', msg='fts_rescan error')
|
|
||||||
|
|
||||||
if 'all' in request.json:
|
exec_details = await rescan_exec.inspect()
|
||||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
if exec_details["ExitCode"] == None or exec_details["ExitCode"] == 0:
|
||||||
rescan_return = container.exec_run(["/bin/bash", "-c", "/usr/bin/doveadm fts rescan -A"], user='vmail')
|
res = {
|
||||||
if rescan_return.exit_code == 0:
|
'type': 'success',
|
||||||
return jsonify(type='success', msg='fts_rescan: rescan triggered')
|
'msg': 'fts_rescan: rescan triggered'
|
||||||
else:
|
}
|
||||||
return jsonify(type='warning', msg='fts_rescan error')
|
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||||
|
else:
|
||||||
|
res = {
|
||||||
|
'type': 'warning',
|
||||||
|
'msg': 'fts_rescan error'
|
||||||
|
}
|
||||||
|
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||||
|
|
||||||
|
if 'all' in request_json:
|
||||||
|
for container in (await self.docker_client.containers.list()):
|
||||||
|
if container._id == container_id:
|
||||||
|
rescan_exec = await container.exec(["/bin/bash", "-c", "/usr/bin/doveadm fts rescan -A"], user='vmail')
|
||||||
|
async with rescan_exec.start(detach=False) as stream:
|
||||||
|
rescan_return = await stream.read_out()
|
||||||
|
|
||||||
|
exec_details = await rescan_exec.inspect()
|
||||||
|
if exec_details["ExitCode"] == None or exec_details["ExitCode"] == 0:
|
||||||
|
res = {
|
||||||
|
'type': 'success',
|
||||||
|
'msg': 'fts_rescan: rescan triggered'
|
||||||
|
}
|
||||||
|
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||||
|
else:
|
||||||
|
res = {
|
||||||
|
'type': 'warning',
|
||||||
|
'msg': 'fts_rescan error'
|
||||||
|
}
|
||||||
|
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||||
|
|
||||||
|
|
||||||
# api call: container_post - post_action: exec - cmd: system - task: df
|
# api call: container_post - post_action: exec - cmd: system - task: df
|
||||||
def container_post__exec__system__df(self, container_id):
|
async def container_post__exec__system__df(self, container_id, request_json):
|
||||||
if 'dir' in request.json:
|
if 'dir' in request_json:
|
||||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
for container in (await self.docker_client.containers.list()):
|
||||||
df_return = container.exec_run(["/bin/bash", "-c", "/bin/df -H '" + request.json['dir'].replace("'", "'\\''") + "' | /usr/bin/tail -n1 | /usr/bin/tr -s [:blank:] | /usr/bin/tr ' ' ','"], user='nobody')
|
if container._id == container_id:
|
||||||
if df_return.exit_code == 0:
|
df_exec = await container.exec(["/bin/bash", "-c", "/bin/df -H '" + request_json['dir'].replace("'", "'\\''") + "' | /usr/bin/tail -n1 | /usr/bin/tr -s [:blank:] | /usr/bin/tr ' ' ','"], user='nobody')
|
||||||
return df_return.output.decode('utf-8').rstrip()
|
async with df_exec.start(detach=False) as stream:
|
||||||
else:
|
df_return = await stream.read_out()
|
||||||
return "0,0,0,0,0,0"
|
|
||||||
|
print(df_return)
|
||||||
|
print(await df_exec.inspect())
|
||||||
|
exec_details = await df_exec.inspect()
|
||||||
|
if exec_details["ExitCode"] == None or exec_details["ExitCode"] == 0:
|
||||||
|
return df_return.data.decode('utf-8').rstrip()
|
||||||
|
else:
|
||||||
|
return "0,0,0,0,0,0"
|
||||||
|
|
||||||
|
|
||||||
# api call: container_post - post_action: exec - cmd: system - task: mysql_upgrade
|
# api call: container_post - post_action: exec - cmd: system - task: mysql_upgrade
|
||||||
def container_post__exec__system__mysql_upgrade(self, container_id):
|
async def container_post__exec__system__mysql_upgrade(self, container_id, request_json):
|
||||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
for container in (await self.docker_client.containers.list()):
|
||||||
sql_return = container.exec_run(["/bin/bash", "-c", "/usr/bin/mysql_upgrade -uroot -p'" + os.environ['DBROOT'].replace("'", "'\\''") + "'\n"], user='mysql')
|
if container._id == container_id:
|
||||||
if sql_return.exit_code == 0:
|
sql_exec = await container.exec(["/bin/bash", "-c", "/usr/bin/mysql_upgrade -uroot -p'" + os.environ['DBROOT'].replace("'", "'\\''") + "'\n"], user='mysql')
|
||||||
matched = False
|
async with sql_exec.start(detach=False) as stream:
|
||||||
for line in sql_return.output.decode('utf-8').split("\n"):
|
sql_return = await stream.read_out()
|
||||||
if 'is already upgraded to' in line:
|
|
||||||
matched = True
|
exec_details = await sql_exec.inspect()
|
||||||
if matched:
|
if exec_details["ExitCode"] == None or exec_details["ExitCode"] == 0:
|
||||||
return jsonify(type='success', msg='mysql_upgrade: already upgraded', text=sql_return.output.decode('utf-8'))
|
matched = False
|
||||||
|
for line in sql_return.data.decode('utf-8').split("\n"):
|
||||||
|
if 'is already upgraded to' in line:
|
||||||
|
matched = True
|
||||||
|
if matched:
|
||||||
|
res = {
|
||||||
|
'type': 'success',
|
||||||
|
'msg': 'mysql_upgrade: already upgraded',
|
||||||
|
'text': sql_return.data.decode('utf-8')
|
||||||
|
}
|
||||||
|
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||||
|
else:
|
||||||
|
await container.restart()
|
||||||
|
res = {
|
||||||
|
'type': 'warning',
|
||||||
|
'msg': 'mysql_upgrade: upgrade was applied',
|
||||||
|
'text': sql_return.data.decode('utf-8')
|
||||||
|
}
|
||||||
|
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||||
else:
|
else:
|
||||||
container.restart()
|
res = {
|
||||||
return jsonify(type='warning', msg='mysql_upgrade: upgrade was applied', text=sql_return.output.decode('utf-8'))
|
'type': 'error',
|
||||||
else:
|
'msg': 'mysql_upgrade: error running command',
|
||||||
return jsonify(type='error', msg='mysql_upgrade: error running command', text=sql_return.output.decode('utf-8'))
|
'text': sql_return.data.decode('utf-8')
|
||||||
|
}
|
||||||
|
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||||
|
|
||||||
# api call: container_post - post_action: exec - cmd: system - task: mysql_tzinfo_to_sql
|
# api call: container_post - post_action: exec - cmd: system - task: mysql_tzinfo_to_sql
|
||||||
def container_post__exec__system__mysql_tzinfo_to_sql(self, container_id):
|
async def container_post__exec__system__mysql_tzinfo_to_sql(self, container_id, request_json):
|
||||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
for container in (await self.docker_client.containers.list()):
|
||||||
sql_return = container.exec_run(["/bin/bash", "-c", "/usr/bin/mysql_tzinfo_to_sql /usr/share/zoneinfo | /bin/sed 's/Local time zone must be set--see zic manual page/FCTY/' | /usr/bin/mysql -uroot -p'" + os.environ['DBROOT'].replace("'", "'\\''") + "' mysql \n"], user='mysql')
|
if container._id == container_id:
|
||||||
if sql_return.exit_code == 0:
|
sql_exec = await container.exec(["/bin/bash", "-c", "/usr/bin/mysql_tzinfo_to_sql /usr/share/zoneinfo | /bin/sed 's/Local time zone must be set--see zic manual page/FCTY/' | /usr/bin/mysql -uroot -p'" + os.environ['DBROOT'].replace("'", "'\\''") + "' mysql \n"], user='mysql')
|
||||||
return jsonify(type='info', msg='mysql_tzinfo_to_sql: command completed successfully', text=sql_return.output.decode('utf-8'))
|
async with sql_exec.start(detach=False) as stream:
|
||||||
else:
|
sql_return = await stream.read_out()
|
||||||
return jsonify(type='error', msg='mysql_tzinfo_to_sql: error running command', text=sql_return.output.decode('utf-8'))
|
|
||||||
|
exec_details = await sql_exec.inspect()
|
||||||
|
if exec_details["ExitCode"] == None or exec_details["ExitCode"] == 0:
|
||||||
|
res = {
|
||||||
|
'type': 'info',
|
||||||
|
'msg': 'mysql_tzinfo_to_sql: command completed successfully',
|
||||||
|
'text': sql_return.data.decode('utf-8')
|
||||||
|
}
|
||||||
|
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||||
|
else:
|
||||||
|
res = {
|
||||||
|
'type': 'error',
|
||||||
|
'msg': 'mysql_tzinfo_to_sql: error running command',
|
||||||
|
'text': sql_return.data.decode('utf-8')
|
||||||
|
}
|
||||||
|
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||||
|
|
||||||
# api call: container_post - post_action: exec - cmd: reload - task: dovecot
|
# api call: container_post - post_action: exec - cmd: reload - task: dovecot
|
||||||
def container_post__exec__reload__dovecot(self, container_id):
|
async def container_post__exec__reload__dovecot(self, container_id, request_json):
|
||||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
for container in (await self.docker_client.containers.list()):
|
||||||
reload_return = container.exec_run(["/bin/bash", "-c", "/usr/sbin/dovecot reload"])
|
if container._id == container_id:
|
||||||
return exec_run_handler('generic', reload_return)
|
reload_exec = await container.exec(["/bin/bash", "-c", "/usr/sbin/dovecot reload"])
|
||||||
|
return await exec_run_handler('generic', reload_exec)
|
||||||
|
|
||||||
|
|
||||||
# api call: container_post - post_action: exec - cmd: reload - task: postfix
|
# api call: container_post - post_action: exec - cmd: reload - task: postfix
|
||||||
def container_post__exec__reload__postfix(self, container_id):
|
async def container_post__exec__reload__postfix(self, container_id, request_json):
|
||||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
for container in (await self.docker_client.containers.list()):
|
||||||
reload_return = container.exec_run(["/bin/bash", "-c", "/usr/sbin/postfix reload"])
|
if container._id == container_id:
|
||||||
return exec_run_handler('generic', reload_return)
|
reload_exec = await container.exec(["/bin/bash", "-c", "/usr/sbin/postfix reload"])
|
||||||
|
return await exec_run_handler('generic', reload_exec)
|
||||||
|
|
||||||
|
|
||||||
# api call: container_post - post_action: exec - cmd: reload - task: nginx
|
# api call: container_post - post_action: exec - cmd: reload - task: nginx
|
||||||
def container_post__exec__reload__nginx(self, container_id):
|
async def container_post__exec__reload__nginx(self, container_id, request_json):
|
||||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
for container in (await self.docker_client.containers.list()):
|
||||||
reload_return = container.exec_run(["/bin/sh", "-c", "/usr/sbin/nginx -s reload"])
|
if container._id == container_id:
|
||||||
return exec_run_handler('generic', reload_return)
|
reload_exec = await container.exec(["/bin/sh", "-c", "/usr/sbin/nginx -s reload"])
|
||||||
|
return await exec_run_handler('generic', reload_exec)
|
||||||
|
|
||||||
|
|
||||||
# api call: container_post - post_action: exec - cmd: sieve - task: list
|
# api call: container_post - post_action: exec - cmd: sieve - task: list
|
||||||
def container_post__exec__sieve__list(self, container_id):
|
async def container_post__exec__sieve__list(self, container_id, request_json):
|
||||||
if 'username' in request.json:
|
if 'username' in request_json:
|
||||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
for container in (await self.docker_client.containers.list()):
|
||||||
sieve_return = container.exec_run(["/bin/bash", "-c", "/usr/bin/doveadm sieve list -u '" + request.json['username'].replace("'", "'\\''") + "'"])
|
if container._id == container_id:
|
||||||
return exec_run_handler('utf8_text_only', sieve_return)
|
sieve_exec = await container.exec(["/bin/bash", "-c", "/usr/bin/doveadm sieve list -u '" + request_json['username'].replace("'", "'\\''") + "'"])
|
||||||
|
return await exec_run_handler('utf8_text_only', sieve_exec)
|
||||||
|
|
||||||
|
|
||||||
# api call: container_post - post_action: exec - cmd: sieve - task: print
|
# api call: container_post - post_action: exec - cmd: sieve - task: print
|
||||||
def container_post__exec__sieve__print(self, container_id):
|
async def container_post__exec__sieve__print(self, container_id, request_json):
|
||||||
if 'username' in request.json and 'script_name' in request.json:
|
if 'username' in request_json and 'script_name' in request_json:
|
||||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
for container in (await self.docker_client.containers.list()):
|
||||||
cmd = ["/bin/bash", "-c", "/usr/bin/doveadm sieve get -u '" + request.json['username'].replace("'", "'\\''") + "' '" + request.json['script_name'].replace("'", "'\\''") + "'"]
|
if container._id == container_id:
|
||||||
sieve_return = container.exec_run(cmd)
|
cmd = ["/bin/bash", "-c", "/usr/bin/doveadm sieve get -u '" + request_json['username'].replace("'", "'\\''") + "' '" + request_json['script_name'].replace("'", "'\\''") + "'"]
|
||||||
return exec_run_handler('utf8_text_only', sieve_return)
|
sieve_exec = await container.exec(cmd)
|
||||||
|
return await exec_run_handler('utf8_text_only', sieve_exec)
|
||||||
|
|
||||||
|
|
||||||
# api call: container_post - post_action: exec - cmd: maildir - task: cleanup
|
# api call: container_post - post_action: exec - cmd: maildir - task: cleanup
|
||||||
def container_post__exec__maildir__cleanup(self, container_id):
|
async def container_post__exec__maildir__cleanup(self, container_id, request_json):
|
||||||
if 'maildir' in request.json:
|
if 'maildir' in request_json:
|
||||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
for container in (await self.docker_client.containers.list()):
|
||||||
sane_name = re.sub(r'\W+', '', request.json['maildir'])
|
if container._id == container_id:
|
||||||
cmd = ["/bin/bash", "-c", "if [[ -d '/var/vmail/" + request.json['maildir'].replace("'", "'\\''") + "' ]]; then /bin/mv '/var/vmail/" + request.json['maildir'].replace("'", "'\\''") + "' '/var/vmail/_garbage/" + str(int(time.time())) + "_" + sane_name + "'; fi"]
|
sane_name = re.sub(r'\W+', '', request_json['maildir'])
|
||||||
maildir_cleanup = container.exec_run(cmd, user='vmail')
|
cmd = ["/bin/bash", "-c", "if [[ -d '/var/vmail/" + request_json['maildir'].replace("'", "'\\''") + "' ]]; then /bin/mv '/var/vmail/" + request_json['maildir'].replace("'", "'\\''") + "' '/var/vmail/_garbage/" + str(int(time.time())) + "_" + sane_name + "'; fi"]
|
||||||
return exec_run_handler('generic', maildir_cleanup)
|
maildir_cleanup_exec = await container.exec(cmd, user='vmail')
|
||||||
|
return await exec_run_handler('generic', maildir_cleanup_exec)
|
||||||
|
|
||||||
|
|
||||||
# api call: container_post - post_action: exec - cmd: rspamd - task: worker_password
|
# api call: container_post - post_action: exec - cmd: rspamd - task: worker_password
|
||||||
def container_post__exec__rspamd__worker_password(self, container_id):
|
async def container_post__exec__rspamd__worker_password(self, container_id, request_json):
|
||||||
if 'raw' in request.json:
|
if 'raw' in request_json:
|
||||||
for container in docker_client.containers.list(filters={"id": container_id}):
|
for container in (await self.docker_client.containers.list()):
|
||||||
cmd = "/usr/bin/rspamadm pw -e -p '" + request.json['raw'].replace("'", "'\\''") + "' 2> /dev/null"
|
if container._id == container_id:
|
||||||
cmd_response = exec_cmd_container(container, cmd, user="_rspamd")
|
|
||||||
matched = False
|
cmd = "./set_worker_password.sh '" + request_json['raw'].replace("'", "'\\''") + "' 2> /dev/null"
|
||||||
for line in cmd_response.split("\n"):
|
rspamd_password_exec = await container.exec(cmd, user='_rspamd')
|
||||||
if '$2$' in line:
|
async with rspamd_password_exec.start(detach=False) as stream:
|
||||||
hash = line.strip()
|
rspamd_password_return = await stream.read_out()
|
||||||
hash_out = re.search('\$2\$.+$', hash).group(0)
|
|
||||||
rspamd_passphrase_hash = re.sub('[^0-9a-zA-Z\$]+', '', hash_out.rstrip())
|
|
||||||
|
|
||||||
rspamd_password_filename = "/etc/rspamd/override.d/worker-controller-password.inc"
|
matched = False
|
||||||
cmd = '''/bin/echo 'enable_password = "%s";' > %s && cat %s''' % (rspamd_passphrase_hash, rspamd_password_filename, rspamd_password_filename)
|
if "OK" in rspamd_password_return.data.decode('utf-8'):
|
||||||
cmd_response = exec_cmd_container(container, cmd, user="_rspamd")
|
matched = True
|
||||||
|
await container.restart()
|
||||||
|
|
||||||
if rspamd_passphrase_hash.startswith("$2$") and rspamd_passphrase_hash in cmd_response:
|
if matched:
|
||||||
container.restart()
|
res = {
|
||||||
matched = True
|
'type': 'success',
|
||||||
|
'msg': 'command completed successfully'
|
||||||
|
}
|
||||||
|
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||||
|
else:
|
||||||
|
res = {
|
||||||
|
'type': 'danger',
|
||||||
|
'msg': 'command did not complete'
|
||||||
|
}
|
||||||
|
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||||
|
|
||||||
if matched:
|
|
||||||
return jsonify(type='success', msg='command completed successfully')
|
|
||||||
else:
|
|
||||||
return jsonify(type='danger', msg='command did not complete')
|
|
||||||
|
|
||||||
def exec_cmd_container(container, cmd, user, timeout=2, shell_cmd="/bin/bash"):
|
|
||||||
|
|
||||||
def recv_socket_data(c_socket, timeout):
|
async def exec_run_handler(type, exec_obj):
|
||||||
c_socket.setblocking(0)
|
async with exec_obj.start(detach=False) as stream:
|
||||||
total_data=[];
|
exec_return = await stream.read_out()
|
||||||
data='';
|
|
||||||
begin=time.time()
|
|
||||||
while True:
|
|
||||||
if total_data and time.time()-begin > timeout:
|
|
||||||
break
|
|
||||||
elif time.time()-begin > timeout*2:
|
|
||||||
break
|
|
||||||
try:
|
|
||||||
data = c_socket.recv(8192)
|
|
||||||
if data:
|
|
||||||
total_data.append(data.decode('utf-8'))
|
|
||||||
#change the beginning time for measurement
|
|
||||||
begin=time.time()
|
|
||||||
else:
|
|
||||||
#sleep for sometime to indicate a gap
|
|
||||||
time.sleep(0.1)
|
|
||||||
break
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
return ''.join(total_data)
|
|
||||||
|
|
||||||
try :
|
if exec_return == None:
|
||||||
socket = container.exec_run([shell_cmd], stdin=True, socket=True, user=user).output._sock
|
exec_return = ""
|
||||||
if not cmd.endswith("\n"):
|
else:
|
||||||
cmd = cmd + "\n"
|
exec_return = exec_return.data.decode('utf-8')
|
||||||
socket.send(cmd.encode('utf-8'))
|
|
||||||
data = recv_socket_data(socket, timeout)
|
|
||||||
socket.close()
|
|
||||||
return data
|
|
||||||
|
|
||||||
except Exception as e:
|
if type == 'generic':
|
||||||
print("error - exec_cmd_container: %s" % str(e))
|
exec_details = await exec_obj.inspect()
|
||||||
traceback.print_exc(file=sys.stdout)
|
if exec_details["ExitCode"] == None or exec_details["ExitCode"] == 0:
|
||||||
|
res = {
|
||||||
def exec_run_handler(type, output):
|
"type": "success",
|
||||||
if type == 'generic':
|
"msg": "command completed successfully"
|
||||||
if output.exit_code == 0:
|
}
|
||||||
return jsonify(type='success', msg='command completed successfully')
|
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||||
else:
|
else:
|
||||||
return jsonify(type='danger', msg='command failed: ' + output.output.decode('utf-8'))
|
res = {
|
||||||
|
"type": "success",
|
||||||
|
"msg": "'command failed: " + exec_return
|
||||||
|
}
|
||||||
|
return Response(content=json.dumps(res, indent=4), media_type="application/json")
|
||||||
if type == 'utf8_text_only':
|
if type == 'utf8_text_only':
|
||||||
r = Response(response=output.output.decode('utf-8'), status=200, mimetype="text/plain")
|
return Response(content=exec_return, media_type="text/plain")
|
||||||
r.headers["Content-Type"] = "text/plain; charset=utf-8"
|
|
||||||
return r
|
|
||||||
|
|
||||||
class GracefulKiller:
|
async def get_host_stats(wait=5):
|
||||||
kill_now = False
|
global host_stats_isUpdating
|
||||||
def __init__(self):
|
|
||||||
signal.signal(signal.SIGINT, self.exit_gracefully)
|
|
||||||
signal.signal(signal.SIGTERM, self.exit_gracefully)
|
|
||||||
|
|
||||||
def exit_gracefully(self, signum, frame):
|
|
||||||
self.kill_now = True
|
|
||||||
|
|
||||||
def create_self_signed_cert():
|
|
||||||
process = subprocess.Popen(
|
|
||||||
"openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes -keyout /app/dockerapi_key.pem -out /app/dockerapi_cert.pem -subj /CN=dockerapi/O=mailcow -addext subjectAltName=DNS:dockerapi".split(),
|
|
||||||
stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell=False
|
|
||||||
)
|
|
||||||
process.wait()
|
|
||||||
|
|
||||||
def startFlaskAPI():
|
|
||||||
create_self_signed_cert()
|
|
||||||
try:
|
try:
|
||||||
ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
|
system_time = datetime.now()
|
||||||
ctx.check_hostname = False
|
host_stats = {
|
||||||
ctx.load_cert_chain(certfile='/app/dockerapi_cert.pem', keyfile='/app/dockerapi_key.pem')
|
"cpu": {
|
||||||
except:
|
"cores": psutil.cpu_count(),
|
||||||
print ("Cannot initialize TLS, retrying in 5s...")
|
"usage": psutil.cpu_percent()
|
||||||
time.sleep(5)
|
},
|
||||||
app.run(debug=False, host='0.0.0.0', port=443, threaded=True, ssl_context=ctx)
|
"memory": {
|
||||||
|
"total": psutil.virtual_memory().total,
|
||||||
|
"usage": psutil.virtual_memory().percent,
|
||||||
|
"swap": psutil.swap_memory()
|
||||||
|
},
|
||||||
|
"uptime": time.time() - psutil.boot_time(),
|
||||||
|
"system_time": system_time.strftime("%d.%m.%Y %H:%M:%S")
|
||||||
|
}
|
||||||
|
|
||||||
api.add_resource(containers_get, '/containers/json')
|
redis_client.set('host_stats', json.dumps(host_stats), ex=10)
|
||||||
api.add_resource(container_get, '/containers/<string:container_id>/json')
|
except Exception as e:
|
||||||
api.add_resource(container_post, '/containers/<string:container_id>/<string:post_action>')
|
res = {
|
||||||
|
"type": "danger",
|
||||||
|
"msg": str(e)
|
||||||
|
}
|
||||||
|
print(json.dumps(res, indent=4))
|
||||||
|
|
||||||
if __name__ == '__main__':
|
await asyncio.sleep(wait)
|
||||||
api_thread = Thread(target=startFlaskAPI)
|
host_stats_isUpdating = False
|
||||||
api_thread.daemon = True
|
|
||||||
api_thread.start()
|
|
||||||
killer = GracefulKiller()
|
async def get_container_stats(container_id, wait=5, stop=False):
|
||||||
while True:
|
global containerIds_to_update
|
||||||
time.sleep(1)
|
|
||||||
if killer.kill_now:
|
if container_id and container_id.isalnum():
|
||||||
break
|
try:
|
||||||
print ("Stopping dockerapi-mailcow")
|
for container in (await async_docker_client.containers.list()):
|
||||||
|
if container._id == container_id:
|
||||||
|
res = await container.stats(stream=False)
|
||||||
|
|
||||||
|
if redis_client.exists(container_id + '_stats'):
|
||||||
|
stats = json.loads(redis_client.get(container_id + '_stats'))
|
||||||
|
else:
|
||||||
|
stats = []
|
||||||
|
stats.append(res[0])
|
||||||
|
if len(stats) > 3:
|
||||||
|
del stats[0]
|
||||||
|
redis_client.set(container_id + '_stats', json.dumps(stats), ex=60)
|
||||||
|
except Exception as e:
|
||||||
|
res = {
|
||||||
|
"type": "danger",
|
||||||
|
"msg": str(e)
|
||||||
|
}
|
||||||
|
print(json.dumps(res, indent=4))
|
||||||
|
else:
|
||||||
|
res = {
|
||||||
|
"type": "danger",
|
||||||
|
"msg": "no or invalid id defined"
|
||||||
|
}
|
||||||
|
print(json.dumps(res, indent=4))
|
||||||
|
|
||||||
|
await asyncio.sleep(wait)
|
||||||
|
if stop == True:
|
||||||
|
# update task was called second time, stop
|
||||||
|
containerIds_to_update.remove(container_id)
|
||||||
|
else:
|
||||||
|
# call update task a second time
|
||||||
|
await get_container_stats(container_id, wait=0, stop=True)
|
||||||
|
|
||||||
|
|
||||||
|
if os.environ['REDIS_SLAVEOF_IP'] != "":
|
||||||
|
redis_client = redis.Redis(host=os.environ['REDIS_SLAVEOF_IP'], port=os.environ['REDIS_SLAVEOF_PORT'], db=0)
|
||||||
|
else:
|
||||||
|
redis_client = redis.Redis(host='redis-mailcow', port=6379, db=0)
|
||||||
|
|
||||||
|
async_docker_client = aiodocker.Docker(url='unix:///var/run/docker.sock')
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
FROM debian:buster-slim
|
FROM debian:bullseye-slim
|
||||||
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
|
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
|
||||||
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
ARG DOVECOT=2.3.17.1
|
ARG DOVECOT=2.3.19.1
|
||||||
ENV LC_ALL C
|
ENV LC_ALL C
|
||||||
ENV GOSU_VERSION 1.12
|
ENV GOSU_VERSION 1.14
|
||||||
|
|
||||||
# Add groups and users before installing Dovecot to not break compatibility
|
# Add groups and users before installing Dovecot to not break compatibility
|
||||||
RUN groupadd -g 5000 vmail \
|
RUN groupadd -g 5000 vmail \
|
||||||
@@ -89,7 +89,7 @@ RUN groupadd -g 5000 vmail \
|
|||||||
&& chmod +x /usr/local/bin/gosu \
|
&& chmod +x /usr/local/bin/gosu \
|
||||||
&& gosu nobody true \
|
&& gosu nobody true \
|
||||||
&& apt-key adv --fetch-keys https://repo.dovecot.org/DOVECOT-REPO-GPG \
|
&& apt-key adv --fetch-keys https://repo.dovecot.org/DOVECOT-REPO-GPG \
|
||||||
&& echo "deb https://repo.dovecot.org/ce-${DOVECOT}/debian/buster buster main" > /etc/apt/sources.list.d/dovecot.list \
|
&& echo "deb https://repo.dovecot.org/ce-${DOVECOT}/debian/bullseye bullseye main" > /etc/apt/sources.list.d/dovecot.list \
|
||||||
&& apt-get update \
|
&& apt-get update \
|
||||||
&& apt-get -y --no-install-recommends install \
|
&& apt-get -y --no-install-recommends install \
|
||||||
dovecot-lua \
|
dovecot-lua \
|
||||||
|
|||||||
@@ -307,6 +307,7 @@ namespace {
|
|||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
|
||||||
cat <<EOF > /etc/dovecot/sogo_trusted_ip.conf
|
cat <<EOF > /etc/dovecot/sogo_trusted_ip.conf
|
||||||
# Autogenerated by mailcow
|
# Autogenerated by mailcow
|
||||||
remote ${IPV4_NETWORK}.248 {
|
remote ${IPV4_NETWORK}.248 {
|
||||||
@@ -349,6 +350,14 @@ sievec /var/vmail/sieve/global_sieve_after.sieve
|
|||||||
sievec /usr/lib/dovecot/sieve/report-spam.sieve
|
sievec /usr/lib/dovecot/sieve/report-spam.sieve
|
||||||
sievec /usr/lib/dovecot/sieve/report-ham.sieve
|
sievec /usr/lib/dovecot/sieve/report-ham.sieve
|
||||||
|
|
||||||
|
for file in /var/vmail/*/*/sieve/*.sieve ; do
|
||||||
|
if [[ "$file" == "/var/vmail/*/*/sieve/*.sieve" ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
sievec "$file" "$(dirname "$file")/../.dovecot.svbin"
|
||||||
|
chown vmail:vmail "$(dirname "$file")/../.dovecot.svbin"
|
||||||
|
done
|
||||||
|
|
||||||
# Fix permissions
|
# Fix permissions
|
||||||
chown root:root /etc/dovecot/sql/*.conf
|
chown root:root /etc/dovecot/sql/*.conf
|
||||||
chown root:dovecot /etc/dovecot/sql/dovecot-dict-sql-sieve* /etc/dovecot/sql/dovecot-dict-sql-quota* /etc/dovecot/lua/passwd-verify.lua
|
chown root:dovecot /etc/dovecot/sql/dovecot-dict-sql-sieve* /etc/dovecot/sql/dovecot-dict-sql-quota* /etc/dovecot/lua/passwd-verify.lua
|
||||||
|
|||||||
+1181
-347
File diff suppressed because it is too large
Load Diff
@@ -50,7 +50,7 @@ try:
|
|||||||
def query_mysql(query, headers = True, update = False):
|
def query_mysql(query, headers = True, update = False):
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
cnx = mysql.connector.connect(unix_socket = '/var/run/mysqld/mysqld.sock', user=os.environ.get('DBUSER'), passwd=os.environ.get('DBPASS'), database=os.environ.get('DBNAME'), charset="utf8")
|
cnx = mysql.connector.connect(unix_socket = '/var/run/mysqld/mysqld.sock', user=os.environ.get('DBUSER'), passwd=os.environ.get('DBPASS'), database=os.environ.get('DBNAME'), charset="utf8mb4", collation="utf8mb4_general_ci")
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
print('%s - trying again...' % (ex))
|
print('%s - trying again...' % (ex))
|
||||||
time.sleep(3)
|
time.sleep(3)
|
||||||
@@ -161,9 +161,9 @@ try:
|
|||||||
attrs = json.loads(attrs.decode('utf-8'))
|
attrs = json.loads(attrs.decode('utf-8'))
|
||||||
if attrs['quarantine_notification'] not in ('hourly', 'daily', 'weekly'):
|
if attrs['quarantine_notification'] not in ('hourly', 'daily', 'weekly'):
|
||||||
continue
|
continue
|
||||||
if last_notification == 0 or (last_notification + time_trans[attrs['quarantine_notification']]) < time_now:
|
if last_notification == 0 or (last_notification + time_trans[attrs['quarantine_notification']]) <= time_now:
|
||||||
print("Notifying %s: Considering %d new items in quarantine (policy: %s)" % (record['rcpt'], record['counter'], attrs['quarantine_notification']))
|
print("Notifying %s: Considering %d new items in quarantine (policy: %s)" % (record['rcpt'], record['counter'], attrs['quarantine_notification']))
|
||||||
notify_rcpt(record['rcpt'], record['counter'], record['quarantine_acl'], attrs['quarantine_category'])
|
notify_rcpt(record['rcpt'], record['counter'], record['quarantine_acl'], attrs['quarantine_category'])
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
os.unlink(pidfile)
|
os.unlink(pidfile)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
@version: 3.19
|
@version: 3.28
|
||||||
@include "scl.conf"
|
@include "scl.conf"
|
||||||
options {
|
options {
|
||||||
chain_hostnames(off);
|
chain_hostnames(off);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
@version: 3.19
|
@version: 3.28
|
||||||
@include "scl.conf"
|
@include "scl.conf"
|
||||||
options {
|
options {
|
||||||
chain_hostnames(off);
|
chain_hostnames(off);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM alpine:3.15
|
FROM alpine:3.17
|
||||||
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
|
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
|
||||||
|
|
||||||
ENV XTABLES_LIBDIR /usr/lib/xtables
|
ENV XTABLES_LIBDIR /usr/lib/xtables
|
||||||
|
|||||||
@@ -94,12 +94,12 @@ def refreshF2bregex():
|
|||||||
f2bregex = {}
|
f2bregex = {}
|
||||||
f2bregex[1] = 'mailcow UI: Invalid password for .+ by ([0-9a-f\.:]+)'
|
f2bregex[1] = 'mailcow UI: Invalid password for .+ by ([0-9a-f\.:]+)'
|
||||||
f2bregex[2] = 'Rspamd UI: Invalid password by ([0-9a-f\.:]+)'
|
f2bregex[2] = 'Rspamd UI: Invalid password by ([0-9a-f\.:]+)'
|
||||||
f2bregex[3] = 'warning: .*\[([0-9a-f\.:]+)\]: SASL .+ authentication failed'
|
f2bregex[3] = 'warning: .*\[([0-9a-f\.:]+)\]: SASL .+ authentication failed: (?!.*Connection lost to authentication server).+'
|
||||||
f2bregex[4] = 'warning: non-SMTP command from .*\[([0-9a-f\.:]+)]:.+'
|
f2bregex[4] = 'warning: non-SMTP command from .*\[([0-9a-f\.:]+)]:.+'
|
||||||
f2bregex[5] = 'NOQUEUE: reject: RCPT from \[([0-9a-f\.:]+)].+Protocol error.+'
|
f2bregex[5] = 'NOQUEUE: reject: RCPT from \[([0-9a-f\.:]+)].+Protocol error.+'
|
||||||
f2bregex[6] = '-login: Disconnected \(auth failed, .+\): user=.*, method=.+, rip=([0-9a-f\.:]+),'
|
f2bregex[6] = '-login: Disconnected.+ \(auth failed, .+\): user=.*, method=.+, rip=([0-9a-f\.:]+),'
|
||||||
f2bregex[7] = '-login: Aborted login \(auth failed .+\): user=.+, rip=([0-9a-f\.:]+), lip.+'
|
f2bregex[7] = '-login: Aborted login.+ \(auth failed .+\): user=.+, rip=([0-9a-f\.:]+), lip.+'
|
||||||
f2bregex[8] = '-login: Aborted login \(tried to use disallowed .+\): user=.+, rip=([0-9a-f\.:]+), lip.+'
|
f2bregex[8] = '-login: Aborted login.+ \(tried to use disallowed .+\): user=.+, rip=([0-9a-f\.:]+), lip.+'
|
||||||
f2bregex[9] = 'SOGo.+ Login from \'([0-9a-f\.:]+)\' for user .+ might not have worked'
|
f2bregex[9] = 'SOGo.+ Login from \'([0-9a-f\.:]+)\' for user .+ might not have worked'
|
||||||
f2bregex[10] = '([0-9a-f\.:]+) \"GET \/SOGo\/.* HTTP.+\" 403 .+'
|
f2bregex[10] = '([0-9a-f\.:]+) \"GET \/SOGo\/.* HTTP.+\" 403 .+'
|
||||||
r.set('F2B_REGEX', json.dumps(f2bregex, ensure_ascii=False))
|
r.set('F2B_REGEX', json.dumps(f2bregex, ensure_ascii=False))
|
||||||
@@ -252,7 +252,7 @@ def permBan(net, unban=False):
|
|||||||
if rule not in chain.rules and not unban:
|
if rule not in chain.rules and not unban:
|
||||||
logCrit('Add host/network %s to blacklist' % net)
|
logCrit('Add host/network %s to blacklist' % net)
|
||||||
chain.insert_rule(rule)
|
chain.insert_rule(rule)
|
||||||
r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time())))
|
r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time())))
|
||||||
elif rule in chain.rules and unban:
|
elif rule in chain.rules and unban:
|
||||||
logCrit('Remove host/network %s from blacklist' % net)
|
logCrit('Remove host/network %s from blacklist' % net)
|
||||||
chain.delete_rule(rule)
|
chain.delete_rule(rule)
|
||||||
@@ -267,7 +267,7 @@ def permBan(net, unban=False):
|
|||||||
if rule not in chain.rules and not unban:
|
if rule not in chain.rules and not unban:
|
||||||
logCrit('Add host/network %s to blacklist' % net)
|
logCrit('Add host/network %s to blacklist' % net)
|
||||||
chain.insert_rule(rule)
|
chain.insert_rule(rule)
|
||||||
r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time())))
|
r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time())))
|
||||||
elif rule in chain.rules and unban:
|
elif rule in chain.rules and unban:
|
||||||
logCrit('Remove host/network %s from blacklist' % net)
|
logCrit('Remove host/network %s from blacklist' % net)
|
||||||
chain.delete_rule(rule)
|
chain.delete_rule(rule)
|
||||||
@@ -346,6 +346,8 @@ def snat4(snat_target):
|
|||||||
rule.dst = '!' + rule.src
|
rule.dst = '!' + rule.src
|
||||||
target = rule.create_target("SNAT")
|
target = rule.create_target("SNAT")
|
||||||
target.to_source = snat_target
|
target.to_source = snat_target
|
||||||
|
match = rule.create_match("comment")
|
||||||
|
match.comment = f'{int(round(time.time()))}'
|
||||||
return rule
|
return rule
|
||||||
|
|
||||||
while not quit_now:
|
while not quit_now:
|
||||||
@@ -356,19 +358,26 @@ def snat4(snat_target):
|
|||||||
table.refresh()
|
table.refresh()
|
||||||
chain = iptc.Chain(table, 'POSTROUTING')
|
chain = iptc.Chain(table, 'POSTROUTING')
|
||||||
table.autocommit = False
|
table.autocommit = False
|
||||||
if get_snat4_rule() not in chain.rules:
|
new_rule = get_snat4_rule()
|
||||||
logCrit('Added POSTROUTING rule for source network %s to SNAT target %s' % (get_snat4_rule().src, snat_target))
|
for position, rule in enumerate(chain.rules):
|
||||||
chain.insert_rule(get_snat4_rule())
|
match = all((
|
||||||
table.commit()
|
new_rule.get_src() == rule.get_src(),
|
||||||
else:
|
new_rule.get_dst() == rule.get_dst(),
|
||||||
for position, item in enumerate(chain.rules):
|
new_rule.target.parameters == rule.target.parameters,
|
||||||
if item == get_snat4_rule():
|
new_rule.target.name == rule.target.name
|
||||||
if position != 0:
|
))
|
||||||
chain.delete_rule(get_snat4_rule())
|
if position == 0:
|
||||||
table.commit()
|
if not match:
|
||||||
|
logInfo(f'Added POSTROUTING rule for source network {new_rule.src} to SNAT target {snat_target}')
|
||||||
|
chain.insert_rule(new_rule)
|
||||||
|
else:
|
||||||
|
if match:
|
||||||
|
logInfo(f'Remove rule for source network {new_rule.src} to SNAT target {snat_target} from POSTROUTING chain at position {position}')
|
||||||
|
chain.delete_rule(rule)
|
||||||
|
table.commit()
|
||||||
table.autocommit = True
|
table.autocommit = True
|
||||||
except:
|
except:
|
||||||
print('Error running SNAT4, retrying...')
|
print('Error running SNAT4, retrying...')
|
||||||
|
|
||||||
def snat6(snat_target):
|
def snat6(snat_target):
|
||||||
global lock
|
global lock
|
||||||
@@ -402,7 +411,7 @@ def snat6(snat_target):
|
|||||||
table.commit()
|
table.commit()
|
||||||
table.autocommit = True
|
table.autocommit = True
|
||||||
except:
|
except:
|
||||||
print('Error running SNAT6, retrying...')
|
print('Error running SNAT6, retrying...')
|
||||||
|
|
||||||
def autopurge():
|
def autopurge():
|
||||||
while not quit_now:
|
while not quit_now:
|
||||||
@@ -468,7 +477,7 @@ def whitelistUpdate():
|
|||||||
if Counter(new_whitelist) != Counter(WHITELIST):
|
if Counter(new_whitelist) != Counter(WHITELIST):
|
||||||
WHITELIST = new_whitelist
|
WHITELIST = new_whitelist
|
||||||
logInfo('Whitelist was changed, it has %s entries' % len(WHITELIST))
|
logInfo('Whitelist was changed, it has %s entries' % len(WHITELIST))
|
||||||
time.sleep(60.0 - ((time.time() - start_time) % 60.0))
|
time.sleep(60.0 - ((time.time() - start_time) % 60.0))
|
||||||
|
|
||||||
def blacklistUpdate():
|
def blacklistUpdate():
|
||||||
global quit_now
|
global quit_now
|
||||||
@@ -479,7 +488,7 @@ def blacklistUpdate():
|
|||||||
new_blacklist = []
|
new_blacklist = []
|
||||||
if list:
|
if list:
|
||||||
new_blacklist = genNetworkList(list)
|
new_blacklist = genNetworkList(list)
|
||||||
if Counter(new_blacklist) != Counter(BLACKLIST):
|
if Counter(new_blacklist) != Counter(BLACKLIST):
|
||||||
addban = set(new_blacklist).difference(BLACKLIST)
|
addban = set(new_blacklist).difference(BLACKLIST)
|
||||||
delban = set(BLACKLIST).difference(new_blacklist)
|
delban = set(BLACKLIST).difference(new_blacklist)
|
||||||
BLACKLIST = new_blacklist
|
BLACKLIST = new_blacklist
|
||||||
@@ -490,7 +499,7 @@ def blacklistUpdate():
|
|||||||
if delban:
|
if delban:
|
||||||
for net in delban:
|
for net in delban:
|
||||||
permBan(net=net, unban=True)
|
permBan(net=net, unban=True)
|
||||||
time.sleep(60.0 - ((time.time() - start_time) % 60.0))
|
time.sleep(60.0 - ((time.time() - start_time) % 60.0))
|
||||||
|
|
||||||
def initChain():
|
def initChain():
|
||||||
# Is called before threads start, no locking
|
# Is called before threads start, no locking
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM alpine:3.15
|
FROM alpine:3.17
|
||||||
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
|
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
@@ -8,9 +8,9 @@ RUN apk add --virtual .build-deps gcc musl-dev python3-dev libffi-dev openssl-de
|
|||||||
&& apk add --update --no-cache python3 py3-pip openssl tzdata libmagic \
|
&& apk add --update --no-cache python3 py3-pip openssl tzdata libmagic \
|
||||||
&& pip3 install --upgrade pip \
|
&& pip3 install --upgrade pip \
|
||||||
&& pip3 install --upgrade asyncio python-magic \
|
&& pip3 install --upgrade asyncio python-magic \
|
||||||
&& pip3 install --upgrade https://github.com/HeinleinSupport/oletools/archive/master.zip \
|
&& pip3 install --upgrade https://github.com/decalage2/oletools/archive/master.zip \
|
||||||
&& apk del .build-deps
|
&& apk del .build-deps
|
||||||
# && sed -i 's/decompress_stream(bytearray(compressed_code))/bytes2str(decompress_stream(bytearray(compressed_code)))/g' /usr/lib/python3.8/site-packages/oletools/olevba.py
|
# && sed -i 's/template_injection_detected = True/template_injection_detected = False/g' /usr/lib/python3.9/site-packages/oletools/olevba.py
|
||||||
|
|
||||||
ADD olefy.py /app/
|
ADD olefy.py /app/
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
FROM php:8.0-fpm-alpine3.14
|
FROM php:8.1-fpm-alpine3.17
|
||||||
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
|
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
|
||||||
|
|
||||||
ENV APCU_PECL 5.1.20
|
ENV APCU_PECL 5.1.22
|
||||||
ENV IMAGICK_PECL 3.5.1
|
ENV IMAGICK_PECL 3.7.0
|
||||||
# Mailparse is pulled from master branch
|
ENV MAILPARSE_PECL 3.1.4
|
||||||
#ENV MAILPARSE_PECL 3.0.2
|
ENV MEMCACHED_PECL 3.2.0
|
||||||
ENV MEMCACHED_PECL 3.1.5
|
ENV REDIS_PECL 5.3.7
|
||||||
ENV REDIS_PECL 5.3.4
|
ENV COMPOSER 2.4.4
|
||||||
|
|
||||||
RUN apk add -U --no-cache autoconf \
|
RUN apk add -U --no-cache autoconf \
|
||||||
aspell-dev \
|
aspell-dev \
|
||||||
@@ -18,6 +18,7 @@ RUN apk add -U --no-cache autoconf \
|
|||||||
freetype-dev \
|
freetype-dev \
|
||||||
g++ \
|
g++ \
|
||||||
git \
|
git \
|
||||||
|
gettext \
|
||||||
gettext-dev \
|
gettext-dev \
|
||||||
gmp-dev \
|
gmp-dev \
|
||||||
gnupg \
|
gnupg \
|
||||||
@@ -27,8 +28,11 @@ RUN apk add -U --no-cache autoconf \
|
|||||||
imagemagick-dev \
|
imagemagick-dev \
|
||||||
imap-dev \
|
imap-dev \
|
||||||
jq \
|
jq \
|
||||||
|
libavif \
|
||||||
|
libavif-dev \
|
||||||
libjpeg-turbo \
|
libjpeg-turbo \
|
||||||
libjpeg-turbo-dev \
|
libjpeg-turbo-dev \
|
||||||
|
libmemcached \
|
||||||
libmemcached-dev \
|
libmemcached-dev \
|
||||||
libpng \
|
libpng \
|
||||||
libpng-dev \
|
libpng-dev \
|
||||||
@@ -38,7 +42,9 @@ RUN apk add -U --no-cache autoconf \
|
|||||||
libtool \
|
libtool \
|
||||||
libwebp-dev \
|
libwebp-dev \
|
||||||
libxml2-dev \
|
libxml2-dev \
|
||||||
|
libxpm \
|
||||||
libxpm-dev \
|
libxpm-dev \
|
||||||
|
libzip \
|
||||||
libzip-dev \
|
libzip-dev \
|
||||||
make \
|
make \
|
||||||
mysql-client \
|
mysql-client \
|
||||||
@@ -49,22 +55,24 @@ RUN apk add -U --no-cache autoconf \
|
|||||||
samba-client \
|
samba-client \
|
||||||
zlib-dev \
|
zlib-dev \
|
||||||
tzdata \
|
tzdata \
|
||||||
&& git clone https://github.com/php/pecl-mail-mailparse \
|
&& pecl install mailparse-${MAILPARSE_PECL} \
|
||||||
&& cd pecl-mail-mailparse \
|
&& pecl install redis-${REDIS_PECL} \
|
||||||
&& pecl install package.xml \
|
&& pecl install memcached-${MEMCACHED_PECL} \
|
||||||
&& cd .. \
|
&& pecl install APCu-${APCU_PECL} \
|
||||||
&& rm -r pecl-mail-mailparse \
|
&& pecl install imagick-${IMAGICK_PECL} \
|
||||||
&& pecl install redis-${REDIS_PECL} memcached-${MEMCACHED_PECL} APCu-${APCU_PECL} imagick-${IMAGICK_PECL} \
|
|
||||||
&& docker-php-ext-enable apcu imagick memcached mailparse redis \
|
&& docker-php-ext-enable apcu imagick memcached mailparse redis \
|
||||||
&& pecl clear-cache \
|
&& pecl clear-cache \
|
||||||
&& docker-php-ext-configure intl \
|
&& docker-php-ext-configure intl \
|
||||||
&& docker-php-ext-configure exif \
|
&& docker-php-ext-configure exif \
|
||||||
&& docker-php-ext-configure gd --with-freetype=/usr/include/ \
|
&& docker-php-ext-configure gd --with-freetype=/usr/include/ \
|
||||||
--with-jpeg=/usr/include/ \
|
--with-jpeg=/usr/include/ \
|
||||||
|
--with-webp \
|
||||||
|
--with-xpm \
|
||||||
|
--with-avif \
|
||||||
&& docker-php-ext-install -j 4 exif gd gettext intl ldap opcache pcntl pdo pdo_mysql pspell soap sockets zip bcmath gmp \
|
&& docker-php-ext-install -j 4 exif gd gettext intl ldap opcache pcntl pdo pdo_mysql pspell soap sockets zip bcmath gmp \
|
||||||
&& docker-php-ext-configure imap --with-imap --with-imap-ssl \
|
&& docker-php-ext-configure imap --with-imap --with-imap-ssl \
|
||||||
&& docker-php-ext-install -j 4 imap \
|
&& docker-php-ext-install -j 4 imap \
|
||||||
&& curl --silent --show-error https://getcomposer.org/installer | php \
|
&& curl --silent --show-error https://getcomposer.org/installer | php -- --version=${COMPOSER} \
|
||||||
&& mv composer.phar /usr/local/bin/composer \
|
&& mv composer.phar /usr/local/bin/composer \
|
||||||
&& chmod +x /usr/local/bin/composer \
|
&& chmod +x /usr/local/bin/composer \
|
||||||
&& apk del --purge autoconf \
|
&& apk del --purge autoconf \
|
||||||
@@ -72,15 +80,21 @@ RUN apk add -U --no-cache autoconf \
|
|||||||
cyrus-sasl-dev \
|
cyrus-sasl-dev \
|
||||||
freetype-dev \
|
freetype-dev \
|
||||||
g++ \
|
g++ \
|
||||||
|
gettext-dev \
|
||||||
icu-dev \
|
icu-dev \
|
||||||
imagemagick-dev \
|
imagemagick-dev \
|
||||||
imap-dev \
|
imap-dev \
|
||||||
|
libavif-dev \
|
||||||
libjpeg-turbo-dev \
|
libjpeg-turbo-dev \
|
||||||
|
libmemcached-dev \
|
||||||
libpng-dev \
|
libpng-dev \
|
||||||
libressl-dev \
|
libressl-dev \
|
||||||
libwebp-dev \
|
libwebp-dev \
|
||||||
libxml2-dev \
|
libxml2-dev \
|
||||||
|
libxpm-dev \
|
||||||
|
libzip-dev \
|
||||||
make \
|
make \
|
||||||
|
openldap-dev \
|
||||||
pcre-dev \
|
pcre-dev \
|
||||||
zlib-dev
|
zlib-dev
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM debian:buster-slim
|
FROM debian:bullseye-slim
|
||||||
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
|
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
|
||||||
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
|||||||
@@ -323,7 +323,19 @@ hosts = unix:/var/run/mysqld/mysqld.sock
|
|||||||
dbname = ${DBNAME}
|
dbname = ${DBNAME}
|
||||||
# First select queries domain and alias_domain to determine if domains are active.
|
# First select queries domain and alias_domain to determine if domains are active.
|
||||||
query = SELECT goto FROM alias
|
query = SELECT goto FROM alias
|
||||||
WHERE address='%s'
|
WHERE id IN (
|
||||||
|
SELECT COALESCE (
|
||||||
|
(
|
||||||
|
SELECT id FROM alias
|
||||||
|
WHERE address='%s'
|
||||||
|
AND (active='1' OR active='2')
|
||||||
|
), (
|
||||||
|
SELECT id FROM alias
|
||||||
|
WHERE address='@%d'
|
||||||
|
AND (active='1' OR active='2')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
AND active='1'
|
AND active='1'
|
||||||
AND (domain IN
|
AND (domain IN
|
||||||
(SELECT domain FROM domain
|
(SELECT domain FROM domain
|
||||||
@@ -354,7 +366,7 @@ query = SELECT goto FROM alias
|
|||||||
WHERE alias_domain.alias_domain = '%d'
|
WHERE alias_domain.alias_domain = '%d'
|
||||||
AND mailbox.username = CONCAT('%u','@',alias_domain.target_domain)
|
AND mailbox.username = CONCAT('%u','@',alias_domain.target_domain)
|
||||||
AND (mailbox.active = '1' OR mailbox.active ='2')
|
AND (mailbox.active = '1' OR mailbox.active ='2')
|
||||||
AND alias_domain.active='1'
|
AND alias_domain.active='1';
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# MX based routing
|
# MX based routing
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
@version: 3.19
|
@version: 3.28
|
||||||
@include "scl.conf"
|
@include "scl.conf"
|
||||||
options {
|
options {
|
||||||
chain_hostnames(off);
|
chain_hostnames(off);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
@version: 3.19
|
@version: 3.28
|
||||||
@include "scl.conf"
|
@include "scl.conf"
|
||||||
options {
|
options {
|
||||||
chain_hostnames(off);
|
chain_hostnames(off);
|
||||||
|
|||||||
@@ -21,10 +21,12 @@ RUN apt-get update && apt-get install -y \
|
|||||||
&& apt-get clean \
|
&& apt-get clean \
|
||||||
&& mkdir -p /run/rspamd \
|
&& mkdir -p /run/rspamd \
|
||||||
&& chown _rspamd:_rspamd /run/rspamd \
|
&& chown _rspamd:_rspamd /run/rspamd \
|
||||||
&& echo 'alias ll="ls -la --color"' >> ~/.bashrc
|
&& echo 'alias ll="ls -la --color"' >> ~/.bashrc \
|
||||||
|
&& sed -i 's/#analysis_keyword_table > 0/analysis_cat_table.macro_exist == "M"/g' /usr/share/rspamd/lualib/lua_scanners/oletools.lua
|
||||||
|
|
||||||
COPY settings.conf /etc/rspamd/settings.conf
|
COPY settings.conf /etc/rspamd/settings.conf
|
||||||
COPY metadata_exporter.lua /usr/share/rspamd/plugins/metadata_exporter.lua
|
COPY metadata_exporter.lua /usr/share/rspamd/plugins/metadata_exporter.lua
|
||||||
|
COPY set_worker_password.sh /set_worker_password.sh
|
||||||
COPY docker-entrypoint.sh /docker-entrypoint.sh
|
COPY docker-entrypoint.sh /docker-entrypoint.sh
|
||||||
|
|
||||||
ENTRYPOINT ["/docker-entrypoint.sh"]
|
ENTRYPOINT ["/docker-entrypoint.sh"]
|
||||||
|
|||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
password_file='/etc/rspamd/override.d/worker-controller-password.inc'
|
||||||
|
password_hash=`/usr/bin/rspamadm pw -e -p $1`
|
||||||
|
|
||||||
|
echo 'enable_password = "'$password_hash'";' > $password_file
|
||||||
|
|
||||||
|
if grep -q "$password_hash" "$password_file"; then
|
||||||
|
echo "OK"
|
||||||
|
else
|
||||||
|
echo "ERROR"
|
||||||
|
fi
|
||||||
@@ -2,7 +2,7 @@ FROM debian:bullseye-slim
|
|||||||
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
|
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
|
||||||
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
ARG SOGO_DEBIAN_REPOSITORY=http://packages.inverse.ca/SOGo/nightly/5/debian/
|
ARG SOGO_DEBIAN_REPOSITORY=http://packages.sogo.nu/nightly/5/debian/
|
||||||
ENV LC_ALL C
|
ENV LC_ALL C
|
||||||
ENV GOSU_VERSION 1.14
|
ENV GOSU_VERSION 1.14
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ RUN echo "Building from repository $SOGO_DEBIAN_REPOSITORY" \
|
|||||||
&& gosu nobody true \
|
&& gosu nobody true \
|
||||||
&& mkdir /usr/share/doc/sogo \
|
&& mkdir /usr/share/doc/sogo \
|
||||||
&& touch /usr/share/doc/sogo/empty.sh \
|
&& touch /usr/share/doc/sogo/empty.sh \
|
||||||
&& apt-key adv --keyserver keyserver.ubuntu.com --recv-key 0x810273C4 \
|
&& apt-key adv --keyserver keys.openpgp.org --recv-key 74FFC6D72B925A34B5D356BDF8A27B36A6E2EAE9 \
|
||||||
&& echo "deb ${SOGO_DEBIAN_REPOSITORY} bullseye bullseye" > /etc/apt/sources.list.d/sogo.list \
|
&& echo "deb ${SOGO_DEBIAN_REPOSITORY} bullseye bullseye" > /etc/apt/sources.list.d/sogo.list \
|
||||||
&& apt-get update && apt-get install -y --no-install-recommends \
|
&& apt-get update && apt-get install -y --no-install-recommends \
|
||||||
sogo \
|
sogo \
|
||||||
@@ -52,4 +52,4 @@ RUN chmod +x /bootstrap-sogo.sh \
|
|||||||
|
|
||||||
ENTRYPOINT ["/docker-entrypoint.sh"]
|
ENTRYPOINT ["/docker-entrypoint.sh"]
|
||||||
|
|
||||||
CMD exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf
|
CMD exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf
|
||||||
@@ -142,6 +142,10 @@ cat <<EOF > /var/lib/sogo/GNUstep/Defaults/sogod.plist
|
|||||||
<string>mysql://${DBUSER}:${DBPASS}@%2Fvar%2Frun%2Fmysqld%2Fmysqld.sock/${DBNAME}/sogo_acl</string>
|
<string>mysql://${DBUSER}:${DBPASS}@%2Fvar%2Frun%2Fmysqld%2Fmysqld.sock/${DBNAME}/sogo_acl</string>
|
||||||
<key>SOGoIMAPServer</key>
|
<key>SOGoIMAPServer</key>
|
||||||
<string>imap://${IPV4_NETWORK}.250:143/?TLS=YES&tlsVerifyMode=none</string>
|
<string>imap://${IPV4_NETWORK}.250:143/?TLS=YES&tlsVerifyMode=none</string>
|
||||||
|
<key>SOGoSieveServer</key>
|
||||||
|
<string>sieve://${IPV4_NETWORK}.250:4190/?TLS=YES&tlsVerifyMode=none</string>
|
||||||
|
<key>SOGoSMTPServer</key>
|
||||||
|
<string>smtp://${IPV4_NETWORK}.253:588/?TLS=YES&tlsVerifyMode=none</string>
|
||||||
<key>SOGoTrustProxyAuthentication</key>
|
<key>SOGoTrustProxyAuthentication</key>
|
||||||
<string>YES</string>
|
<string>YES</string>
|
||||||
<key>SOGoEncryptionKey</key>
|
<key>SOGoEncryptionKey</key>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM alpine:3.15
|
FROM alpine:3.17
|
||||||
|
|
||||||
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
|
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM alpine:3.15
|
FROM alpine:3.17
|
||||||
LABEL maintainer "André Peters <andre.peters@servercow.de>"
|
LABEL maintainer "André Peters <andre.peters@servercow.de>"
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
|
|||||||
@@ -47,6 +47,14 @@ server {
|
|||||||
return 301 $client_req_scheme_nc://$host/remote.php/dav;
|
return 301 $client_req_scheme_nc://$host/remote.php/dav;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
location = /.well-known/webfinger {
|
||||||
|
return 301 $client_req_scheme_nc://$host/index.php/.well-known/webfinger;
|
||||||
|
}
|
||||||
|
|
||||||
|
location = /.well-known/nodeinfo {
|
||||||
|
return 301 $client_req_scheme_nc://$host/index.php/.well-known/nodeinfo;
|
||||||
|
}
|
||||||
|
|
||||||
location ^~ /.well-known/acme-challenge/ {
|
location ^~ /.well-known/acme-challenge/ {
|
||||||
default_type "text/plain";
|
default_type "text/plain";
|
||||||
root /web;
|
root /web;
|
||||||
|
|||||||
@@ -65,7 +65,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
location ~ ^/api/v1/(.*)$ {
|
location ~ ^/api/v1/(.*)$ {
|
||||||
try_files $uri $uri/ /json_api.php?query=$1;
|
try_files $uri $uri/ /json_api.php?query=$1&$args;
|
||||||
}
|
}
|
||||||
|
|
||||||
location ^~ /.well-known/acme-challenge/ {
|
location ^~ /.well-known/acme-challenge/ {
|
||||||
@@ -163,7 +163,9 @@
|
|||||||
proxy_connect_timeout 75;
|
proxy_connect_timeout 75;
|
||||||
proxy_send_timeout 3600;
|
proxy_send_timeout 3600;
|
||||||
proxy_read_timeout 3600;
|
proxy_read_timeout 3600;
|
||||||
proxy_buffers 64 256k;
|
proxy_buffer_size 128k;
|
||||||
|
proxy_buffers 64 512k;
|
||||||
|
proxy_busy_buffers_size 512k;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
proxy_set_header Host $http_host;
|
proxy_set_header Host $http_host;
|
||||||
@@ -197,6 +199,9 @@
|
|||||||
proxy_set_header x-webobjects-server-name $server_name;
|
proxy_set_header x-webobjects-server-name $server_name;
|
||||||
proxy_set_header x-webobjects-server-url $client_req_scheme://$http_host;
|
proxy_set_header x-webobjects-server-url $client_req_scheme://$http_host;
|
||||||
proxy_set_header x-webobjects-server-port $server_port;
|
proxy_set_header x-webobjects-server-port $server_port;
|
||||||
|
proxy_buffer_size 128k;
|
||||||
|
proxy_buffers 64 512k;
|
||||||
|
proxy_busy_buffers_size 512k;
|
||||||
proxy_send_timeout 3600;
|
proxy_send_timeout 3600;
|
||||||
proxy_read_timeout 3600;
|
proxy_read_timeout 3600;
|
||||||
client_body_buffer_size 128k;
|
client_body_buffer_size 128k;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
opcache.enable=1
|
opcache.enable=1
|
||||||
opcache.enable_cli=1
|
opcache.enable_cli=1
|
||||||
opcache.interned_strings_buffer=8
|
opcache.interned_strings_buffer=16
|
||||||
opcache.max_accelerated_files=10000
|
opcache.max_accelerated_files=10000
|
||||||
opcache.memory_consumption=128
|
opcache.memory_consumption=128
|
||||||
opcache.save_comments=1
|
opcache.save_comments=1
|
||||||
|
|||||||
@@ -1,53 +1,63 @@
|
|||||||
# Whitelist generated by Postwhite v3.4 on Sun Dec 15 21:16:19 CET 2019
|
# Whitelist generated by Postwhite v3.4 on Mon 21 Mar 2022 06:50:26 PM CET
|
||||||
# https://github.com/stevejenkins/postwhite/
|
# https://github.com/stevejenkins/postwhite/
|
||||||
# 1928 total rules
|
# 1898 total rules
|
||||||
2a00:1450:4000::/36 permit
|
2a00:1450:4000::/36 permit
|
||||||
2a01:111:f400::/48 permit
|
2a01:111:f400::/48 permit
|
||||||
2a01:111:f403::/48 permit
|
2a01:111:f403::/48 permit
|
||||||
|
2a01:4180:4050:0400::/64 permit
|
||||||
|
2a01:4180:4050:0800::/64 permit
|
||||||
|
2a01:4180:4051:0400::/64 permit
|
||||||
|
2a01:4180:4051:0800::/64 permit
|
||||||
2a02:a60:0:5::/64 permit
|
2a02:a60:0:5::/64 permit
|
||||||
2c0f:fb50:4000::/36 permit
|
2c0f:fb50:4000::/36 permit
|
||||||
3.93.157.0/24 permit
|
|
||||||
8.20.114.31 permit
|
8.20.114.31 permit
|
||||||
8.25.194.0/23 permit
|
8.25.194.0/23 permit
|
||||||
8.25.196.0/23 permit
|
8.25.196.0/23 permit
|
||||||
8.39.54.0/23 permit
|
8.39.54.0/23 permit
|
||||||
8.40.222.0/23 permit
|
8.40.222.0/23 permit
|
||||||
8.45.169.0/24 permit
|
|
||||||
12.130.86.238 permit
|
12.130.86.238 permit
|
||||||
|
13.70.32.43 permit
|
||||||
|
13.72.50.45 permit
|
||||||
|
13.74.143.28 permit
|
||||||
13.77.161.179 permit
|
13.77.161.179 permit
|
||||||
|
13.78.233.182 permit
|
||||||
|
13.92.31.129 permit
|
||||||
|
13.110.208.0/21 permit
|
||||||
|
13.110.216.0/22 permit
|
||||||
|
13.110.224.0/20 permit
|
||||||
13.111.0.0/16 permit
|
13.111.0.0/16 permit
|
||||||
13.111.0.0/22 permit
|
|
||||||
13.111.52.0/22 permit
|
|
||||||
13.111.63.0/24 permit
|
|
||||||
13.111.68.0/24 permit
|
|
||||||
13.111.72.0/22 permit
|
|
||||||
13.111.92.0/24 permit
|
|
||||||
13.111.111.0/24 permit
|
|
||||||
17.36.0.0/16 permit
|
|
||||||
17.41.0.0/16 permit
|
17.41.0.0/16 permit
|
||||||
|
17.57.155.0/24 permit
|
||||||
|
17.57.156.0/24 permit
|
||||||
17.58.0.0/16 permit
|
17.58.0.0/16 permit
|
||||||
17.110.0.0/15 permit
|
17.110.0.0/15 permit
|
||||||
17.111.110.0/23 permit
|
|
||||||
17.120.0.0/16 permit
|
|
||||||
17.133.0.0/16 permit
|
|
||||||
17.139.0.0/16 permit
|
|
||||||
17.142.0.0/15 permit
|
17.142.0.0/15 permit
|
||||||
17.151.1.0/24 permit
|
|
||||||
17.158.0.0/15 permit
|
|
||||||
17.162.0.0/15 permit
|
17.162.0.0/15 permit
|
||||||
17.164.0.0/16 permit
|
17.164.0.0/16 permit
|
||||||
17.171.37.0/24 permit
|
17.171.37.0/24 permit
|
||||||
17.172.0.0/16 permit
|
17.172.0.0/16 permit
|
||||||
17.179.168.0/23 permit
|
17.179.168.0/23 permit
|
||||||
18.194.95.56 permit
|
18.194.95.56 permit
|
||||||
18.208.124.128/25 permit
|
18.198.96.88 permit
|
||||||
|
20.47.149.138 permit
|
||||||
|
20.48.0.0/12 permit
|
||||||
|
20.52.52.2 permit
|
||||||
|
20.52.128.133 permit
|
||||||
|
20.63.210.192/28 permit
|
||||||
|
20.64.0.0/10 permit
|
||||||
|
20.94.180.64/28 permit
|
||||||
|
20.185.213.160/27 permit
|
||||||
|
20.185.213.224/27 permit
|
||||||
20.185.214.0/27 permit
|
20.185.214.0/27 permit
|
||||||
20.185.214.2 permit
|
20.185.214.2 permit
|
||||||
20.185.214.32/27 permit
|
20.185.214.32/27 permit
|
||||||
20.185.214.64/27 permit
|
20.185.214.64/27 permit
|
||||||
23.23.237.213 permit
|
20.192.0.0/10 permit
|
||||||
23.103.131.7 permit
|
23.100.85.1 permit
|
||||||
23.103.224.0/19 permit
|
23.103.224.0/19 permit
|
||||||
|
23.249.208.0/20 permit
|
||||||
|
23.251.224.0/19 permit
|
||||||
|
23.253.141.0/24 permit
|
||||||
23.253.182.0/23 permit
|
23.253.182.0/23 permit
|
||||||
23.253.182.103 permit
|
23.253.182.103 permit
|
||||||
23.253.183.145 permit
|
23.253.183.145 permit
|
||||||
@@ -68,11 +78,11 @@
|
|||||||
27.123.206.56/29 permit
|
27.123.206.56/29 permit
|
||||||
27.123.206.76/30 permit
|
27.123.206.76/30 permit
|
||||||
27.123.206.80/28 permit
|
27.123.206.80/28 permit
|
||||||
27.126.146.0/24 permit
|
34.194.25.167 permit
|
||||||
34.200.123.20 permit
|
34.194.144.120 permit
|
||||||
34.212.163.75 permit
|
34.212.163.75 permit
|
||||||
34.213.104.127 permit
|
|
||||||
34.225.212.172 permit
|
34.225.212.172 permit
|
||||||
|
34.247.168.44 permit
|
||||||
35.176.132.251 permit
|
35.176.132.251 permit
|
||||||
35.190.247.0/24 permit
|
35.190.247.0/24 permit
|
||||||
35.191.0.0/16 permit
|
35.191.0.0/16 permit
|
||||||
@@ -80,7 +90,10 @@
|
|||||||
37.218.248.47 permit
|
37.218.248.47 permit
|
||||||
37.218.249.47 permit
|
37.218.249.47 permit
|
||||||
37.218.251.62 permit
|
37.218.251.62 permit
|
||||||
|
39.156.163.64/29 permit
|
||||||
|
40.71.187.0/24 permit
|
||||||
40.76.4.15 permit
|
40.76.4.15 permit
|
||||||
|
40.77.102.222 permit
|
||||||
40.92.0.0/15 permit
|
40.92.0.0/15 permit
|
||||||
40.97.116.82 permit
|
40.97.116.82 permit
|
||||||
40.97.128.194 permit
|
40.97.128.194 permit
|
||||||
@@ -91,18 +104,20 @@
|
|||||||
40.97.161.50 permit
|
40.97.161.50 permit
|
||||||
40.97.164.146 permit
|
40.97.164.146 permit
|
||||||
40.107.0.0/16 permit
|
40.107.0.0/16 permit
|
||||||
|
40.112.65.63 permit
|
||||||
40.112.72.205 permit
|
40.112.72.205 permit
|
||||||
40.113.200.201 permit
|
40.113.200.201 permit
|
||||||
|
40.117.80.0/24 permit
|
||||||
|
40.121.71.46 permit
|
||||||
41.74.192.0/22 permit
|
41.74.192.0/22 permit
|
||||||
41.74.196.0/22 permit
|
41.74.196.0/22 permit
|
||||||
41.74.200.0/23 permit
|
41.74.200.0/23 permit
|
||||||
41.74.201.0/24 permit
|
|
||||||
41.74.204.0/23 permit
|
41.74.204.0/23 permit
|
||||||
41.74.205.0/24 permit
|
41.74.206.0/24 permit
|
||||||
42.159.163.81 permit
|
42.159.163.81 permit
|
||||||
42.159.163.82 permit
|
42.159.163.82 permit
|
||||||
42.159.163.83 permit
|
42.159.163.83 permit
|
||||||
46.19.168.0/23 permit
|
43.228.184.0/22 permit
|
||||||
46.226.48.0/21 permit
|
46.226.48.0/21 permit
|
||||||
46.228.36.37 permit
|
46.228.36.37 permit
|
||||||
46.228.36.38/31 permit
|
46.228.36.38/31 permit
|
||||||
@@ -160,26 +175,19 @@
|
|||||||
50.18.125.97 permit
|
50.18.125.97 permit
|
||||||
50.18.125.237 permit
|
50.18.125.237 permit
|
||||||
50.18.126.162 permit
|
50.18.126.162 permit
|
||||||
50.23.218.192/27 permit
|
|
||||||
50.31.32.0/19 permit
|
50.31.32.0/19 permit
|
||||||
50.31.36.197 permit
|
|
||||||
50.31.36.199 permit
|
|
||||||
50.31.36.205 permit
|
|
||||||
50.31.36.208 permit
|
|
||||||
50.31.36.213 permit
|
|
||||||
50.31.44.111 permit
|
|
||||||
50.31.57.54/31 permit
|
|
||||||
50.31.57.60 permit
|
|
||||||
50.31.57.61 permit
|
|
||||||
50.31.57.62 permit
|
|
||||||
50.31.60.1 permit
|
|
||||||
50.31.156.96/27 permit
|
50.31.156.96/27 permit
|
||||||
50.31.205.0/24 permit
|
50.31.205.0/24 permit
|
||||||
50.207.218.237 permit
|
|
||||||
51.4.71.62 permit
|
51.4.71.62 permit
|
||||||
|
51.4.72.0/24 permit
|
||||||
|
51.4.80.0/27 permit
|
||||||
|
51.5.72.0/24 permit
|
||||||
|
51.5.80.0/27 permit
|
||||||
|
51.137.58.21 permit
|
||||||
|
51.140.75.55 permit
|
||||||
|
51.144.100.179 permit
|
||||||
51.163.158.0/24 permit
|
51.163.158.0/24 permit
|
||||||
51.163.159.0/24 permit
|
51.163.159.21 permit
|
||||||
52.0.20.102 permit
|
|
||||||
52.5.230.59 permit
|
52.5.230.59 permit
|
||||||
52.27.5.72 permit
|
52.27.5.72 permit
|
||||||
52.27.28.47 permit
|
52.27.28.47 permit
|
||||||
@@ -190,10 +198,15 @@
|
|||||||
52.41.64.145 permit
|
52.41.64.145 permit
|
||||||
52.60.41.5 permit
|
52.60.41.5 permit
|
||||||
52.60.115.116 permit
|
52.60.115.116 permit
|
||||||
|
52.82.172.0/22 permit
|
||||||
|
52.94.124.0/28 permit
|
||||||
52.95.48.152/29 permit
|
52.95.48.152/29 permit
|
||||||
52.95.49.88/29 permit
|
52.95.49.88/29 permit
|
||||||
52.100.0.0/14 permit
|
52.100.0.0/14 permit
|
||||||
52.128.40.0/21 permit
|
52.119.213.144/28 permit
|
||||||
|
52.160.39.140 permit
|
||||||
|
52.165.175.144 permit
|
||||||
|
52.185.106.240/28 permit
|
||||||
52.200.59.0/24 permit
|
52.200.59.0/24 permit
|
||||||
52.205.61.79 permit
|
52.205.61.79 permit
|
||||||
52.207.191.216 permit
|
52.207.191.216 permit
|
||||||
@@ -201,26 +214,30 @@
|
|||||||
52.222.73.83 permit
|
52.222.73.83 permit
|
||||||
52.222.73.120 permit
|
52.222.73.120 permit
|
||||||
52.222.75.85 permit
|
52.222.75.85 permit
|
||||||
|
52.234.172.96/28 permit
|
||||||
|
52.236.28.240/28 permit
|
||||||
|
52.237.141.173 permit
|
||||||
|
52.244.206.214 permit
|
||||||
|
52.247.53.144 permit
|
||||||
|
52.250.107.196 permit
|
||||||
|
52.250.126.174 permit
|
||||||
|
52.251.55.143 permit
|
||||||
54.90.148.255 permit
|
54.90.148.255 permit
|
||||||
54.156.255.69 permit
|
54.156.255.69 permit
|
||||||
54.172.97.247 permit
|
54.172.97.247 permit
|
||||||
54.173.229.38 permit
|
|
||||||
54.174.52.0/24 permit
|
|
||||||
54.174.53.128/30 permit
|
|
||||||
54.174.57.0/24 permit
|
|
||||||
54.174.59.0/24 permit
|
|
||||||
54.174.60.0/23 permit
|
|
||||||
54.174.63.0/24 permit
|
|
||||||
54.186.193.102 permit
|
54.186.193.102 permit
|
||||||
|
54.191.223.5 permit
|
||||||
|
54.194.61.95 permit
|
||||||
|
54.195.113.45 permit
|
||||||
54.214.39.184 permit
|
54.214.39.184 permit
|
||||||
|
54.216.77.168 permit
|
||||||
54.240.0.0/18 permit
|
54.240.0.0/18 permit
|
||||||
54.240.40.0/25 permit
|
54.240.64.0/19 permit
|
||||||
54.240.56.128/26 permit
|
54.240.96.0/19 permit
|
||||||
54.240.63.0/25 permit
|
|
||||||
54.241.16.209 permit
|
54.241.16.209 permit
|
||||||
54.243.205.80 permit
|
|
||||||
54.244.54.130 permit
|
54.244.54.130 permit
|
||||||
54.244.242.0/24 permit
|
54.244.242.0/24 permit
|
||||||
|
54.246.232.180 permit
|
||||||
62.13.128.0/24 permit
|
62.13.128.0/24 permit
|
||||||
62.13.129.128/25 permit
|
62.13.129.128/25 permit
|
||||||
62.13.136.0/22 permit
|
62.13.136.0/22 permit
|
||||||
@@ -231,9 +248,9 @@
|
|||||||
62.13.152.0/23 permit
|
62.13.152.0/23 permit
|
||||||
62.17.146.128/26 permit
|
62.17.146.128/26 permit
|
||||||
62.140.7.0/24 permit
|
62.140.7.0/24 permit
|
||||||
62.140.10.0/24 permit
|
62.140.10.21 permit
|
||||||
|
63.32.13.159 permit
|
||||||
63.80.14.0/23 permit
|
63.80.14.0/23 permit
|
||||||
63.111.28.137 permit
|
|
||||||
63.128.21.0/24 permit
|
63.128.21.0/24 permit
|
||||||
63.143.57.128/25 permit
|
63.143.57.128/25 permit
|
||||||
63.143.59.128/25 permit
|
63.143.59.128/25 permit
|
||||||
@@ -241,9 +258,11 @@
|
|||||||
64.20.241.45 permit
|
64.20.241.45 permit
|
||||||
64.34.47.128/27 permit
|
64.34.47.128/27 permit
|
||||||
64.34.57.192/26 permit
|
64.34.57.192/26 permit
|
||||||
|
64.71.149.160/28 permit
|
||||||
64.79.155.0/24 permit
|
64.79.155.0/24 permit
|
||||||
64.79.155.192 permit
|
64.89.44.85 permit
|
||||||
64.89.45.192/30 permit
|
64.89.45.80 permit
|
||||||
|
64.89.45.194 permit
|
||||||
64.89.45.196 permit
|
64.89.45.196 permit
|
||||||
64.95.144.196 permit
|
64.95.144.196 permit
|
||||||
64.127.115.252 permit
|
64.127.115.252 permit
|
||||||
@@ -265,21 +284,21 @@
|
|||||||
64.207.219.7 permit
|
64.207.219.7 permit
|
||||||
64.207.219.8 permit
|
64.207.219.8 permit
|
||||||
64.207.219.9 permit
|
64.207.219.9 permit
|
||||||
64.207.219.10 permit
|
64.207.219.13 permit
|
||||||
64.207.219.11 permit
|
64.207.219.14 permit
|
||||||
64.207.219.12 permit
|
64.207.219.15 permit
|
||||||
64.207.219.71 permit
|
64.207.219.71 permit
|
||||||
64.207.219.72 permit
|
64.207.219.72 permit
|
||||||
64.207.219.73 permit
|
64.207.219.73 permit
|
||||||
64.207.219.74 permit
|
64.207.219.77 permit
|
||||||
64.207.219.75 permit
|
64.207.219.78 permit
|
||||||
64.207.219.76 permit
|
64.207.219.79 permit
|
||||||
64.207.219.135 permit
|
64.207.219.135 permit
|
||||||
64.207.219.136 permit
|
64.207.219.136 permit
|
||||||
64.207.219.137 permit
|
64.207.219.137 permit
|
||||||
64.207.219.138 permit
|
64.207.219.141 permit
|
||||||
64.207.219.139 permit
|
64.207.219.142 permit
|
||||||
64.207.219.140 permit
|
64.207.219.143 permit
|
||||||
64.233.160.0/19 permit
|
64.233.160.0/19 permit
|
||||||
65.38.115.76 permit
|
65.38.115.76 permit
|
||||||
65.38.115.84 permit
|
65.38.115.84 permit
|
||||||
@@ -288,7 +307,6 @@
|
|||||||
65.54.51.64/26 permit
|
65.54.51.64/26 permit
|
||||||
65.54.61.64/26 permit
|
65.54.61.64/26 permit
|
||||||
65.54.121.120/29 permit
|
65.54.121.120/29 permit
|
||||||
65.54.121.124/31 permit
|
|
||||||
65.54.190.0/24 permit
|
65.54.190.0/24 permit
|
||||||
65.54.241.0/24 permit
|
65.54.241.0/24 permit
|
||||||
65.55.29.77 permit
|
65.55.29.77 permit
|
||||||
@@ -298,7 +316,6 @@
|
|||||||
65.55.52.224/27 permit
|
65.55.52.224/27 permit
|
||||||
65.55.78.128/25 permit
|
65.55.78.128/25 permit
|
||||||
65.55.81.48/28 permit
|
65.55.81.48/28 permit
|
||||||
65.55.81.54/31 permit
|
|
||||||
65.55.90.0/24 permit
|
65.55.90.0/24 permit
|
||||||
65.55.94.0/25 permit
|
65.55.94.0/25 permit
|
||||||
65.55.111.0/24 permit
|
65.55.111.0/24 permit
|
||||||
@@ -325,9 +342,6 @@
|
|||||||
66.111.4.225 permit
|
66.111.4.225 permit
|
||||||
66.111.4.229 permit
|
66.111.4.229 permit
|
||||||
66.111.4.230 permit
|
66.111.4.230 permit
|
||||||
66.135.202.0/27 permit
|
|
||||||
66.135.215.0/24 permit
|
|
||||||
66.135.222.1 permit
|
|
||||||
66.162.193.226/31 permit
|
66.162.193.226/31 permit
|
||||||
66.163.184.0/21 permit
|
66.163.184.0/21 permit
|
||||||
66.163.184.0/24 permit
|
66.163.184.0/24 permit
|
||||||
@@ -358,7 +372,8 @@
|
|||||||
66.196.81.232/31 permit
|
66.196.81.232/31 permit
|
||||||
66.196.81.234 permit
|
66.196.81.234 permit
|
||||||
66.211.168.230/31 permit
|
66.211.168.230/31 permit
|
||||||
66.211.184.0/23 permit
|
66.211.170.86/31 permit
|
||||||
|
66.211.170.88/30 permit
|
||||||
66.218.74.64/30 permit
|
66.218.74.64/30 permit
|
||||||
66.218.74.68/31 permit
|
66.218.74.68/31 permit
|
||||||
66.218.75.112/30 permit
|
66.218.75.112/30 permit
|
||||||
@@ -420,9 +435,7 @@
|
|||||||
67.221.168.65 permit
|
67.221.168.65 permit
|
||||||
67.228.2.24/30 permit
|
67.228.2.24/30 permit
|
||||||
67.228.21.184/29 permit
|
67.228.21.184/29 permit
|
||||||
67.228.34.32/27 permit
|
|
||||||
67.228.37.4/30 permit
|
67.228.37.4/30 permit
|
||||||
67.228.50.54/31 permit
|
|
||||||
67.231.145.42 permit
|
67.231.145.42 permit
|
||||||
67.231.153.30 permit
|
67.231.153.30 permit
|
||||||
68.142.230.0/24 permit
|
68.142.230.0/24 permit
|
||||||
@@ -432,17 +445,6 @@
|
|||||||
68.142.230.72/30 permit
|
68.142.230.72/30 permit
|
||||||
68.142.230.76/31 permit
|
68.142.230.76/31 permit
|
||||||
68.142.230.78 permit
|
68.142.230.78 permit
|
||||||
68.232.131.164 permit
|
|
||||||
68.232.131.172 permit
|
|
||||||
68.232.131.183 permit
|
|
||||||
68.232.131.185 permit
|
|
||||||
68.232.143.44 permit
|
|
||||||
68.232.145.216 permit
|
|
||||||
68.232.148.56 permit
|
|
||||||
68.232.148.128 permit
|
|
||||||
68.232.148.138 permit
|
|
||||||
68.232.157.60 permit
|
|
||||||
68.232.157.143 permit
|
|
||||||
68.232.192.0/20 permit
|
68.232.192.0/20 permit
|
||||||
69.63.178.128/25 permit
|
69.63.178.128/25 permit
|
||||||
69.63.181.0/24 permit
|
69.63.181.0/24 permit
|
||||||
@@ -456,9 +458,9 @@
|
|||||||
69.171.232.0/24 permit
|
69.171.232.0/24 permit
|
||||||
69.171.244.0/23 permit
|
69.171.244.0/23 permit
|
||||||
70.37.151.128/25 permit
|
70.37.151.128/25 permit
|
||||||
|
70.42.149.0/24 permit
|
||||||
70.42.149.35 permit
|
70.42.149.35 permit
|
||||||
72.3.185.0/24 permit
|
72.3.185.0/24 permit
|
||||||
72.3.237.64/28 permit
|
|
||||||
72.14.192.0/18 permit
|
72.14.192.0/18 permit
|
||||||
72.21.192.0/19 permit
|
72.21.192.0/19 permit
|
||||||
72.21.217.142 permit
|
72.21.217.142 permit
|
||||||
@@ -523,8 +525,10 @@
|
|||||||
72.32.154.0/24 permit
|
72.32.154.0/24 permit
|
||||||
72.32.217.0/24 permit
|
72.32.217.0/24 permit
|
||||||
72.32.243.0/24 permit
|
72.32.243.0/24 permit
|
||||||
72.34.168.75 permit
|
|
||||||
72.34.168.76 permit
|
72.34.168.76 permit
|
||||||
|
72.34.168.80 permit
|
||||||
|
72.34.168.85 permit
|
||||||
|
72.34.168.86 permit
|
||||||
72.52.72.32/28 permit
|
72.52.72.32/28 permit
|
||||||
72.52.72.36 permit
|
72.52.72.36 permit
|
||||||
74.6.128.0/21 permit
|
74.6.128.0/21 permit
|
||||||
@@ -536,9 +540,6 @@
|
|||||||
74.6.133.0/24 permit
|
74.6.133.0/24 permit
|
||||||
74.6.134.0/24 permit
|
74.6.134.0/24 permit
|
||||||
74.6.135.0/24 permit
|
74.6.135.0/24 permit
|
||||||
74.63.63.115 permit
|
|
||||||
74.63.63.121 permit
|
|
||||||
74.63.194.126 permit
|
|
||||||
74.63.212.0/24 permit
|
74.63.212.0/24 permit
|
||||||
74.63.234.75 permit
|
74.63.234.75 permit
|
||||||
74.63.236.0/24 permit
|
74.63.236.0/24 permit
|
||||||
@@ -557,17 +558,9 @@
|
|||||||
74.112.67.243 permit
|
74.112.67.243 permit
|
||||||
74.125.0.0/16 permit
|
74.125.0.0/16 permit
|
||||||
74.202.227.40 permit
|
74.202.227.40 permit
|
||||||
74.208.4.192/26 permit
|
|
||||||
74.208.5.64/26 permit
|
|
||||||
74.208.122.0/26 permit
|
|
||||||
74.209.250.0/24 permit
|
74.209.250.0/24 permit
|
||||||
74.209.250.12 permit
|
74.209.250.12 permit
|
||||||
75.126.253.48 permit
|
76.223.176.0/20 permit
|
||||||
76.223.176.0/24 permit
|
|
||||||
76.223.180.0/23 permit
|
|
||||||
76.223.188.0/24 permit
|
|
||||||
76.223.189.0/24 permit
|
|
||||||
76.223.190.0/24 permit
|
|
||||||
77.238.176.0/22 permit
|
77.238.176.0/22 permit
|
||||||
77.238.176.0/24 permit
|
77.238.176.0/24 permit
|
||||||
77.238.177.0/24 permit
|
77.238.177.0/24 permit
|
||||||
@@ -590,13 +583,11 @@
|
|||||||
77.238.189.146/31 permit
|
77.238.189.146/31 permit
|
||||||
77.238.189.148/30 permit
|
77.238.189.148/30 permit
|
||||||
81.223.46.0/27 permit
|
81.223.46.0/27 permit
|
||||||
82.165.159.0/24 permit
|
|
||||||
82.165.159.0/26 permit
|
|
||||||
82.165.229.130 permit
|
|
||||||
82.165.230.22 permit
|
|
||||||
84.16.77.1 permit
|
84.16.77.1 permit
|
||||||
85.158.136.0/21 permit
|
85.158.136.0/21 permit
|
||||||
86.61.88.25 permit
|
86.61.88.25 permit
|
||||||
|
87.198.219.130 permit
|
||||||
|
87.198.219.153 permit
|
||||||
87.238.80.0/21 permit
|
87.238.80.0/21 permit
|
||||||
87.248.103.12 permit
|
87.248.103.12 permit
|
||||||
87.248.103.21 permit
|
87.248.103.21 permit
|
||||||
@@ -633,11 +624,9 @@
|
|||||||
87.248.117.201 permit
|
87.248.117.201 permit
|
||||||
87.248.117.202 permit
|
87.248.117.202 permit
|
||||||
87.248.117.205 permit
|
87.248.117.205 permit
|
||||||
|
87.252.219.254 permit
|
||||||
87.253.232.0/21 permit
|
87.253.232.0/21 permit
|
||||||
89.22.108.0/24 permit
|
89.22.108.0/24 permit
|
||||||
91.194.248.0/23 permit
|
|
||||||
91.211.240.0/22 permit
|
|
||||||
91.211.243.0/24 permit
|
|
||||||
91.220.42.0/24 permit
|
91.220.42.0/24 permit
|
||||||
94.236.119.0/26 permit
|
94.236.119.0/26 permit
|
||||||
94.245.112.0/27 permit
|
94.245.112.0/27 permit
|
||||||
@@ -649,7 +638,6 @@
|
|||||||
96.43.148.64/28 permit
|
96.43.148.64/28 permit
|
||||||
96.43.148.64/31 permit
|
96.43.148.64/31 permit
|
||||||
96.43.151.64/28 permit
|
96.43.151.64/28 permit
|
||||||
96.46.150.192/27 permit
|
|
||||||
98.136.44.181 permit
|
98.136.44.181 permit
|
||||||
98.136.44.182/31 permit
|
98.136.44.182/31 permit
|
||||||
98.136.44.184 permit
|
98.136.44.184 permit
|
||||||
@@ -1152,20 +1140,25 @@
|
|||||||
98.139.245.180/31 permit
|
98.139.245.180/31 permit
|
||||||
98.139.245.208/30 permit
|
98.139.245.208/30 permit
|
||||||
98.139.245.212/31 permit
|
98.139.245.212/31 permit
|
||||||
|
99.78.197.208/28 permit
|
||||||
|
103.2.140.0/22 permit
|
||||||
103.9.8.121 permit
|
103.9.8.121 permit
|
||||||
103.9.8.122 permit
|
103.9.8.122 permit
|
||||||
103.9.8.123 permit
|
103.9.8.123 permit
|
||||||
103.9.96.0/22 permit
|
103.9.96.0/22 permit
|
||||||
103.13.69.0/24 permit
|
103.13.69.0/24 permit
|
||||||
103.28.42.0/24 permit
|
103.47.204.0/22 permit
|
||||||
103.96.20.0/24 permit
|
103.96.21.0/24 permit
|
||||||
103.96.22.0/24 permit
|
103.96.23.0/24 permit
|
||||||
|
103.151.192.0/23 permit
|
||||||
103.237.104.0/22 permit
|
103.237.104.0/22 permit
|
||||||
104.43.243.237 permit
|
104.43.243.237 permit
|
||||||
104.47.0.0/17 permit
|
104.47.0.0/17 permit
|
||||||
104.130.96.0/28 permit
|
104.130.96.0/28 permit
|
||||||
104.130.122.0/23 permit
|
104.130.122.0/23 permit
|
||||||
|
104.214.25.77 permit
|
||||||
104.215.148.63 permit
|
104.215.148.63 permit
|
||||||
|
104.215.186.3 permit
|
||||||
104.245.209.192/26 permit
|
104.245.209.192/26 permit
|
||||||
106.10.144.64/27 permit
|
106.10.144.64/27 permit
|
||||||
106.10.144.100/31 permit
|
106.10.144.100/31 permit
|
||||||
@@ -1291,6 +1284,7 @@
|
|||||||
106.10.242.0/24 permit
|
106.10.242.0/24 permit
|
||||||
106.10.243.0/24 permit
|
106.10.243.0/24 permit
|
||||||
106.10.244.0/24 permit
|
106.10.244.0/24 permit
|
||||||
|
106.39.212.64/29 permit
|
||||||
106.50.16.0/28 permit
|
106.50.16.0/28 permit
|
||||||
108.174.0.0/24 permit
|
108.174.0.0/24 permit
|
||||||
108.174.0.215 permit
|
108.174.0.215 permit
|
||||||
@@ -1302,13 +1296,14 @@
|
|||||||
108.175.30.45 permit
|
108.175.30.45 permit
|
||||||
108.177.8.0/21 permit
|
108.177.8.0/21 permit
|
||||||
108.177.96.0/19 permit
|
108.177.96.0/19 permit
|
||||||
108.178.6.0/24 permit
|
|
||||||
109.237.142.0/24 permit
|
109.237.142.0/24 permit
|
||||||
111.221.23.128/25 permit
|
111.221.23.128/25 permit
|
||||||
111.221.26.0/27 permit
|
111.221.26.0/27 permit
|
||||||
111.221.66.0/25 permit
|
111.221.66.0/25 permit
|
||||||
111.221.69.128/25 permit
|
111.221.69.128/25 permit
|
||||||
111.221.112.0/21 permit
|
111.221.112.0/21 permit
|
||||||
|
112.19.199.64/29 permit
|
||||||
|
112.19.242.64/29 permit
|
||||||
116.214.12.0/24 permit
|
116.214.12.0/24 permit
|
||||||
116.214.12.47 permit
|
116.214.12.47 permit
|
||||||
116.214.12.48/31 permit
|
116.214.12.48/31 permit
|
||||||
@@ -1325,6 +1320,7 @@
|
|||||||
117.120.16.0/21 permit
|
117.120.16.0/21 permit
|
||||||
119.42.242.52/31 permit
|
119.42.242.52/31 permit
|
||||||
119.42.242.156 permit
|
119.42.242.156 permit
|
||||||
|
123.126.78.64/29 permit
|
||||||
124.47.150.0/24 permit
|
124.47.150.0/24 permit
|
||||||
124.47.189.0/24 permit
|
124.47.189.0/24 permit
|
||||||
124.108.96.0/24 permit
|
124.108.96.0/24 permit
|
||||||
@@ -1332,11 +1328,19 @@
|
|||||||
124.108.96.28/31 permit
|
124.108.96.28/31 permit
|
||||||
124.108.96.70/31 permit
|
124.108.96.70/31 permit
|
||||||
124.108.96.72/31 permit
|
124.108.96.72/31 permit
|
||||||
|
128.17.0.0/20 permit
|
||||||
|
128.17.64.0/20 permit
|
||||||
|
128.17.128.0/20 permit
|
||||||
|
128.17.192.0/20 permit
|
||||||
128.127.70.0/26 permit
|
128.127.70.0/26 permit
|
||||||
|
128.245.0.0/20 permit
|
||||||
|
128.245.64.0/20 permit
|
||||||
129.41.77.70 permit
|
129.41.77.70 permit
|
||||||
129.41.169.249 permit
|
129.41.169.249 permit
|
||||||
|
129.146.236.58 permit
|
||||||
|
129.153.194.228 permit
|
||||||
|
129.159.87.137 permit
|
||||||
130.61.9.72 permit
|
130.61.9.72 permit
|
||||||
130.61.68.235 permit
|
|
||||||
130.211.0.0/22 permit
|
130.211.0.0/22 permit
|
||||||
130.248.172.0/24 permit
|
130.248.172.0/24 permit
|
||||||
130.248.173.0/24 permit
|
130.248.173.0/24 permit
|
||||||
@@ -1345,8 +1349,10 @@
|
|||||||
131.253.121.0/26 permit
|
131.253.121.0/26 permit
|
||||||
131.253.121.20 permit
|
131.253.121.20 permit
|
||||||
131.253.121.52 permit
|
131.253.121.52 permit
|
||||||
132.145.11.129 permit
|
|
||||||
132.145.13.209 permit
|
132.145.13.209 permit
|
||||||
|
132.226.26.225 permit
|
||||||
|
132.226.49.32 permit
|
||||||
|
132.226.56.24 permit
|
||||||
134.170.27.8 permit
|
134.170.27.8 permit
|
||||||
134.170.113.0/26 permit
|
134.170.113.0/26 permit
|
||||||
134.170.141.64/26 permit
|
134.170.141.64/26 permit
|
||||||
@@ -1356,21 +1362,27 @@
|
|||||||
135.84.82.0/24 permit
|
135.84.82.0/24 permit
|
||||||
135.84.216.0/22 permit
|
135.84.216.0/22 permit
|
||||||
136.143.182.0/23 permit
|
136.143.182.0/23 permit
|
||||||
136.143.188.0/23 permit
|
136.143.184.0/24 permit
|
||||||
|
136.143.188.0/24 permit
|
||||||
136.147.128.0/20 permit
|
136.147.128.0/20 permit
|
||||||
136.147.135.0/24 permit
|
136.147.135.0/24 permit
|
||||||
136.147.176.0/20 permit
|
136.147.176.0/20 permit
|
||||||
136.147.176.0/24 permit
|
136.147.176.0/24 permit
|
||||||
136.147.182.0/24 permit
|
136.147.182.0/24 permit
|
||||||
|
138.91.172.26 permit
|
||||||
139.60.152.0/22 permit
|
139.60.152.0/22 permit
|
||||||
139.178.64.159 permit
|
139.178.64.159 permit
|
||||||
139.178.64.195 permit
|
139.178.64.195 permit
|
||||||
139.180.17.0/24 permit
|
|
||||||
141.193.32.0/23 permit
|
141.193.32.0/23 permit
|
||||||
|
143.55.224.0/21 permit
|
||||||
|
143.55.232.0/22 permit
|
||||||
|
143.55.236.0/22 permit
|
||||||
|
144.178.36.0/24 permit
|
||||||
|
144.178.38.0/24 permit
|
||||||
146.20.112.0/26 permit
|
146.20.112.0/26 permit
|
||||||
146.20.113.0/24 permit
|
146.20.113.0/24 permit
|
||||||
146.20.191.0/24 permit
|
146.20.191.0/24 permit
|
||||||
146.88.28.0/24 permit
|
146.20.215.0/24 permit
|
||||||
146.101.78.0/24 permit
|
146.101.78.0/24 permit
|
||||||
147.75.65.173 permit
|
147.75.65.173 permit
|
||||||
147.75.65.174 permit
|
147.75.65.174 permit
|
||||||
@@ -1384,10 +1396,7 @@
|
|||||||
148.105.0.14 permit
|
148.105.0.14 permit
|
||||||
148.105.8.0/21 permit
|
148.105.8.0/21 permit
|
||||||
149.72.0.0/16 permit
|
149.72.0.0/16 permit
|
||||||
151.101.1.140 permit
|
152.67.105.195 permit
|
||||||
151.101.65.140 permit
|
|
||||||
151.101.129.140 permit
|
|
||||||
151.101.193.140 permit
|
|
||||||
157.55.0.192/26 permit
|
157.55.0.192/26 permit
|
||||||
157.55.1.128/26 permit
|
157.55.1.128/26 permit
|
||||||
157.55.2.0/25 permit
|
157.55.2.0/25 permit
|
||||||
@@ -1397,6 +1406,7 @@
|
|||||||
157.55.61.0/24 permit
|
157.55.61.0/24 permit
|
||||||
157.55.157.128/25 permit
|
157.55.157.128/25 permit
|
||||||
157.55.225.0/25 permit
|
157.55.225.0/25 permit
|
||||||
|
157.55.254.216 permit
|
||||||
157.56.24.0/25 permit
|
157.56.24.0/25 permit
|
||||||
157.56.120.128/26 permit
|
157.56.120.128/26 permit
|
||||||
157.56.232.0/21 permit
|
157.56.232.0/21 permit
|
||||||
@@ -1405,21 +1415,26 @@
|
|||||||
157.58.196.96/29 permit
|
157.58.196.96/29 permit
|
||||||
157.58.249.3 permit
|
157.58.249.3 permit
|
||||||
157.151.208.65 permit
|
157.151.208.65 permit
|
||||||
158.247.16.0/20 permit
|
157.255.1.64/29 permit
|
||||||
|
159.92.157.0/24 permit
|
||||||
|
159.92.158.0/24 permit
|
||||||
|
159.92.159.0/24 permit
|
||||||
|
159.92.160.0/24 permit
|
||||||
|
159.92.161.0/24 permit
|
||||||
|
159.92.162.0/24 permit
|
||||||
|
159.135.132.128/25 permit
|
||||||
|
159.135.140.80/29 permit
|
||||||
159.135.224.0/20 permit
|
159.135.224.0/20 permit
|
||||||
161.38.192.0/22 permit
|
159.183.0.0/16 permit
|
||||||
161.38.196.0/22 permit
|
161.38.192.0/20 permit
|
||||||
161.71.32.0/21 permit
|
161.38.204.0/22 permit
|
||||||
|
161.71.32.0/19 permit
|
||||||
|
161.71.64.0/20 permit
|
||||||
162.208.119.181 permit
|
162.208.119.181 permit
|
||||||
162.247.216.0/22 permit
|
162.247.216.0/22 permit
|
||||||
162.248.184.121 permit
|
163.47.180.0/23 permit
|
||||||
162.248.184.122 permit
|
|
||||||
162.248.185.121 permit
|
|
||||||
162.248.185.122 permit
|
|
||||||
162.248.186.121 permit
|
|
||||||
162.248.186.122 permit
|
|
||||||
163.47.180.0/22 permit
|
|
||||||
163.114.130.16 permit
|
163.114.130.16 permit
|
||||||
|
163.114.132.120 permit
|
||||||
166.78.68.0/22 permit
|
166.78.68.0/22 permit
|
||||||
166.78.68.221 permit
|
166.78.68.221 permit
|
||||||
166.78.69.146 permit
|
166.78.69.146 permit
|
||||||
@@ -1427,16 +1442,7 @@
|
|||||||
166.78.69.170 permit
|
166.78.69.170 permit
|
||||||
166.78.71.131 permit
|
166.78.71.131 permit
|
||||||
167.89.0.0/17 permit
|
167.89.0.0/17 permit
|
||||||
167.89.2.4 permit
|
|
||||||
167.89.22.44 permit
|
|
||||||
167.89.25.84 permit
|
|
||||||
167.89.31.192/29 permit
|
|
||||||
167.89.32.5 permit
|
|
||||||
167.89.32.50 permit
|
|
||||||
167.89.46.159 permit
|
167.89.46.159 permit
|
||||||
167.89.46.185 permit
|
|
||||||
167.89.60.95 permit
|
|
||||||
167.89.62.118 permit
|
|
||||||
167.89.64.9 permit
|
167.89.64.9 permit
|
||||||
167.89.65.0 permit
|
167.89.65.0 permit
|
||||||
167.89.65.53 permit
|
167.89.65.53 permit
|
||||||
@@ -1448,22 +1454,15 @@
|
|||||||
167.89.75.164 permit
|
167.89.75.164 permit
|
||||||
167.89.101.2 permit
|
167.89.101.2 permit
|
||||||
167.89.101.192/28 permit
|
167.89.101.192/28 permit
|
||||||
167.89.107.125 permit
|
|
||||||
167.89.107.127 permit
|
|
||||||
167.89.107.129 permit
|
|
||||||
167.89.107.136 permit
|
|
||||||
167.216.129.170 permit
|
|
||||||
167.216.129.182/31 permit
|
|
||||||
167.216.129.184/29 permit
|
|
||||||
167.216.129.192/29 permit
|
|
||||||
167.216.129.200 permit
|
|
||||||
167.216.129.205 permit
|
|
||||||
167.216.129.206/31 permit
|
|
||||||
167.216.129.208/31 permit
|
|
||||||
167.216.129.210 permit
|
167.216.129.210 permit
|
||||||
|
167.216.131.180 permit
|
||||||
167.220.67.232/29 permit
|
167.220.67.232/29 permit
|
||||||
167.220.67.238 permit
|
167.220.67.238 permit
|
||||||
|
168.138.5.36 permit
|
||||||
168.245.0.0/17 permit
|
168.245.0.0/17 permit
|
||||||
|
170.10.68.0/22 permit
|
||||||
|
170.10.129.0/24 permit
|
||||||
|
170.10.133.0/24 permit
|
||||||
172.217.0.0/19 permit
|
172.217.0.0/19 permit
|
||||||
172.217.32.0/20 permit
|
172.217.32.0/20 permit
|
||||||
172.217.128.0/19 permit
|
172.217.128.0/19 permit
|
||||||
@@ -1473,8 +1472,6 @@
|
|||||||
172.253.112.0/20 permit
|
172.253.112.0/20 permit
|
||||||
173.0.84.224/27 permit
|
173.0.84.224/27 permit
|
||||||
173.0.94.244/30 permit
|
173.0.94.244/30 permit
|
||||||
173.193.132.134/31 permit
|
|
||||||
173.193.210.32/27 permit
|
|
||||||
173.194.0.0/16 permit
|
173.194.0.0/16 permit
|
||||||
173.203.79.182 permit
|
173.203.79.182 permit
|
||||||
173.203.81.39 permit
|
173.203.81.39 permit
|
||||||
@@ -1482,7 +1479,6 @@
|
|||||||
173.224.160.188 permit
|
173.224.160.188 permit
|
||||||
173.224.161.128/25 permit
|
173.224.161.128/25 permit
|
||||||
173.228.155.0/24 permit
|
173.228.155.0/24 permit
|
||||||
173.236.20.0/24 permit
|
|
||||||
174.36.84.8/29 permit
|
174.36.84.8/29 permit
|
||||||
174.36.84.16/29 permit
|
174.36.84.16/29 permit
|
||||||
174.36.84.32/29 permit
|
174.36.84.32/29 permit
|
||||||
@@ -1494,30 +1490,25 @@
|
|||||||
174.36.114.148/30 permit
|
174.36.114.148/30 permit
|
||||||
174.36.114.152/29 permit
|
174.36.114.152/29 permit
|
||||||
174.37.67.28/30 permit
|
174.37.67.28/30 permit
|
||||||
174.37.226.64/27 permit
|
|
||||||
174.129.194.241 permit
|
|
||||||
174.129.203.189 permit
|
174.129.203.189 permit
|
||||||
174.137.46.0/24 permit
|
|
||||||
176.32.105.0/24 permit
|
176.32.105.0/24 permit
|
||||||
176.32.127.0/24 permit
|
176.32.127.0/24 permit
|
||||||
178.236.10.128/26 permit
|
178.236.10.128/26 permit
|
||||||
180.189.28.0/24 permit
|
180.189.28.0/24 permit
|
||||||
182.50.76.0/22 permit
|
182.50.76.0/22 permit
|
||||||
182.50.78.64/28 permit
|
182.50.78.64/28 permit
|
||||||
184.173.105.0/24 permit
|
183.240.219.64/29 permit
|
||||||
184.173.153.0/24 permit
|
|
||||||
185.4.120.0/24 permit
|
|
||||||
185.4.122.0/24 permit
|
|
||||||
185.12.80.0/22 permit
|
185.12.80.0/22 permit
|
||||||
185.28.196.0/22 permit
|
185.28.196.0/22 permit
|
||||||
185.58.84.0/24 permit
|
185.58.84.93 permit
|
||||||
185.58.87.0/24 permit
|
185.58.85.0/24 permit
|
||||||
|
185.58.86.0/24 permit
|
||||||
185.72.128.75 permit
|
185.72.128.75 permit
|
||||||
185.72.128.76 permit
|
185.72.128.76 permit
|
||||||
|
185.72.128.80 permit
|
||||||
185.80.93.204 permit
|
185.80.93.204 permit
|
||||||
185.80.93.227 permit
|
185.80.93.227 permit
|
||||||
185.80.95.31 permit
|
185.80.95.31 permit
|
||||||
185.90.20.0/22 permit
|
|
||||||
185.189.236.0/22 permit
|
185.189.236.0/22 permit
|
||||||
185.211.120.0/22 permit
|
185.211.120.0/22 permit
|
||||||
185.250.236.0/22 permit
|
185.250.236.0/22 permit
|
||||||
@@ -1577,7 +1568,6 @@
|
|||||||
192.64.236.0/24 permit
|
192.64.236.0/24 permit
|
||||||
192.64.237.0/24 permit
|
192.64.237.0/24 permit
|
||||||
192.64.238.0/24 permit
|
192.64.238.0/24 permit
|
||||||
192.92.97.0/24 permit
|
|
||||||
192.161.144.0/20 permit
|
192.161.144.0/20 permit
|
||||||
192.162.87.0/24 permit
|
192.162.87.0/24 permit
|
||||||
192.237.158.0/23 permit
|
192.237.158.0/23 permit
|
||||||
@@ -1589,37 +1579,34 @@
|
|||||||
192.254.113.10 permit
|
192.254.113.10 permit
|
||||||
192.254.113.101 permit
|
192.254.113.101 permit
|
||||||
192.254.114.176 permit
|
192.254.114.176 permit
|
||||||
192.254.115.72 permit
|
|
||||||
192.254.118.63 permit
|
192.254.118.63 permit
|
||||||
192.254.127.96/27 permit
|
193.7.206.0/25 permit
|
||||||
|
193.7.207.0/25 permit
|
||||||
193.109.254.0/23 permit
|
193.109.254.0/23 permit
|
||||||
194.64.234.128/27 permit
|
193.122.128.100 permit
|
||||||
194.64.234.129 permit
|
194.64.234.129 permit
|
||||||
|
194.104.109.0/24 permit
|
||||||
|
194.104.111.0/24 permit
|
||||||
194.106.220.0/23 permit
|
194.106.220.0/23 permit
|
||||||
194.113.24.0/22 permit
|
|
||||||
194.154.193.192/27 permit
|
194.154.193.192/27 permit
|
||||||
195.54.172.0/23 permit
|
|
||||||
195.130.217.0/24 permit
|
195.130.217.0/24 permit
|
||||||
|
195.234.109.226 permit
|
||||||
195.245.230.0/23 permit
|
195.245.230.0/23 permit
|
||||||
198.2.128.0/18 permit
|
198.2.128.0/18 permit
|
||||||
198.2.128.0/24 permit
|
198.2.128.0/24 permit
|
||||||
198.2.132.0/22 permit
|
198.2.132.0/22 permit
|
||||||
198.2.136.0/23 permit
|
198.2.136.0/23 permit
|
||||||
|
198.2.145.0/24 permit
|
||||||
198.2.177.0/24 permit
|
198.2.177.0/24 permit
|
||||||
198.2.178.0/24 permit
|
198.2.178.0/23 permit
|
||||||
198.2.179.0/24 permit
|
|
||||||
198.2.180.0/24 permit
|
198.2.180.0/24 permit
|
||||||
198.2.186.0/23 permit
|
198.2.186.0/23 permit
|
||||||
198.21.0.0/21 permit
|
198.21.0.0/21 permit
|
||||||
198.21.3.166 permit
|
|
||||||
198.21.4.224 permit
|
|
||||||
198.37.144.0/20 permit
|
198.37.144.0/20 permit
|
||||||
198.37.145.250 permit
|
198.37.152.186 permit
|
||||||
198.37.146.118/31 permit
|
|
||||||
198.37.149.128 permit
|
|
||||||
198.37.151.26 permit
|
|
||||||
198.61.254.0/23 permit
|
198.61.254.0/23 permit
|
||||||
198.61.254.231 permit
|
198.61.254.231 permit
|
||||||
|
198.74.56.28 permit
|
||||||
198.178.234.57 permit
|
198.178.234.57 permit
|
||||||
198.245.80.0/20 permit
|
198.245.80.0/20 permit
|
||||||
198.245.81.0/24 permit
|
198.245.81.0/24 permit
|
||||||
@@ -1636,18 +1623,15 @@
|
|||||||
199.122.120.0/21 permit
|
199.122.120.0/21 permit
|
||||||
199.122.123.0/24 permit
|
199.122.123.0/24 permit
|
||||||
199.127.232.0/22 permit
|
199.127.232.0/22 permit
|
||||||
199.201.64.23 permit
|
|
||||||
199.201.65.23 permit
|
|
||||||
199.255.192.0/22 permit
|
199.255.192.0/22 permit
|
||||||
202.129.242.0/23 permit
|
202.129.242.0/23 permit
|
||||||
202.165.102.47 permit
|
202.165.102.47 permit
|
||||||
202.177.148.100 permit
|
202.177.148.100 permit
|
||||||
202.177.148.110 permit
|
202.177.148.110 permit
|
||||||
|
203.31.36.0/22 permit
|
||||||
203.32.4.25 permit
|
203.32.4.25 permit
|
||||||
203.55.21.0/24 permit
|
|
||||||
203.81.17.0/24 permit
|
203.81.17.0/24 permit
|
||||||
203.122.32.250 permit
|
203.122.32.250 permit
|
||||||
203.145.57.160/27 permit
|
|
||||||
203.188.194.32 permit
|
203.188.194.32 permit
|
||||||
203.188.194.151 permit
|
203.188.194.151 permit
|
||||||
203.188.194.203 permit
|
203.188.194.203 permit
|
||||||
@@ -1680,32 +1664,30 @@
|
|||||||
203.188.201.12/30 permit
|
203.188.201.12/30 permit
|
||||||
203.209.230.75 permit
|
203.209.230.75 permit
|
||||||
203.209.230.76/31 permit
|
203.209.230.76/31 permit
|
||||||
204.2.193.0/29 permit
|
|
||||||
204.11.168.0/21 permit
|
204.11.168.0/21 permit
|
||||||
204.13.11.48/29 permit
|
204.13.11.48/29 permit
|
||||||
204.13.11.48/30 permit
|
|
||||||
204.14.232.0/21 permit
|
204.14.232.0/21 permit
|
||||||
204.14.232.64/28 permit
|
204.14.232.64/28 permit
|
||||||
204.14.234.64/28 permit
|
204.14.234.64/28 permit
|
||||||
204.29.186.0/23 permit
|
204.29.186.0/23 permit
|
||||||
204.75.142.0/24 permit
|
|
||||||
204.79.197.212 permit
|
204.79.197.212 permit
|
||||||
204.92.114.187 permit
|
204.92.114.187 permit
|
||||||
204.92.114.203 permit
|
204.92.114.203 permit
|
||||||
204.92.114.204/31 permit
|
204.92.114.204/31 permit
|
||||||
204.141.32.0/23 permit
|
204.141.32.0/23 permit
|
||||||
204.141.42.0/23 permit
|
204.141.42.0/23 permit
|
||||||
204.153.120.0/23 permit
|
204.153.121.0/24 permit
|
||||||
|
204.232.168.0/24 permit
|
||||||
205.139.110.0/24 permit
|
205.139.110.0/24 permit
|
||||||
205.139.111.0/24 permit
|
|
||||||
205.201.128.0/20 permit
|
205.201.128.0/20 permit
|
||||||
205.201.131.128/25 permit
|
205.201.131.128/25 permit
|
||||||
205.201.134.128/25 permit
|
205.201.134.128/25 permit
|
||||||
205.201.136.0/23 permit
|
205.201.136.0/23 permit
|
||||||
205.201.137.229 permit
|
|
||||||
205.201.139.0/24 permit
|
205.201.139.0/24 permit
|
||||||
205.207.104.0/22 permit
|
205.207.104.0/22 permit
|
||||||
205.207.104.108 permit
|
205.207.104.108 permit
|
||||||
|
205.220.167.17 permit
|
||||||
|
205.220.179.17 permit
|
||||||
205.251.233.32 permit
|
205.251.233.32 permit
|
||||||
205.251.233.36 permit
|
205.251.233.36 permit
|
||||||
206.25.247.143 permit
|
206.25.247.143 permit
|
||||||
@@ -1727,6 +1709,8 @@
|
|||||||
207.46.132.128/27 permit
|
207.46.132.128/27 permit
|
||||||
207.46.198.0/25 permit
|
207.46.198.0/25 permit
|
||||||
207.46.200.0/27 permit
|
207.46.200.0/27 permit
|
||||||
|
207.46.225.107 permit
|
||||||
|
207.58.147.64/28 permit
|
||||||
207.67.38.0/24 permit
|
207.67.38.0/24 permit
|
||||||
207.67.98.192/27 permit
|
207.67.98.192/27 permit
|
||||||
207.68.176.0/26 permit
|
207.68.176.0/26 permit
|
||||||
@@ -1734,7 +1718,8 @@
|
|||||||
207.82.80.0/24 permit
|
207.82.80.0/24 permit
|
||||||
207.126.144.0/20 permit
|
207.126.144.0/20 permit
|
||||||
207.171.160.0/19 permit
|
207.171.160.0/19 permit
|
||||||
207.211.30.0/24 permit
|
207.211.30.64/26 permit
|
||||||
|
207.211.30.128/25 permit
|
||||||
207.211.31.0/25 permit
|
207.211.31.0/25 permit
|
||||||
207.211.41.113 permit
|
207.211.41.113 permit
|
||||||
207.218.90.0/24 permit
|
207.218.90.0/24 permit
|
||||||
@@ -1743,7 +1728,7 @@
|
|||||||
208.43.21.28/30 permit
|
208.43.21.28/30 permit
|
||||||
208.43.21.64/29 permit
|
208.43.21.64/29 permit
|
||||||
208.43.21.72/30 permit
|
208.43.21.72/30 permit
|
||||||
208.43.239.136/30 permit
|
208.46.212.80 permit
|
||||||
208.46.212.208/31 permit
|
208.46.212.208/31 permit
|
||||||
208.46.212.210 permit
|
208.46.212.210 permit
|
||||||
208.64.132.0/22 permit
|
208.64.132.0/22 permit
|
||||||
@@ -1773,13 +1758,13 @@
|
|||||||
208.71.42.212/31 permit
|
208.71.42.212/31 permit
|
||||||
208.71.42.214 permit
|
208.71.42.214 permit
|
||||||
208.72.249.240/29 permit
|
208.72.249.240/29 permit
|
||||||
208.74.204.0/22 permit
|
|
||||||
208.74.204.9 permit
|
208.74.204.9 permit
|
||||||
208.75.120.0/22 permit
|
208.75.120.0/22 permit
|
||||||
208.75.122.246 permit
|
208.75.122.246 permit
|
||||||
208.82.236.96/28 permit
|
208.82.237.96/29 permit
|
||||||
208.82.237.96/28 permit
|
208.82.237.104/31 permit
|
||||||
208.82.238.96/28 permit
|
208.82.238.96/29 permit
|
||||||
|
208.82.238.104/31 permit
|
||||||
208.85.50.137 permit
|
208.85.50.137 permit
|
||||||
208.117.48.0/20 permit
|
208.117.48.0/20 permit
|
||||||
208.185.229.45 permit
|
208.185.229.45 permit
|
||||||
@@ -1792,10 +1777,10 @@
|
|||||||
209.67.98.59 permit
|
209.67.98.59 permit
|
||||||
209.85.128.0/17 permit
|
209.85.128.0/17 permit
|
||||||
212.4.136.0/26 permit
|
212.4.136.0/26 permit
|
||||||
212.25.240.75 permit
|
212.25.240.80 permit
|
||||||
212.25.240.76 permit
|
|
||||||
212.25.240.83 permit
|
212.25.240.83 permit
|
||||||
212.25.240.84 permit
|
212.25.240.84/31 permit
|
||||||
|
212.25.240.88 permit
|
||||||
212.82.96.0/24 permit
|
212.82.96.0/24 permit
|
||||||
212.82.96.32/27 permit
|
212.82.96.32/27 permit
|
||||||
212.82.96.64/29 permit
|
212.82.96.64/29 permit
|
||||||
@@ -1836,13 +1821,8 @@
|
|||||||
212.82.111.228/31 permit
|
212.82.111.228/31 permit
|
||||||
212.82.111.230 permit
|
212.82.111.230 permit
|
||||||
212.123.28.40 permit
|
212.123.28.40 permit
|
||||||
212.227.15.0/24 permit
|
213.167.75.0/25 permit
|
||||||
212.227.15.0/25 permit
|
213.167.81.0/25 permit
|
||||||
212.227.17.0/27 permit
|
|
||||||
212.227.126.128/25 permit
|
|
||||||
213.165.64.0/23 permit
|
|
||||||
213.167.75.0/24 permit
|
|
||||||
213.167.81.0/24 permit
|
|
||||||
213.199.128.139 permit
|
213.199.128.139 permit
|
||||||
213.199.128.145 permit
|
213.199.128.145 permit
|
||||||
213.199.138.181 permit
|
213.199.138.181 permit
|
||||||
@@ -1851,6 +1831,7 @@
|
|||||||
213.199.177.0/26 permit
|
213.199.177.0/26 permit
|
||||||
216.17.150.242 permit
|
216.17.150.242 permit
|
||||||
216.17.150.251 permit
|
216.17.150.251 permit
|
||||||
|
216.22.15.224/27 permit
|
||||||
216.24.224.0/20 permit
|
216.24.224.0/20 permit
|
||||||
216.39.60.0/23 permit
|
216.39.60.0/23 permit
|
||||||
216.39.60.154/31 permit
|
216.39.60.154/31 permit
|
||||||
@@ -1877,17 +1858,9 @@
|
|||||||
216.39.62.60/31 permit
|
216.39.62.60/31 permit
|
||||||
216.39.62.136/29 permit
|
216.39.62.136/29 permit
|
||||||
216.39.62.144/31 permit
|
216.39.62.144/31 permit
|
||||||
216.46.168.197 permit
|
216.46.168.0/24 permit
|
||||||
216.46.168.222 permit
|
|
||||||
216.52.185.88/29 permit
|
|
||||||
216.58.192.0/19 permit
|
216.58.192.0/19 permit
|
||||||
216.66.217.240/29 permit
|
216.66.217.240/29 permit
|
||||||
216.71.96.0/22 permit
|
|
||||||
216.71.152.175 permit
|
|
||||||
216.71.152.207 permit
|
|
||||||
216.71.154.29 permit
|
|
||||||
216.71.155.88 permit
|
|
||||||
216.71.155.89 permit
|
|
||||||
216.74.162.13 permit
|
216.74.162.13 permit
|
||||||
216.74.162.14 permit
|
216.74.162.14 permit
|
||||||
216.82.240.0/20 permit
|
216.82.240.0/20 permit
|
||||||
@@ -1897,9 +1870,6 @@
|
|||||||
216.109.114.0/24 permit
|
216.109.114.0/24 permit
|
||||||
216.109.114.32/27 permit
|
216.109.114.32/27 permit
|
||||||
216.109.114.64/29 permit
|
216.109.114.64/29 permit
|
||||||
216.113.160.0/24 permit
|
|
||||||
216.113.172.0/25 permit
|
|
||||||
216.113.175.0/24 permit
|
|
||||||
216.128.126.97 permit
|
216.128.126.97 permit
|
||||||
216.136.162.65 permit
|
216.136.162.65 permit
|
||||||
216.136.162.120/29 permit
|
216.136.162.120/29 permit
|
||||||
@@ -1909,14 +1879,13 @@
|
|||||||
216.203.33.178/31 permit
|
216.203.33.178/31 permit
|
||||||
216.205.24.0/24 permit
|
216.205.24.0/24 permit
|
||||||
216.239.32.0/19 permit
|
216.239.32.0/19 permit
|
||||||
217.72.192.64/26 permit
|
|
||||||
217.72.192.248/29 permit
|
|
||||||
217.72.207.0/27 permit
|
|
||||||
217.77.141.52 permit
|
217.77.141.52 permit
|
||||||
217.77.141.59 permit
|
217.77.141.59 permit
|
||||||
217.175.193.0/24 permit
|
222.73.195.64/29 permit
|
||||||
217.175.194.0/23 permit
|
223.165.113.0/24 permit
|
||||||
217.175.196.0/24 permit
|
223.165.115.0/24 permit
|
||||||
|
223.165.118.0/23 permit
|
||||||
|
223.165.120.0/23 permit
|
||||||
2001:4860:4000::/36 permit
|
2001:4860:4000::/36 permit
|
||||||
2404:6800:4000::/36 permit
|
2404:6800:4000::/36 permit
|
||||||
2607:f8b0:4000::/36 permit
|
2607:f8b0:4000::/36 permit
|
||||||
@@ -1925,6 +1894,7 @@
|
|||||||
2620:109:c006:104::215 permit
|
2620:109:c006:104::215 permit
|
||||||
2620:109:c006:104::/64 permit
|
2620:109:c006:104::/64 permit
|
||||||
2620:109:c00d:104::/64 permit
|
2620:109:c00d:104::/64 permit
|
||||||
|
2620:10d:c090:450::120 permit
|
||||||
2620:10d:c091:450::16 permit
|
2620:10d:c091:450::16 permit
|
||||||
2620:119:50c0:207::215 permit
|
2620:119:50c0:207::215 permit
|
||||||
2620:119:50c0:207::/64 permit
|
2620:119:50c0:207::/64 permit
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
/.*episerver.*/i
|
/.*episerver.*/i
|
||||||
/.*supergewinne.*/i
|
/.*supergewinne.*/i
|
||||||
/List-Unsubscribe.*nbps\.eu/i
|
/List-Unsubscribe.*nbps\.eu/i
|
||||||
/X-Mailer: AWeber.*/i
|
|
||||||
/.*regiofinder.*/i
|
/.*regiofinder.*/i
|
||||||
/.*EmailSocket.*/i
|
/.*EmailSocket.*/i
|
||||||
/List-Unsubscribe:.*respread.*/i
|
/List-Unsubscribe:.*respread.*/i
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ symbols {
|
|||||||
"ENCRYPTED_CHAT" {
|
"ENCRYPTED_CHAT" {
|
||||||
score = -20.0;
|
score = -20.0;
|
||||||
}
|
}
|
||||||
|
"SOGO_CONTACT" {
|
||||||
|
score = -99.0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
group "MX" {
|
group "MX" {
|
||||||
|
|||||||
@@ -16,8 +16,7 @@ rules {
|
|||||||
backend = "http";
|
backend = "http";
|
||||||
url = "http://nginx:9081/pushover.php";
|
url = "http://nginx:9081/pushover.php";
|
||||||
selector = "mailcow_rcpt";
|
selector = "mailcow_rcpt";
|
||||||
# Only return msgid, do not parse the full message
|
formatter = "json";
|
||||||
formatter = "msgid";
|
|
||||||
meta_headers = true;
|
meta_headers = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
rules {
|
|
||||||
"LONG" {
|
|
||||||
train {
|
|
||||||
max_trains = 200;
|
|
||||||
max_usages = 20;
|
|
||||||
max_iterations = 25;
|
|
||||||
learning_rate = 0.01,
|
|
||||||
}
|
|
||||||
symbol_spam = "NEURAL_SPAM_LONG";
|
|
||||||
symbol_ham = "NEURAL_HAM_LONG";
|
|
||||||
ann_expire = 45d;
|
|
||||||
}
|
|
||||||
"SHORT" {
|
|
||||||
train {
|
|
||||||
max_trains = 100;
|
|
||||||
max_usages = 10;
|
|
||||||
max_iterations = 15;
|
|
||||||
learning_rate = 0.01,
|
|
||||||
}
|
|
||||||
symbol_spam = "NEURAL_SPAM_SHORT";
|
|
||||||
symbol_ham = "NEURAL_HAM_SHORT";
|
|
||||||
ann_expire = 7d;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
symbols = {
|
|
||||||
"NEURAL_SPAM_LONG" {
|
|
||||||
weight = 3.7; # sample weight
|
|
||||||
description = "Neural network spam (long)";
|
|
||||||
}
|
|
||||||
"NEURAL_HAM_LONG" {
|
|
||||||
weight = -4.0; # sample weight
|
|
||||||
description = "Neural network ham (long)";
|
|
||||||
}
|
|
||||||
"NEURAL_SPAM_SHORT" {
|
|
||||||
weight = 2.5; # sample weight
|
|
||||||
description = "Neural network spam (short)";
|
|
||||||
}
|
|
||||||
"NEURAL_HAM_SHORT" {
|
|
||||||
weight = -2.0; # sample weight
|
|
||||||
description = "Neural network ham (short)";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
-- Thanks to https://raw.githubusercontent.com/fatalbanana
|
|
||||||
|
|
||||||
local lua_maps = require 'lua_maps'
|
|
||||||
local rspamd_regexp = require 'rspamd_regexp'
|
|
||||||
local rspamd_util = require 'rspamd_util'
|
|
||||||
|
|
||||||
local ivm_sendgrid_ids = lua_maps.map_add_from_ucl(
|
|
||||||
'https://www.invaluement.com/spdata/sendgrid-id-dnsbl.txt',
|
|
||||||
'set',
|
|
||||||
'Invaluement Service Provider DNSBL: Sendgrid IDs'
|
|
||||||
)
|
|
||||||
|
|
||||||
local ivm_sendgrid_envfromdomains = lua_maps.map_add_from_ucl(
|
|
||||||
'https://www.invaluement.com/spdata/sendgrid-envelopefromdomain-dnsbl.txt',
|
|
||||||
'set',
|
|
||||||
'Invaluement Service Provider DNSBL: Sendgrid envelope domains'
|
|
||||||
)
|
|
||||||
|
|
||||||
local cb_id = rspamd_config:register_symbol({
|
|
||||||
name = 'IVM_SENDGRID',
|
|
||||||
callback = function(task)
|
|
||||||
-- Is it Sendgrid?
|
|
||||||
local sg_hdr = task:get_header('X-SG-EID')
|
|
||||||
if not sg_hdr then return end
|
|
||||||
|
|
||||||
-- Get original envelope from
|
|
||||||
local env_from = task:get_from{'smtp', 'orig'}
|
|
||||||
if not env_from then return end
|
|
||||||
|
|
||||||
-- Check normalised domain in domains list
|
|
||||||
if ivm_sendgrid_envfromdomains and ivm_sendgrid_envfromdomains:get_key(rspamd_util.get_tld(env_from[1].domain)) then
|
|
||||||
task:insert_result('IVM_SENDGRID_DOMAIN', 1.0)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Check ID in ID list
|
|
||||||
local lp_re = rspamd_regexp.create_cached([[^bounces\+(\d+)-]])
|
|
||||||
local res = lp_re:search(env_from[1].user, true, true)
|
|
||||||
if not res then return end
|
|
||||||
if ivm_sendgrid_ids and ivm_sendgrid_ids:get_key(res[1][2]) then
|
|
||||||
task:insert_result('IVM_SENDGRID_ID', 1.0)
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
description = 'Invaluement Service Provider DNSBL: Sendgrid',
|
|
||||||
type = 'callback',
|
|
||||||
})
|
|
||||||
|
|
||||||
rspamd_config:register_symbol({
|
|
||||||
name = 'IVM_SENDGRID_DOMAIN',
|
|
||||||
parent = cb_id,
|
|
||||||
group = 'ivmspdnsbl',
|
|
||||||
score = 8.0,
|
|
||||||
type = 'virtual',
|
|
||||||
})
|
|
||||||
|
|
||||||
rspamd_config:register_symbol({
|
|
||||||
name = 'IVM_SENDGRID_ID',
|
|
||||||
parent = cb_id,
|
|
||||||
group = 'ivmspdnsbl',
|
|
||||||
score = 8.0,
|
|
||||||
type = 'virtual',
|
|
||||||
})
|
|
||||||
@@ -47,12 +47,14 @@ if (!function_exists('getallheaders')) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$headers = getallheaders();
|
$headers = getallheaders();
|
||||||
|
$json_body = json_decode(file_get_contents('php://input'));
|
||||||
|
|
||||||
$qid = $headers['X-Rspamd-Qid'];
|
$qid = $headers['X-Rspamd-Qid'];
|
||||||
$rcpts = $headers['X-Rspamd-Rcpt'];
|
$rcpts = $headers['X-Rspamd-Rcpt'];
|
||||||
$sender = $headers['X-Rspamd-From'];
|
$sender = $headers['X-Rspamd-From'];
|
||||||
$ip = $headers['X-Rspamd-Ip'];
|
$ip = $headers['X-Rspamd-Ip'];
|
||||||
$subject = $headers['X-Rspamd-Subject'];
|
$subject = $headers['X-Rspamd-Subject'];
|
||||||
|
$messageid= $json_body->message_id;
|
||||||
$priority = 0;
|
$priority = 0;
|
||||||
|
|
||||||
$symbols_array = json_decode($headers['X-Rspamd-Symbols'], true);
|
$symbols_array = json_decode($headers['X-Rspamd-Symbols'], true);
|
||||||
@@ -65,6 +67,20 @@ if (is_array($symbols_array)) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$sender_address = $json_body->header_from[0];
|
||||||
|
$sender_name = '-';
|
||||||
|
if (preg_match('/(?<name>.*?)<(?<address>.*?)>/i', $sender_address, $matches)) {
|
||||||
|
$sender_address = $matches['address'];
|
||||||
|
$sender_name = trim($matches['name'], '"\' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
$to_address = $json_body->header_to[0];
|
||||||
|
$to_name = '-';
|
||||||
|
if (preg_match('/(?<name>.*?)<(?<address>.*?)>/i', $to_address, $matches)) {
|
||||||
|
$to_address = $matches['address'];
|
||||||
|
$to_name = trim($matches['name'], '"\' ');
|
||||||
|
}
|
||||||
|
|
||||||
$rcpt_final_mailboxes = array();
|
$rcpt_final_mailboxes = array();
|
||||||
|
|
||||||
// Loop through all rcpts
|
// Loop through all rcpts
|
||||||
@@ -229,9 +245,16 @@ foreach ($rcpt_final_mailboxes as $rcpt_final) {
|
|||||||
$post_fields = array(
|
$post_fields = array(
|
||||||
"token" => $api_data['token'],
|
"token" => $api_data['token'],
|
||||||
"user" => $api_data['key'],
|
"user" => $api_data['key'],
|
||||||
"title" => sprintf("%s", str_replace(array('{SUBJECT}', '{SENDER}'), array($subject, $sender), $title)),
|
"title" => sprintf("%s", str_replace(
|
||||||
|
array('{SUBJECT}', '{SENDER}', '{SENDER_NAME}', '{SENDER_ADDRESS}', '{TO_NAME}', '{TO_ADDRESS}', '{MSG_ID}'),
|
||||||
|
array($subject, $sender, $sender_name, $sender_address, $to_name, $to_address, $messageid), $title)
|
||||||
|
),
|
||||||
"priority" => $priority,
|
"priority" => $priority,
|
||||||
"message" => sprintf("%s", str_replace(array('{SUBJECT}', '{SENDER}'), array($subject, $sender), $text))
|
"message" => sprintf("%s", str_replace(
|
||||||
|
array('{SUBJECT}', '{SENDER}', '{SENDER_NAME}', '{SENDER_ADDRESS}', '{TO_NAME}', '{TO_ADDRESS}', '{MSG_ID}', '\n'),
|
||||||
|
array($subject, $sender, $sender_name, $sender_address, $to_name, $to_address, $messageid, PHP_EOL), $text)
|
||||||
|
),
|
||||||
|
"sound" => $attributes['sound'] ?? "pushover"
|
||||||
);
|
);
|
||||||
if ($attributes['evaluate_x_prio'] == "1" && $priority == 1) {
|
if ($attributes['evaluate_x_prio'] == "1" && $priority == 1) {
|
||||||
$post_fields['expire'] = 600;
|
$post_fields['expire'] = 600;
|
||||||
|
|||||||
@@ -32,8 +32,6 @@
|
|||||||
// );
|
// );
|
||||||
|
|
||||||
// self-signed is not trusted anymore
|
// self-signed is not trusted anymore
|
||||||
SOGoSieveServer = "sieve://dovecot:4190/?TLS=YES&tlsVerifyMode=none";
|
|
||||||
SOGoSMTPServer = "smtp://postfix:588/?TLS=YES&tlsVerifyMode=none";
|
|
||||||
WOPort = "0.0.0.0:20000";
|
WOPort = "0.0.0.0:20000";
|
||||||
SOGoMemcachedHost = "memcached";
|
SOGoMemcachedHost = "memcached";
|
||||||
|
|
||||||
|
|||||||
@@ -13,12 +13,12 @@
|
|||||||
Please check the logs or contact support if the error persists.</p>
|
Please check the logs or contact support if the error persists.</p>
|
||||||
<h2>Quick debugging</h2>
|
<h2>Quick debugging</h2>
|
||||||
<p>Check Nginx and PHP logs:</p>
|
<p>Check Nginx and PHP logs:</p>
|
||||||
<pre>docker-compose logs --tail=200 php-fpm-mailcow nginx-mailcow</pre>
|
<pre>docker compose logs --tail=200 php-fpm-mailcow nginx-mailcow</pre>
|
||||||
<p>Make sure your SQL credentials in mailcow.conf (a link to .env) do fit your initialized SQL volume. If you see an access denied, you might have the wrong mailcow.conf:</p>
|
<p>Make sure your SQL credentials in mailcow.conf (a link to .env) do fit your initialized SQL volume. If you see an access denied, you might have the wrong mailcow.conf:</p>
|
||||||
<pre>source mailcow.conf ; docker-compose exec mysql-mailcow mysql -u${DBUSER} -p${DBPASS} ${DBNAME}</pre>
|
<pre>source mailcow.conf ; docker compose exec mysql-mailcow mysql -u${DBUSER} -p${DBPASS} ${DBNAME}</pre>
|
||||||
<p>In case of a previous failed installation, create a backup of your existing data, followed by removing all volumes and starting over (<b>NEVER</b> do this with a production system, it will remove <b>ALL</b> data):</p>
|
<p>In case of a previous failed installation, create a backup of your existing data, followed by removing all volumes and starting over (<b>NEVER</b> do this with a production system, it will remove <b>ALL</b> data):</p>
|
||||||
<pre>BACKUP_LOCATION=/tmp/ ./helper-scripts/backup_and_restore.sh backup all</pre>
|
<pre>BACKUP_LOCATION=/tmp/ ./helper-scripts/backup_and_restore.sh backup all</pre>
|
||||||
<pre>docker-compose down --volumes ; docker-compose up -d</pre>
|
<pre>docker compose down --volumes ; docker compose up -d</pre>
|
||||||
<p>Make sure your timezone is correct. Use "America/New_York" for example, do not use spaces. Check <a href="https://en.wikipedia.org/wiki/List_of_tz_database_time_zones">here</a> for a list.</p>
|
<p>Make sure your timezone is correct. Use "America/New_York" for example, do not use spaces. Check <a href="https://en.wikipedia.org/wiki/List_of_tz_database_time_zones">here</a> for a list.</p>
|
||||||
<br>Click to learn more about <a style="color:red;text-decoration:none;" href="https://mailcow.github.io/mailcow-dockerized-docs/#get-support" target="_blank">getting support.</a>
|
<br>Click to learn more about <a style="color:red;text-decoration:none;" href="https://mailcow.github.io/mailcow-dockerized-docs/#get-support" target="_blank">getting support.</a>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
+1
-6
@@ -10,9 +10,6 @@ require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/header.inc.php';
|
|||||||
$_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
|
$_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
|
||||||
$tfa_data = get_tfa();
|
$tfa_data = get_tfa();
|
||||||
$fido2_data = fido2(array("action" => "get_friendly_names"));
|
$fido2_data = fido2(array("action" => "get_friendly_names"));
|
||||||
if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CACHE')) {
|
|
||||||
$_SESSION['gal'] = json_decode($license_cache, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
$js_minifier->add('/web/js/site/admin.js');
|
$js_minifier->add('/web/js/site/admin.js');
|
||||||
$js_minifier->add('/web/js/presets/rspamd.js');
|
$js_minifier->add('/web/js/presets/rspamd.js');
|
||||||
@@ -83,15 +80,12 @@ foreach ($RSPAMD_MAPS['regex'] as $rspamd_regex_desc => $rspamd_regex_map) {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$template = 'admin.twig';
|
$template = 'admin.twig';
|
||||||
$template_data = [
|
$template_data = [
|
||||||
'tfa_data' => $tfa_data,
|
'tfa_data' => $tfa_data,
|
||||||
'tfa_id' => @$_SESSION['tfa_id'],
|
'tfa_id' => @$_SESSION['tfa_id'],
|
||||||
'fido2_cid' => @$_SESSION['fido2_cid'],
|
'fido2_cid' => @$_SESSION['fido2_cid'],
|
||||||
'fido2_data' => $fido2_data,
|
'fido2_data' => $fido2_data,
|
||||||
'gal' => @$_SESSION['gal'],
|
|
||||||
'license_guid' => license('guid'),
|
|
||||||
'api' => [
|
'api' => [
|
||||||
'ro' => admin_api('ro', 'get'),
|
'ro' => admin_api('ro', 'get'),
|
||||||
'rw' => admin_api('rw', 'get'),
|
'rw' => admin_api('rw', 'get'),
|
||||||
@@ -112,6 +106,7 @@ $template_data = [
|
|||||||
'password_complexity' => password_complexity('get'),
|
'password_complexity' => password_complexity('get'),
|
||||||
'show_rspamd_global_filters' => @$_SESSION['show_rspamd_global_filters'],
|
'show_rspamd_global_filters' => @$_SESSION['show_rspamd_global_filters'],
|
||||||
'lang_admin' => json_encode($lang['admin']),
|
'lang_admin' => json_encode($lang['admin']),
|
||||||
|
'lang_datatables' => json_encode($lang['datatables'])
|
||||||
];
|
];
|
||||||
|
|
||||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/footer.inc.php';
|
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/footer.inc.php';
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
html {
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: -moz-scrollbars-vertical;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
*,
|
||||||
|
*:before,
|
||||||
|
*:after {
|
||||||
|
box-sizing: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
background: #fafafa;
|
||||||
|
}
|
||||||
+2
-43
@@ -5,56 +5,15 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Swagger UI</title>
|
<title>Swagger UI</title>
|
||||||
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" />
|
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="index.css" />
|
||||||
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
|
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
|
||||||
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
|
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
|
||||||
<style>
|
|
||||||
html
|
|
||||||
{
|
|
||||||
box-sizing: border-box;
|
|
||||||
overflow: -moz-scrollbars-vertical;
|
|
||||||
overflow-y: scroll;
|
|
||||||
}
|
|
||||||
|
|
||||||
*,
|
|
||||||
*:before,
|
|
||||||
*:after
|
|
||||||
{
|
|
||||||
box-sizing: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
body
|
|
||||||
{
|
|
||||||
margin:0;
|
|
||||||
background: #fafafa;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="swagger-ui"></div>
|
<div id="swagger-ui"></div>
|
||||||
|
|
||||||
<script src="./swagger-ui-bundle.js" charset="UTF-8"> </script>
|
<script src="./swagger-ui-bundle.js" charset="UTF-8"> </script>
|
||||||
<script src="./swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
|
<script src="./swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
|
||||||
<script>
|
<script src="./swagger-initializer.js" charset="UTF-8"> </script>
|
||||||
window.onload = function() {
|
|
||||||
// Begin Swagger UI call region
|
|
||||||
const ui = SwaggerUIBundle({
|
|
||||||
url: "/api/openapi.yaml",
|
|
||||||
dom_id: '#swagger-ui',
|
|
||||||
deepLinking: true,
|
|
||||||
presets: [
|
|
||||||
SwaggerUIBundle.presets.apis,
|
|
||||||
SwaggerUIStandalonePreset
|
|
||||||
],
|
|
||||||
plugins: [
|
|
||||||
SwaggerUIBundle.plugins.DownloadUrl
|
|
||||||
],
|
|
||||||
layout: "StandaloneLayout"
|
|
||||||
});
|
|
||||||
// End Swagger UI call region
|
|
||||||
|
|
||||||
window.ui = ui;
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
var isValid, qp, arr;
|
var isValid, qp, arr;
|
||||||
|
|
||||||
if (/code|token|error/.test(window.location.hash)) {
|
if (/code|token|error/.test(window.location.hash)) {
|
||||||
qp = window.location.hash.substring(1);
|
qp = window.location.hash.substring(1).replace('?', '&');
|
||||||
} else {
|
} else {
|
||||||
qp = location.search.substring(1);
|
qp = location.search.substring(1);
|
||||||
}
|
}
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
authId: oauth2.auth.name,
|
authId: oauth2.auth.name,
|
||||||
source: "auth",
|
source: "auth",
|
||||||
level: "warning",
|
level: "warning",
|
||||||
message: "Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"
|
message: "Authorization may be unsafe, passed state was changed in server. The passed state wasn't returned from auth server."
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
authId: oauth2.auth.name,
|
authId: oauth2.auth.name,
|
||||||
source: "auth",
|
source: "auth",
|
||||||
level: "error",
|
level: "error",
|
||||||
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server"
|
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server."
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -67,9 +67,13 @@
|
|||||||
window.close();
|
window.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('DOMContentLoaded', function () {
|
if (document.readyState !== 'loading') {
|
||||||
run();
|
run();
|
||||||
});
|
} else {
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
run();
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
+345
-53
@@ -209,10 +209,17 @@ paths:
|
|||||||
- app_passwd
|
- app_passwd
|
||||||
- add
|
- add
|
||||||
- active: "1"
|
- active: "1"
|
||||||
app_name: emclient
|
username: info@domain.tld
|
||||||
|
app_name: wordpress
|
||||||
app_passwd: keyleudecticidechothistishownsan31
|
app_passwd: keyleudecticidechothistishownsan31
|
||||||
app_passwd2: keyleudecticidechothistishownsan31
|
app_passwd2: keyleudecticidechothistishownsan31
|
||||||
username: hello@mailcow.email
|
protocols:
|
||||||
|
- imap_access
|
||||||
|
- dav_access
|
||||||
|
- smtp_access
|
||||||
|
- eas_access
|
||||||
|
- pop3_access
|
||||||
|
- sieve_access
|
||||||
msg: app_passwd_added
|
msg: app_passwd_added
|
||||||
type: success
|
type: success
|
||||||
schema:
|
schema:
|
||||||
@@ -249,6 +256,13 @@ paths:
|
|||||||
app_name: wordpress
|
app_name: wordpress
|
||||||
app_passwd: keyleudecticidechothistishownsan31
|
app_passwd: keyleudecticidechothistishownsan31
|
||||||
app_passwd2: keyleudecticidechothistishownsan31
|
app_passwd2: keyleudecticidechothistishownsan31
|
||||||
|
protocols:
|
||||||
|
- imap_access
|
||||||
|
- dav_access
|
||||||
|
- smtp_access
|
||||||
|
- eas_access
|
||||||
|
- pop3_access
|
||||||
|
- sieve_access
|
||||||
properties:
|
properties:
|
||||||
active:
|
active:
|
||||||
description: is alias active or not
|
description: is alias active or not
|
||||||
@@ -497,27 +511,30 @@ paths:
|
|||||||
relay_all_recipients: "0"
|
relay_all_recipients: "0"
|
||||||
rl_frame: s
|
rl_frame: s
|
||||||
rl_value: "10"
|
rl_value: "10"
|
||||||
|
tags: ["tag1", "tag2"]
|
||||||
- null
|
- null
|
||||||
msg:
|
msg:
|
||||||
- domain_added
|
- domain_added
|
||||||
- domain.tld
|
- domain.tld
|
||||||
type: success
|
type: success
|
||||||
schema:
|
schema:
|
||||||
properties:
|
type: array
|
||||||
log:
|
items:
|
||||||
description: contains request object
|
type: object
|
||||||
items: {}
|
properties:
|
||||||
type: array
|
log:
|
||||||
msg:
|
description: contains request object
|
||||||
items: {}
|
items: {}
|
||||||
type: array
|
type: array
|
||||||
type:
|
msg:
|
||||||
enum:
|
items: {}
|
||||||
- success
|
type: array
|
||||||
- danger
|
type:
|
||||||
- error
|
enum:
|
||||||
type: string
|
- success
|
||||||
type: object
|
- danger
|
||||||
|
- error
|
||||||
|
type: string
|
||||||
description: OK
|
description: OK
|
||||||
headers: {}
|
headers: {}
|
||||||
tags:
|
tags:
|
||||||
@@ -544,6 +561,7 @@ paths:
|
|||||||
rl_frame: s
|
rl_frame: s
|
||||||
rl_value: "10"
|
rl_value: "10"
|
||||||
restart_sogo: "10"
|
restart_sogo: "10"
|
||||||
|
tags: ["tag1", "tag2"]
|
||||||
properties:
|
properties:
|
||||||
active:
|
active:
|
||||||
description: is domain active or not
|
description: is domain active or not
|
||||||
@@ -563,6 +581,11 @@ paths:
|
|||||||
domain:
|
domain:
|
||||||
description: Fully qualified domain name
|
description: Fully qualified domain name
|
||||||
type: string
|
type: string
|
||||||
|
gal:
|
||||||
|
description: >-
|
||||||
|
is domain global address list active or not, it enables
|
||||||
|
shared contacts accross domain in SOGo webmail
|
||||||
|
type: boolean
|
||||||
mailboxes:
|
mailboxes:
|
||||||
description: limit count of mailboxes associated with this domain
|
description: limit count of mailboxes associated with this domain
|
||||||
type: number
|
type: number
|
||||||
@@ -580,6 +603,9 @@ paths:
|
|||||||
if not, them you have to create "dummy" mailbox for each
|
if not, them you have to create "dummy" mailbox for each
|
||||||
address to relay
|
address to relay
|
||||||
type: boolean
|
type: boolean
|
||||||
|
relay_unknown_only:
|
||||||
|
description: Relay non-existing mailboxes only. Existing mailboxes will be delivered locally.
|
||||||
|
type: boolean
|
||||||
rl_frame:
|
rl_frame:
|
||||||
enum:
|
enum:
|
||||||
- s
|
- s
|
||||||
@@ -590,6 +616,11 @@ paths:
|
|||||||
rl_value:
|
rl_value:
|
||||||
description: rate limit value
|
description: rate limit value
|
||||||
type: number
|
type: number
|
||||||
|
tags:
|
||||||
|
description: tags for this Domain
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
type: object
|
type: object
|
||||||
summary: Create domain
|
summary: Create domain
|
||||||
/api/v1/add/domain-admin:
|
/api/v1/add/domain-admin:
|
||||||
@@ -1010,6 +1041,7 @@ paths:
|
|||||||
force_pw_update: "1"
|
force_pw_update: "1"
|
||||||
tls_enforce_in: "1"
|
tls_enforce_in: "1"
|
||||||
tls_enforce_out: "1"
|
tls_enforce_out: "1"
|
||||||
|
tags: ["tag1", "tag2"]
|
||||||
- null
|
- null
|
||||||
msg:
|
msg:
|
||||||
- mailbox_added
|
- mailbox_added
|
||||||
@@ -1054,6 +1086,7 @@ paths:
|
|||||||
force_pw_update: "1"
|
force_pw_update: "1"
|
||||||
tls_enforce_in: "1"
|
tls_enforce_in: "1"
|
||||||
tls_enforce_out: "1"
|
tls_enforce_out: "1"
|
||||||
|
tags: ["tag1", "tag2"]
|
||||||
properties:
|
properties:
|
||||||
active:
|
active:
|
||||||
description: is mailbox active or not
|
description: is mailbox active or not
|
||||||
@@ -1934,21 +1967,23 @@ paths:
|
|||||||
- domain2.tld
|
- domain2.tld
|
||||||
type: success
|
type: success
|
||||||
schema:
|
schema:
|
||||||
properties:
|
type: array
|
||||||
log:
|
items:
|
||||||
description: contains request object
|
type: object
|
||||||
items: {}
|
properties:
|
||||||
type: array
|
log:
|
||||||
msg:
|
description: contains request object
|
||||||
items: {}
|
items: {}
|
||||||
type: array
|
type: array
|
||||||
type:
|
msg:
|
||||||
enum:
|
items: {}
|
||||||
- success
|
type: array
|
||||||
- danger
|
type:
|
||||||
- error
|
enum:
|
||||||
type: string
|
- success
|
||||||
type: object
|
- danger
|
||||||
|
- error
|
||||||
|
type: string
|
||||||
description: OK
|
description: OK
|
||||||
headers: {}
|
headers: {}
|
||||||
tags:
|
tags:
|
||||||
@@ -1959,14 +1994,15 @@ paths:
|
|||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
|
type: object
|
||||||
example:
|
example:
|
||||||
- domain.tld
|
- domain.tld
|
||||||
- domain2.tld
|
- domain2.tld
|
||||||
properties:
|
properties:
|
||||||
items:
|
items:
|
||||||
description: contains list of domains you want to delete
|
type: array
|
||||||
type: object
|
items:
|
||||||
type: object
|
type: string
|
||||||
summary: Delete domain
|
summary: Delete domain
|
||||||
/api/v1/delete/domain-admin:
|
/api/v1/delete/domain-admin:
|
||||||
post:
|
post:
|
||||||
@@ -2716,6 +2752,140 @@ paths:
|
|||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
summary: Delete Transport Maps
|
summary: Delete Transport Maps
|
||||||
|
"/api/v1/delete/mailbox/tag/{mailbox}":
|
||||||
|
post:
|
||||||
|
parameters:
|
||||||
|
- description: name of mailbox
|
||||||
|
in: path
|
||||||
|
name: mailbox
|
||||||
|
example: info@domain.tld
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
"401":
|
||||||
|
$ref: "#/components/responses/Unauthorized"
|
||||||
|
"200":
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
examples:
|
||||||
|
response:
|
||||||
|
value:
|
||||||
|
- log:
|
||||||
|
- mailbox
|
||||||
|
- delete
|
||||||
|
- tags_mailbox
|
||||||
|
- tags:
|
||||||
|
- tag1
|
||||||
|
- tag2
|
||||||
|
mailbox: info@domain.tld
|
||||||
|
- null
|
||||||
|
msg:
|
||||||
|
- mailbox_modified
|
||||||
|
- info@domain.tld
|
||||||
|
type: success
|
||||||
|
schema:
|
||||||
|
properties:
|
||||||
|
log:
|
||||||
|
description: contains request object
|
||||||
|
items: {}
|
||||||
|
type: array
|
||||||
|
msg:
|
||||||
|
items: {}
|
||||||
|
type: array
|
||||||
|
type:
|
||||||
|
enum:
|
||||||
|
- success
|
||||||
|
- danger
|
||||||
|
- error
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
description: OK
|
||||||
|
headers: {}
|
||||||
|
tags:
|
||||||
|
- Mailboxes
|
||||||
|
description: You can delete one or more mailbox tags.
|
||||||
|
operationId: Delete mailbox tags
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
example:
|
||||||
|
- tag1
|
||||||
|
- tag2
|
||||||
|
properties:
|
||||||
|
items:
|
||||||
|
description: contains list of mailboxes you want to delete
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
summary: Delete mailbox tags
|
||||||
|
"/api/v1/delete/domain/tag/{domain}":
|
||||||
|
post:
|
||||||
|
parameters:
|
||||||
|
- description: name of domain
|
||||||
|
in: path
|
||||||
|
name: domain
|
||||||
|
example: domain.tld
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
"401":
|
||||||
|
$ref: "#/components/responses/Unauthorized"
|
||||||
|
"200":
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
examples:
|
||||||
|
response:
|
||||||
|
value:
|
||||||
|
- log:
|
||||||
|
- mailbox
|
||||||
|
- delete
|
||||||
|
- tags_domain
|
||||||
|
- tags:
|
||||||
|
- tag1
|
||||||
|
- tag2
|
||||||
|
domain: domain.tld
|
||||||
|
- null
|
||||||
|
msg:
|
||||||
|
- domain_modified
|
||||||
|
- domain.tld
|
||||||
|
type: success
|
||||||
|
schema:
|
||||||
|
properties:
|
||||||
|
log:
|
||||||
|
description: contains request object
|
||||||
|
items: {}
|
||||||
|
type: array
|
||||||
|
msg:
|
||||||
|
items: {}
|
||||||
|
type: array
|
||||||
|
type:
|
||||||
|
enum:
|
||||||
|
- success
|
||||||
|
- danger
|
||||||
|
- error
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
description: OK
|
||||||
|
headers: {}
|
||||||
|
tags:
|
||||||
|
- Domains
|
||||||
|
description: You can delete one or more domain tags.
|
||||||
|
operationId: Delete domain tags
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
example:
|
||||||
|
- tag1
|
||||||
|
- tag2
|
||||||
|
properties:
|
||||||
|
items:
|
||||||
|
description: contains list of domains you want to delete
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
summary: Delete domain tags
|
||||||
/api/v1/edit/alias:
|
/api/v1/edit/alias:
|
||||||
post:
|
post:
|
||||||
responses:
|
responses:
|
||||||
@@ -2820,23 +2990,25 @@ paths:
|
|||||||
$ref: "#/components/responses/Unauthorized"
|
$ref: "#/components/responses/Unauthorized"
|
||||||
"200":
|
"200":
|
||||||
content:
|
content:
|
||||||
"*/*":
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
properties:
|
type: array
|
||||||
log:
|
items:
|
||||||
description: contains request object
|
type: object
|
||||||
items: {}
|
properties:
|
||||||
type: array
|
log:
|
||||||
msg:
|
type: array
|
||||||
items: {}
|
description: contains request object
|
||||||
type: array
|
items: {}
|
||||||
type:
|
msg:
|
||||||
enum:
|
type: array
|
||||||
- success
|
items: {}
|
||||||
- danger
|
type:
|
||||||
- error
|
enum:
|
||||||
type: string
|
- success
|
||||||
type: object
|
- danger
|
||||||
|
- error
|
||||||
|
type: string
|
||||||
description: OK
|
description: OK
|
||||||
headers: {}
|
headers: {}
|
||||||
tags:
|
tags:
|
||||||
@@ -2865,6 +3037,7 @@ paths:
|
|||||||
quota: "10240"
|
quota: "10240"
|
||||||
relay_all_recipients: "0"
|
relay_all_recipients: "0"
|
||||||
relayhost: "2"
|
relayhost: "2"
|
||||||
|
tags: ["tag3", "tag4"]
|
||||||
items: domain.tld
|
items: domain.tld
|
||||||
properties:
|
properties:
|
||||||
attr:
|
attr:
|
||||||
@@ -2903,13 +3076,33 @@ paths:
|
|||||||
if not, them you have to create "dummy" mailbox for each
|
if not, them you have to create "dummy" mailbox for each
|
||||||
address to relay
|
address to relay
|
||||||
type: boolean
|
type: boolean
|
||||||
|
relay_unknown_only:
|
||||||
|
description: Relay non-existing mailboxes only. Existing mailboxes will be delivered locally.
|
||||||
|
type: boolean
|
||||||
relayhost:
|
relayhost:
|
||||||
description: id of relayhost
|
description: id of relayhost
|
||||||
type: number
|
type: number
|
||||||
|
rl_frame:
|
||||||
|
enum:
|
||||||
|
- s
|
||||||
|
- m
|
||||||
|
- h
|
||||||
|
- d
|
||||||
|
type: string
|
||||||
|
rl_value:
|
||||||
|
description: rate limit value
|
||||||
|
type: number
|
||||||
|
tags:
|
||||||
|
description: tags for this Domain
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
type: object
|
type: object
|
||||||
items:
|
items:
|
||||||
description: contains list of domain names you want update
|
description: contains list of domain names you want update
|
||||||
type: object
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
type: object
|
type: object
|
||||||
summary: Update domain
|
summary: Update domain
|
||||||
/api/v1/edit/fail2ban:
|
/api/v1/edit/fail2ban:
|
||||||
@@ -3019,6 +3212,7 @@ paths:
|
|||||||
sogo_access: "1"
|
sogo_access: "1"
|
||||||
username:
|
username:
|
||||||
- info@domain.tld
|
- info@domain.tld
|
||||||
|
tags: ["tag3", "tag4"]
|
||||||
- null
|
- null
|
||||||
msg:
|
msg:
|
||||||
- mailbox_modified
|
- mailbox_modified
|
||||||
@@ -3066,6 +3260,7 @@ paths:
|
|||||||
- domain3.tld
|
- domain3.tld
|
||||||
- "*"
|
- "*"
|
||||||
sogo_access: "1"
|
sogo_access: "1"
|
||||||
|
tags: ["tag3", "tag4"]
|
||||||
items:
|
items:
|
||||||
- info@domain.tld
|
- info@domain.tld
|
||||||
properties:
|
properties:
|
||||||
@@ -3154,6 +3349,7 @@ paths:
|
|||||||
evaluate_x_prio: "0"
|
evaluate_x_prio: "0"
|
||||||
key: 21e8918e1jksdjcpis712
|
key: 21e8918e1jksdjcpis712
|
||||||
only_x_prio: "0"
|
only_x_prio: "0"
|
||||||
|
sound: "pushover"
|
||||||
senders: ""
|
senders: ""
|
||||||
senders_regex: ""
|
senders_regex: ""
|
||||||
text: ""
|
text: ""
|
||||||
@@ -3197,6 +3393,7 @@ paths:
|
|||||||
evaluate_x_prio: "0"
|
evaluate_x_prio: "0"
|
||||||
key: 21e8918e1jksdjcpis712
|
key: 21e8918e1jksdjcpis712
|
||||||
only_x_prio: "0"
|
only_x_prio: "0"
|
||||||
|
sound: "pushover"
|
||||||
senders: ""
|
senders: ""
|
||||||
senders_regex: ""
|
senders_regex: ""
|
||||||
text: ""
|
text: ""
|
||||||
@@ -3218,6 +3415,9 @@ paths:
|
|||||||
only_x_prio:
|
only_x_prio:
|
||||||
description: Only send push for prio mails
|
description: Only send push for prio mails
|
||||||
type: number
|
type: number
|
||||||
|
sound:
|
||||||
|
description: Set notification sound
|
||||||
|
type: string
|
||||||
senders:
|
senders:
|
||||||
description: Only send push for emails from these senders
|
description: Only send push for emails from these senders
|
||||||
type: string
|
type: string
|
||||||
@@ -3793,6 +3993,13 @@ paths:
|
|||||||
- all
|
- all
|
||||||
- mailcow.tld
|
- mailcow.tld
|
||||||
type: string
|
type: string
|
||||||
|
- description: comma seperated list of tags to filter by
|
||||||
|
example: "tag1,tag2"
|
||||||
|
in: query
|
||||||
|
name: tags
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
- description: e.g. api-key-string
|
- description: e.g. api-key-string
|
||||||
example: api-key-string
|
example: api-key-string
|
||||||
in: header
|
in: header
|
||||||
@@ -3831,6 +4038,7 @@ paths:
|
|||||||
relay_all_recipients: "0"
|
relay_all_recipients: "0"
|
||||||
relayhost: "0"
|
relayhost: "0"
|
||||||
rl: false
|
rl: false
|
||||||
|
tags: ["tag1", "tag2"]
|
||||||
- active: "1"
|
- active: "1"
|
||||||
aliases_in_domain: 0
|
aliases_in_domain: 0
|
||||||
aliases_left: 400
|
aliases_left: 400
|
||||||
@@ -3853,6 +4061,7 @@ paths:
|
|||||||
relay_all_recipients: "0"
|
relay_all_recipients: "0"
|
||||||
relayhost: "0"
|
relayhost: "0"
|
||||||
rl: false
|
rl: false
|
||||||
|
tags: ["tag3", "tag4"]
|
||||||
description: OK
|
description: OK
|
||||||
headers: {}
|
headers: {}
|
||||||
tags:
|
tags:
|
||||||
@@ -4345,6 +4554,13 @@ paths:
|
|||||||
- all
|
- all
|
||||||
- user@domain.tld
|
- user@domain.tld
|
||||||
type: string
|
type: string
|
||||||
|
- description: comma seperated list of tags to filter by
|
||||||
|
example: "tag1,tag2"
|
||||||
|
in: query
|
||||||
|
name: tags
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
- description: e.g. api-key-string
|
- description: e.g. api-key-string
|
||||||
example: api-key-string
|
example: api-key-string
|
||||||
in: header
|
in: header
|
||||||
@@ -4382,6 +4598,7 @@ paths:
|
|||||||
rl: false
|
rl: false
|
||||||
spam_aliases: 0
|
spam_aliases: 0
|
||||||
username: info@doman3.tld
|
username: info@doman3.tld
|
||||||
|
tags: ["tag1", "tag2"]
|
||||||
description: OK
|
description: OK
|
||||||
headers: {}
|
headers: {}
|
||||||
tags:
|
tags:
|
||||||
@@ -5072,6 +5289,27 @@ paths:
|
|||||||
of used storage.
|
of used storage.
|
||||||
operationId: Get vmail status
|
operationId: Get vmail status
|
||||||
summary: Get vmail status
|
summary: Get vmail status
|
||||||
|
/api/v1/get/status/version:
|
||||||
|
get:
|
||||||
|
responses:
|
||||||
|
"401":
|
||||||
|
$ref: "#/components/responses/Unauthorized"
|
||||||
|
"200":
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
examples:
|
||||||
|
response:
|
||||||
|
value:
|
||||||
|
version: "2022-04"
|
||||||
|
description: OK
|
||||||
|
headers: {}
|
||||||
|
tags:
|
||||||
|
- Status
|
||||||
|
description: >-
|
||||||
|
Using this endpoint you can get the current running release of this
|
||||||
|
instance.
|
||||||
|
operationId: Get version status
|
||||||
|
summary: Get version status
|
||||||
/api/v1/get/syncjobs/all/no_log:
|
/api/v1/get/syncjobs/all/no_log:
|
||||||
get:
|
get:
|
||||||
responses:
|
responses:
|
||||||
@@ -5268,6 +5506,60 @@ paths:
|
|||||||
attr:
|
attr:
|
||||||
spam_score: "8,15"
|
spam_score: "8,15"
|
||||||
summary: Edit mailbox spam filter score
|
summary: Edit mailbox spam filter score
|
||||||
|
"/api/v1/get/mailbox/all/{domain}":
|
||||||
|
get:
|
||||||
|
parameters:
|
||||||
|
- description: name of domain
|
||||||
|
in: path
|
||||||
|
name: domain
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- description: e.g. api-key-string
|
||||||
|
example: api-key-string
|
||||||
|
in: header
|
||||||
|
name: X-API-Key
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
"401":
|
||||||
|
$ref: "#/components/responses/Unauthorized"
|
||||||
|
"200":
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
examples:
|
||||||
|
response:
|
||||||
|
value:
|
||||||
|
- active: "1"
|
||||||
|
attributes:
|
||||||
|
force_pw_update: "0"
|
||||||
|
mailbox_format: "maildir:"
|
||||||
|
quarantine_notification: never
|
||||||
|
sogo_access: "1"
|
||||||
|
tls_enforce_in: "0"
|
||||||
|
tls_enforce_out: "0"
|
||||||
|
domain: domain3.tld
|
||||||
|
is_relayed: 0
|
||||||
|
local_part: info
|
||||||
|
max_new_quota: 10737418240
|
||||||
|
messages: 0
|
||||||
|
name: Full name
|
||||||
|
percent_class: success
|
||||||
|
percent_in_use: 0
|
||||||
|
quota: 3221225472
|
||||||
|
quota_used: 0
|
||||||
|
rl: false
|
||||||
|
spam_aliases: 0
|
||||||
|
username: info@domain3.tld
|
||||||
|
tags: ["tag1", "tag2"]
|
||||||
|
description: OK
|
||||||
|
headers: {}
|
||||||
|
tags:
|
||||||
|
- Mailboxes
|
||||||
|
description: You can list all mailboxes existing in system for a specific domain.
|
||||||
|
operationId: Get mailboxes of a domain
|
||||||
|
summary: Get mailboxes of a domain
|
||||||
|
|
||||||
tags:
|
tags:
|
||||||
- name: Domains
|
- name: Domains
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
window.onload = function() {
|
||||||
|
// Begin Swagger UI call region
|
||||||
|
const ui = SwaggerUIBundle({
|
||||||
|
urls: [{url: "/api/openapi.yaml", name: "mailcow API"}],
|
||||||
|
dom_id: '#swagger-ui',
|
||||||
|
deepLinking: true,
|
||||||
|
presets: [
|
||||||
|
SwaggerUIBundle.presets.apis,
|
||||||
|
SwaggerUIStandalonePreset
|
||||||
|
],
|
||||||
|
plugins: [
|
||||||
|
SwaggerUIBundle.plugins.DownloadUrl
|
||||||
|
],
|
||||||
|
layout: "StandaloneLayout"
|
||||||
|
});
|
||||||
|
// End Swagger UI call region
|
||||||
|
|
||||||
|
window.ui = ui;
|
||||||
|
};
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -68,7 +68,7 @@ if (empty($_SERVER['PHP_AUTH_USER']) || empty($_SERVER['PHP_AUTH_PW'])) {
|
|||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
$login_role = check_login($login_user, $login_pass, true);
|
$login_role = check_login($login_user, $login_pass, array('eas' => TRUE));
|
||||||
|
|
||||||
if ($login_role === "user") {
|
if ($login_role === "user") {
|
||||||
header("Content-Type: application/xml");
|
header("Content-Type: application/xml");
|
||||||
|
|||||||
-11
File diff suppressed because one or more lines are too long
+1
-1
@@ -1 +1 @@
|
|||||||
@media (max-width:1050px){.navbar-header{float:none}.navbar-left,.navbar-nav,.navbar-right{float:none!important}.navbar-toggle{display:block}.navbar-collapse{border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-collapse.collapse{display:none!important}.navbar-nav{margin-top:7.5px}.navbar-nav>li{float:none}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px}.collapse.in{display:block!important}.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}}
|
@media (max-width:1050px){.navbar-header{float:none}.navbar-left,.navbar-nav,.navbar-right{float:none!important}.navbar-toggle{display:block}.navbar-collapse{border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-nav{margin-top:7.5px}.navbar-nav>li{float:none}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px}.collapse.in{display:block!important}.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}}
|
||||||
@@ -0,0 +1,487 @@
|
|||||||
|
/*!
|
||||||
|
* Bootstrap-select v1.14.0-beta2 (https://developer.snapappointments.com/bootstrap-select)
|
||||||
|
*
|
||||||
|
* Copyright 2012-2021 SnapAppointments, LLC
|
||||||
|
* Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE)
|
||||||
|
*/
|
||||||
|
|
||||||
|
@-webkit-keyframes bs-notify-fadeOut {
|
||||||
|
0% {
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-o-keyframes bs-notify-fadeOut {
|
||||||
|
0% {
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes bs-notify-fadeOut {
|
||||||
|
0% {
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
select.bs-select-hidden,
|
||||||
|
.bootstrap-select > select.bs-select-hidden,
|
||||||
|
select.selectpicker {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
.bootstrap-select {
|
||||||
|
width: 220px \0;
|
||||||
|
/*IE9 and below*/
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
.bootstrap-select > .dropdown-toggle {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
text-align: right;
|
||||||
|
white-space: nowrap;
|
||||||
|
display: -webkit-inline-box;
|
||||||
|
display: -webkit-inline-flex;
|
||||||
|
display: -ms-inline-flexbox;
|
||||||
|
display: inline-flex;
|
||||||
|
-webkit-box-align: center;
|
||||||
|
-webkit-align-items: center;
|
||||||
|
-ms-flex-align: center;
|
||||||
|
align-items: center;
|
||||||
|
-webkit-box-pack: justify;
|
||||||
|
-webkit-justify-content: space-between;
|
||||||
|
-ms-flex-pack: justify;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.bootstrap-select > .dropdown-toggle:after {
|
||||||
|
margin-top: -1px;
|
||||||
|
}
|
||||||
|
.bootstrap-select > .dropdown-toggle.bs-placeholder,
|
||||||
|
.bootstrap-select > .dropdown-toggle.bs-placeholder:hover,
|
||||||
|
.bootstrap-select > .dropdown-toggle.bs-placeholder:focus,
|
||||||
|
.bootstrap-select > .dropdown-toggle.bs-placeholder:active {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-primary,
|
||||||
|
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-secondary,
|
||||||
|
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-success,
|
||||||
|
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-danger,
|
||||||
|
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-info,
|
||||||
|
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-dark,
|
||||||
|
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-primary:hover,
|
||||||
|
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-secondary:hover,
|
||||||
|
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-success:hover,
|
||||||
|
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-danger:hover,
|
||||||
|
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-info:hover,
|
||||||
|
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-dark:hover,
|
||||||
|
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-primary:focus,
|
||||||
|
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-secondary:focus,
|
||||||
|
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-success:focus,
|
||||||
|
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-danger:focus,
|
||||||
|
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-info:focus,
|
||||||
|
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-dark:focus,
|
||||||
|
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-primary:active,
|
||||||
|
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-secondary:active,
|
||||||
|
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-success:active,
|
||||||
|
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-danger:active,
|
||||||
|
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-info:active,
|
||||||
|
.bootstrap-select > .dropdown-toggle.bs-placeholder.btn-dark:active {
|
||||||
|
color: rgba(255, 255, 255, 0.5);
|
||||||
|
}
|
||||||
|
.bootstrap-select > select {
|
||||||
|
position: absolute !important;
|
||||||
|
bottom: 0;
|
||||||
|
left: 50%;
|
||||||
|
display: block !important;
|
||||||
|
width: 0.5px !important;
|
||||||
|
height: 100% !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
opacity: 0 !important;
|
||||||
|
border: none;
|
||||||
|
z-index: 0 !important;
|
||||||
|
}
|
||||||
|
.bootstrap-select > select.mobile-device {
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
display: block !important;
|
||||||
|
width: 100% !important;
|
||||||
|
z-index: 2 !important;
|
||||||
|
}
|
||||||
|
.has-error .bootstrap-select .dropdown-toggle,
|
||||||
|
.error .bootstrap-select .dropdown-toggle,
|
||||||
|
.bootstrap-select.is-invalid .dropdown-toggle,
|
||||||
|
.was-validated .bootstrap-select select:invalid + .dropdown-toggle {
|
||||||
|
border-color: #b94a48;
|
||||||
|
}
|
||||||
|
.bootstrap-select.is-valid .dropdown-toggle,
|
||||||
|
.was-validated .bootstrap-select select:valid + .dropdown-toggle {
|
||||||
|
border-color: #28a745;
|
||||||
|
}
|
||||||
|
.bootstrap-select.fit-width {
|
||||||
|
width: auto !important;
|
||||||
|
}
|
||||||
|
.bootstrap-select:not([class*="col-"]):not([class*="form-control"]):not(.input-group-btn) {
|
||||||
|
width: 220px;
|
||||||
|
}
|
||||||
|
.bootstrap-select > select.mobile-device:focus + .dropdown-toggle,
|
||||||
|
.bootstrap-select .dropdown-toggle:focus {
|
||||||
|
outline: thin dotted #333333 !important;
|
||||||
|
outline: 5px auto -webkit-focus-ring-color !important;
|
||||||
|
outline-offset: -2px;
|
||||||
|
}
|
||||||
|
.bootstrap-select.form-control {
|
||||||
|
margin-bottom: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: none;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
:not(.input-group) > .bootstrap-select.form-control:not([class*="col-"]) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.bootstrap-select.form-control.input-group-btn {
|
||||||
|
float: none;
|
||||||
|
z-index: auto;
|
||||||
|
}
|
||||||
|
.form-inline .bootstrap-select,
|
||||||
|
.form-inline .bootstrap-select.form-control:not([class*="col-"]) {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
.bootstrap-select:not(.input-group-btn),
|
||||||
|
.bootstrap-select[class*="col-"] {
|
||||||
|
float: none;
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
.bootstrap-select.dropdown-menu-right,
|
||||||
|
.bootstrap-select[class*="col-"].dropdown-menu-right,
|
||||||
|
.row .bootstrap-select[class*="col-"].dropdown-menu-right {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
.form-inline .bootstrap-select,
|
||||||
|
.form-horizontal .bootstrap-select,
|
||||||
|
.form-group .bootstrap-select {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
.form-group-lg .bootstrap-select.form-control,
|
||||||
|
.form-group-sm .bootstrap-select.form-control {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.form-group-lg .bootstrap-select.form-control .dropdown-toggle,
|
||||||
|
.form-group-sm .bootstrap-select.form-control .dropdown-toggle {
|
||||||
|
height: 100%;
|
||||||
|
font-size: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
border-radius: inherit;
|
||||||
|
}
|
||||||
|
.bootstrap-select.form-control-sm .dropdown-toggle,
|
||||||
|
.bootstrap-select.form-control-lg .dropdown-toggle {
|
||||||
|
font-size: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
border-radius: inherit;
|
||||||
|
}
|
||||||
|
.bootstrap-select.form-control-sm .dropdown-toggle {
|
||||||
|
padding: 0.25rem 0.5rem;
|
||||||
|
}
|
||||||
|
.bootstrap-select.form-control-lg .dropdown-toggle {
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
}
|
||||||
|
.form-inline .bootstrap-select .form-control {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.bootstrap-select.disabled,
|
||||||
|
.bootstrap-select > .disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
.bootstrap-select.disabled:focus,
|
||||||
|
.bootstrap-select > .disabled:focus {
|
||||||
|
outline: none !important;
|
||||||
|
}
|
||||||
|
.bootstrap-select.bs-container {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 0 !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
.bootstrap-select.bs-container .dropdown-menu {
|
||||||
|
z-index: 1060;
|
||||||
|
}
|
||||||
|
.bootstrap-select .dropdown-toggle .filter-option {
|
||||||
|
position: static;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
float: left;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
text-align: left;
|
||||||
|
overflow: hidden;
|
||||||
|
-webkit-box-flex: 0;
|
||||||
|
-webkit-flex: 0 1 auto;
|
||||||
|
-ms-flex: 0 1 auto;
|
||||||
|
flex: 0 1 auto;
|
||||||
|
}
|
||||||
|
.bs3.bootstrap-select .dropdown-toggle .filter-option {
|
||||||
|
padding-right: inherit;
|
||||||
|
}
|
||||||
|
.input-group .bs3-has-addon.bootstrap-select .dropdown-toggle .filter-option {
|
||||||
|
position: absolute;
|
||||||
|
padding-top: inherit;
|
||||||
|
padding-bottom: inherit;
|
||||||
|
padding-left: inherit;
|
||||||
|
float: none;
|
||||||
|
}
|
||||||
|
.input-group .bs3-has-addon.bootstrap-select .dropdown-toggle .filter-option .filter-option-inner {
|
||||||
|
padding-right: inherit;
|
||||||
|
}
|
||||||
|
.bootstrap-select .dropdown-toggle .filter-option-inner-inner {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.bootstrap-select .dropdown-toggle .filter-expand {
|
||||||
|
width: 0 !important;
|
||||||
|
float: left;
|
||||||
|
opacity: 0 !important;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.bootstrap-select .dropdown-toggle .caret {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
right: 12px;
|
||||||
|
margin-top: -2px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
.bootstrap-select .dropdown-toggle .bs-select-clear-selected {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
margin-right: 5px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.bs3.bootstrap-select .dropdown-toggle .bs-select-clear-selected {
|
||||||
|
padding-right: inherit;
|
||||||
|
}
|
||||||
|
.bootstrap-select .dropdown-toggle .bs-select-clear-selected span {
|
||||||
|
position: relative;
|
||||||
|
top: -webkit-calc(((-1em / 1.5) + 1ex) / 2);
|
||||||
|
top: calc(((-1em / 1.5) + 1ex) / 2);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.bs3.bootstrap-select .dropdown-toggle .bs-select-clear-selected span {
|
||||||
|
top: auto;
|
||||||
|
}
|
||||||
|
.bootstrap-select .dropdown-toggle.bs-placeholder .bs-select-clear-selected {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.input-group .bootstrap-select.form-control .dropdown-toggle {
|
||||||
|
border-radius: inherit;
|
||||||
|
}
|
||||||
|
.bootstrap-select[class*="col-"] .dropdown-toggle {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.bootstrap-select .dropdown-menu {
|
||||||
|
min-width: 100%;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.bootstrap-select .dropdown-menu > .inner:focus {
|
||||||
|
outline: none !important;
|
||||||
|
}
|
||||||
|
.bootstrap-select .dropdown-menu.inner {
|
||||||
|
position: static;
|
||||||
|
float: none;
|
||||||
|
border: 0;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
-webkit-box-shadow: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
.bootstrap-select .dropdown-menu li {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.bootstrap-select .dropdown-menu li.active small {
|
||||||
|
color: rgba(255, 255, 255, 0.5) !important;
|
||||||
|
}
|
||||||
|
.bootstrap-select .dropdown-menu li.disabled a {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
.bootstrap-select .dropdown-menu li a {
|
||||||
|
cursor: pointer;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
.bootstrap-select .dropdown-menu li a.opt {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 2.25em;
|
||||||
|
}
|
||||||
|
.bootstrap-select .dropdown-menu li a span.check-mark {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.bootstrap-select .dropdown-menu li a span.text {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.bootstrap-select .dropdown-menu li small {
|
||||||
|
padding-left: 0.5em;
|
||||||
|
}
|
||||||
|
.bootstrap-select .dropdown-menu .notify {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 5px;
|
||||||
|
width: 96%;
|
||||||
|
margin: 0 2%;
|
||||||
|
min-height: 26px;
|
||||||
|
padding: 3px 5px;
|
||||||
|
background: #f5f5f5;
|
||||||
|
border: 1px solid #e3e3e3;
|
||||||
|
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
|
||||||
|
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0.9;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.bootstrap-select .dropdown-menu .notify.fadeOut {
|
||||||
|
-webkit-animation: 300ms linear 750ms forwards bs-notify-fadeOut;
|
||||||
|
-o-animation: 300ms linear 750ms forwards bs-notify-fadeOut;
|
||||||
|
animation: 300ms linear 750ms forwards bs-notify-fadeOut;
|
||||||
|
}
|
||||||
|
.bootstrap-select .no-results {
|
||||||
|
padding: 3px;
|
||||||
|
background: #f5f5f5;
|
||||||
|
margin: 0 5px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.bootstrap-select.fit-width .dropdown-toggle .filter-option {
|
||||||
|
position: static;
|
||||||
|
display: inline;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.bootstrap-select.fit-width .dropdown-toggle .filter-option-inner,
|
||||||
|
.bootstrap-select.fit-width .dropdown-toggle .filter-option-inner-inner {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
.bootstrap-select.fit-width .dropdown-toggle .bs-caret:before {
|
||||||
|
content: '\00a0';
|
||||||
|
}
|
||||||
|
.bootstrap-select.fit-width .dropdown-toggle .caret {
|
||||||
|
position: static;
|
||||||
|
top: auto;
|
||||||
|
margin-top: -1px;
|
||||||
|
}
|
||||||
|
.bootstrap-select.show-tick .dropdown-menu .selected span.check-mark {
|
||||||
|
position: absolute;
|
||||||
|
display: inline-block;
|
||||||
|
right: 15px;
|
||||||
|
top: 5px;
|
||||||
|
}
|
||||||
|
.bootstrap-select.show-tick .dropdown-menu li a span.text {
|
||||||
|
margin-right: 34px;
|
||||||
|
}
|
||||||
|
.bootstrap-select .bs-ok-default:after {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
width: 0.5em;
|
||||||
|
height: 1em;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 0 0.26em 0.26em 0;
|
||||||
|
-webkit-transform-style: preserve-3d;
|
||||||
|
transform-style: preserve-3d;
|
||||||
|
-webkit-transform: rotate(45deg);
|
||||||
|
-ms-transform: rotate(45deg);
|
||||||
|
-o-transform: rotate(45deg);
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
.bootstrap-select.show-menu-arrow.open > .dropdown-toggle,
|
||||||
|
.bootstrap-select.show-menu-arrow.show > .dropdown-toggle {
|
||||||
|
z-index: 1061;
|
||||||
|
}
|
||||||
|
.bootstrap-select.show-menu-arrow .dropdown-toggle .filter-option:before {
|
||||||
|
content: '';
|
||||||
|
border-left: 7px solid transparent;
|
||||||
|
border-right: 7px solid transparent;
|
||||||
|
border-bottom: 7px solid rgba(204, 204, 204, 0.2);
|
||||||
|
position: absolute;
|
||||||
|
bottom: -4px;
|
||||||
|
left: 9px;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.bootstrap-select.show-menu-arrow .dropdown-toggle .filter-option:after {
|
||||||
|
content: '';
|
||||||
|
border-left: 6px solid transparent;
|
||||||
|
border-right: 6px solid transparent;
|
||||||
|
border-bottom: 6px solid white;
|
||||||
|
position: absolute;
|
||||||
|
bottom: -4px;
|
||||||
|
left: 10px;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle .filter-option:before {
|
||||||
|
bottom: auto;
|
||||||
|
top: -4px;
|
||||||
|
border-top: 7px solid rgba(204, 204, 204, 0.2);
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle .filter-option:after {
|
||||||
|
bottom: auto;
|
||||||
|
top: -4px;
|
||||||
|
border-top: 6px solid white;
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle .filter-option:before {
|
||||||
|
right: 12px;
|
||||||
|
left: auto;
|
||||||
|
}
|
||||||
|
.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle .filter-option:after {
|
||||||
|
right: 13px;
|
||||||
|
left: auto;
|
||||||
|
}
|
||||||
|
.bootstrap-select.show-menu-arrow.open > .dropdown-toggle .filter-option:before,
|
||||||
|
.bootstrap-select.show-menu-arrow.show > .dropdown-toggle .filter-option:before,
|
||||||
|
.bootstrap-select.show-menu-arrow.open > .dropdown-toggle .filter-option:after,
|
||||||
|
.bootstrap-select.show-menu-arrow.show > .dropdown-toggle .filter-option:after {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.bs-searchbox,
|
||||||
|
.bs-actionsbox,
|
||||||
|
.bs-donebutton {
|
||||||
|
padding: 4px 8px;
|
||||||
|
}
|
||||||
|
.bs-actionsbox {
|
||||||
|
width: 100%;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.bs-actionsbox .btn-group {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.bs-actionsbox .btn-group button {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
.bs-donebutton {
|
||||||
|
float: left;
|
||||||
|
width: 100%;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.bs-donebutton .btn-group {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.bs-donebutton .btn-group button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.bs-searchbox + .bs-actionsbox {
|
||||||
|
padding: 0 8px 4px;
|
||||||
|
}
|
||||||
|
.bs-searchbox .form-control {
|
||||||
|
margin-bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
float: none;
|
||||||
|
}
|
||||||
|
/*# sourceMappingURL=bootstrap-select.css.map */
|
||||||
File diff suppressed because one or more lines are too long
-323
@@ -1,323 +0,0 @@
|
|||||||
table.footable-details,
|
|
||||||
table.footable > thead > tr.footable-filtering > th div.form-group {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
table.footable,
|
|
||||||
table.footable-details {
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
border-spacing: 0;
|
|
||||||
border-collapse: collapse;
|
|
||||||
}
|
|
||||||
table.footable-hide-fouc {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
table > tbody > tr > td > span.footable-toggle {
|
|
||||||
margin-right: 8px;
|
|
||||||
opacity: 0.3;
|
|
||||||
}
|
|
||||||
table > tbody > tr > td > span.footable-toggle.last-column {
|
|
||||||
margin-left: 8px;
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
table.table-condensed > tbody > tr > td > span.footable-toggle {
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
table.footable-details > tbody > tr > th:nth-child(1) {
|
|
||||||
min-width: 40px;
|
|
||||||
width: 120px;
|
|
||||||
}
|
|
||||||
table.footable-details > tbody > tr > td:nth-child(2) {
|
|
||||||
word-break: break-all;
|
|
||||||
}
|
|
||||||
table.footable-details > tbody > tr:first-child > td,
|
|
||||||
table.footable-details > tbody > tr:first-child > th,
|
|
||||||
table.footable-details > tfoot > tr:first-child > td,
|
|
||||||
table.footable-details > tfoot > tr:first-child > th,
|
|
||||||
table.footable-details > thead > tr:first-child > td,
|
|
||||||
table.footable-details > thead > tr:first-child > th {
|
|
||||||
border-top-width: 0;
|
|
||||||
}
|
|
||||||
table.footable-details.table-bordered > tbody > tr:first-child > td,
|
|
||||||
table.footable-details.table-bordered > tbody > tr:first-child > th,
|
|
||||||
table.footable-details.table-bordered > tfoot > tr:first-child > td,
|
|
||||||
table.footable-details.table-bordered > tfoot > tr:first-child > th,
|
|
||||||
table.footable-details.table-bordered > thead > tr:first-child > td,
|
|
||||||
table.footable-details.table-bordered > thead > tr:first-child > th {
|
|
||||||
border-top-width: 1px;
|
|
||||||
}
|
|
||||||
div.footable-loader {
|
|
||||||
vertical-align: middle;
|
|
||||||
text-align: center;
|
|
||||||
height: 300px;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
div.footable-loader > span.fooicon {
|
|
||||||
display: inline-block;
|
|
||||||
opacity: 0.3;
|
|
||||||
font-size: 30px;
|
|
||||||
line-height: 32px;
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
margin-top: -16px;
|
|
||||||
margin-left: -16px;
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
-webkit-animation: fooicon-spin-r 2s infinite linear;
|
|
||||||
animation: fooicon-spin-r 2s infinite linear;
|
|
||||||
}
|
|
||||||
table.footable > tbody > tr.footable-empty > td {
|
|
||||||
vertical-align: middle;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 30px;
|
|
||||||
}
|
|
||||||
table.footable > tbody > tr > td,
|
|
||||||
table.footable > tbody > tr > th {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
table.footable > tbody > tr.footable-detail-row > td,
|
|
||||||
table.footable > tbody > tr.footable-detail-row > th,
|
|
||||||
table.footable > tbody > tr.footable-empty > td,
|
|
||||||
table.footable > tbody > tr.footable-empty > th {
|
|
||||||
display: table-cell;
|
|
||||||
}
|
|
||||||
@-webkit-keyframes fooicon-spin-r {
|
|
||||||
0% {
|
|
||||||
-webkit-transform: rotate(0);
|
|
||||||
transform: rotate(0);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
-webkit-transform: rotate(359deg);
|
|
||||||
transform: rotate(359deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@keyframes fooicon-spin-r {
|
|
||||||
0% {
|
|
||||||
-webkit-transform: rotate(0);
|
|
||||||
transform: rotate(0);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
-webkit-transform: rotate(359deg);
|
|
||||||
transform: rotate(359deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.fooicon {
|
|
||||||
position: relative;
|
|
||||||
top: 0px;
|
|
||||||
display: inline-block;
|
|
||||||
font-family: "bootstrap-icons" !important;
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
line-height: 1;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
}
|
|
||||||
@-moz-document url-prefix() {
|
|
||||||
.fooicon {
|
|
||||||
top: 2px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.fooicon:after,
|
|
||||||
.fooicon:before {
|
|
||||||
-webkit-box-sizing: border-box;
|
|
||||||
-moz-box-sizing: border-box;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
.fooicon-loader:before {
|
|
||||||
content: "\f130";
|
|
||||||
}
|
|
||||||
.fooicon-plus:before {
|
|
||||||
content: "\f4fc";
|
|
||||||
}
|
|
||||||
.fooicon-minus:before {
|
|
||||||
content: "\f2e8";
|
|
||||||
}
|
|
||||||
.fooicon-search:before {
|
|
||||||
content: "\f52a";
|
|
||||||
}
|
|
||||||
.fooicon-remove:before {
|
|
||||||
content: "\f62a";
|
|
||||||
}
|
|
||||||
.fooicon-sort:before {
|
|
||||||
content: "\f3c6";
|
|
||||||
}
|
|
||||||
.fooicon-sort-asc:before {
|
|
||||||
content: "\f575";
|
|
||||||
}
|
|
||||||
.fooicon-sort-desc:before {
|
|
||||||
content: "\f57b";
|
|
||||||
}
|
|
||||||
.fooicon-pencil:before {
|
|
||||||
content: "\f4c9";
|
|
||||||
}
|
|
||||||
.fooicon-trash:before {
|
|
||||||
content: "\f62a";
|
|
||||||
}
|
|
||||||
.fooicon-eye-close:before {
|
|
||||||
content: "\f33f";
|
|
||||||
}
|
|
||||||
.fooicon-flash:before {
|
|
||||||
content: "\f46e";
|
|
||||||
}
|
|
||||||
.fooicon-cog:before {
|
|
||||||
content: "\f3e2";
|
|
||||||
}
|
|
||||||
.fooicon-stats:before {
|
|
||||||
content: "\f359";
|
|
||||||
}
|
|
||||||
table.footable > thead > tr.footable-filtering > th {
|
|
||||||
border-bottom-width: 1px;
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
.footable-filtering-external.footable-filtering-right,
|
|
||||||
table.footable.footable-filtering-right > thead > tr.footable-filtering > th,
|
|
||||||
table.footable > thead > tr.footable-filtering > th {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
.footable-filtering-external.footable-filtering-left,
|
|
||||||
table.footable.footable-filtering-left > thead > tr.footable-filtering > th {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
.footable-filtering-external.footable-filtering-center,
|
|
||||||
.footable-paging-external.footable-paging-center,
|
|
||||||
table.footable-paging-center > tfoot > tr.footable-paging > td,
|
|
||||||
table.footable.footable-filtering-center > thead > tr.footable-filtering > th,
|
|
||||||
table.footable > tfoot > tr.footable-paging > td {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
table.footable > thead > tr.footable-filtering > th div.form-group + div.form-group {
|
|
||||||
margin-top: 5px;
|
|
||||||
}
|
|
||||||
table.footable > thead > tr.footable-filtering > th div.input-group {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.footable-filtering-external ul.dropdown-menu > li > a.checkbox,
|
|
||||||
table.footable > thead > tr.footable-filtering > th ul.dropdown-menu > li > a.checkbox {
|
|
||||||
margin: 0;
|
|
||||||
display: block;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.footable-filtering-external ul.dropdown-menu > li > a.checkbox > label,
|
|
||||||
table.footable > thead > tr.footable-filtering > th ul.dropdown-menu > li > a.checkbox > label {
|
|
||||||
display: block;
|
|
||||||
padding-left: 20px;
|
|
||||||
}
|
|
||||||
.footable-filtering-external ul.dropdown-menu > li > a.checkbox input[type="checkbox"],
|
|
||||||
table.footable > thead > tr.footable-filtering > th ul.dropdown-menu > li > a.checkbox input[type="checkbox"] {
|
|
||||||
position: absolute;
|
|
||||||
margin-left: -20px;
|
|
||||||
}
|
|
||||||
@media (min-width: 768px) {
|
|
||||||
table.footable > thead > tr.footable-filtering > th div.input-group {
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
table.footable > thead > tr.footable-filtering > th div.form-group {
|
|
||||||
margin-left: 2px;
|
|
||||||
margin-right: 2px;
|
|
||||||
}
|
|
||||||
table.footable > thead > tr.footable-filtering > th div.form-group + div.form-group {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
table.footable > tbody > tr > td.footable-sortable,
|
|
||||||
table.footable > tbody > tr > th.footable-sortable,
|
|
||||||
table.footable > tfoot > tr > td.footable-sortable,
|
|
||||||
table.footable > tfoot > tr > th.footable-sortable,
|
|
||||||
table.footable > thead > tr > td.footable-sortable,
|
|
||||||
table.footable > thead > tr > th.footable-sortable {
|
|
||||||
position: relative;
|
|
||||||
padding-right: 30px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
td.footable-sortable > span.fooicon,
|
|
||||||
th.footable-sortable > span.fooicon {
|
|
||||||
position: absolute;
|
|
||||||
right: 6px;
|
|
||||||
top: 50%;
|
|
||||||
margin-top: -7px;
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity 0.3s ease-in;
|
|
||||||
}
|
|
||||||
td.footable-sortable.footable-asc > span.fooicon,
|
|
||||||
td.footable-sortable.footable-desc > span.fooicon,
|
|
||||||
td.footable-sortable:hover > span.fooicon,
|
|
||||||
th.footable-sortable.footable-asc > span.fooicon,
|
|
||||||
th.footable-sortable.footable-desc > span.fooicon,
|
|
||||||
th.footable-sortable:hover > span.fooicon {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
table.footable-sorting-disabled td.footable-sortable.footable-asc > span.fooicon,
|
|
||||||
table.footable-sorting-disabled td.footable-sortable.footable-desc > span.fooicon,
|
|
||||||
table.footable-sorting-disabled td.footable-sortable:hover > span.fooicon,
|
|
||||||
table.footable-sorting-disabled th.footable-sortable.footable-asc > span.fooicon,
|
|
||||||
table.footable-sorting-disabled th.footable-sortable.footable-desc > span.fooicon,
|
|
||||||
table.footable-sorting-disabled th.footable-sortable:hover > span.fooicon {
|
|
||||||
opacity: 0;
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
.footable-paging-external ul.pagination,
|
|
||||||
table.footable > tfoot > tr.footable-paging > td > ul.pagination {
|
|
||||||
margin: 10px 0 0;
|
|
||||||
}
|
|
||||||
.footable-paging-external span.label,
|
|
||||||
table.footable > tfoot > tr.footable-paging > td > span.label {
|
|
||||||
display: inline-block;
|
|
||||||
margin: 0 0 10px;
|
|
||||||
padding: 4px 10px;
|
|
||||||
}
|
|
||||||
.footable-paging-external.footable-paging-left,
|
|
||||||
table.footable-paging-left > tfoot > tr.footable-paging > td {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
.footable-paging-external.footable-paging-right,
|
|
||||||
table.footable-editing-right td.footable-editing,
|
|
||||||
table.footable-editing-right tr.footable-editing,
|
|
||||||
table.footable-paging-right > tfoot > tr.footable-paging > td {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
ul.pagination > li.footable-page {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
ul.pagination > li.footable-page.visible {
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
td.footable-editing {
|
|
||||||
width: 90px;
|
|
||||||
max-width: 90px;
|
|
||||||
}
|
|
||||||
table.footable-editing-no-delete td.footable-editing,
|
|
||||||
table.footable-editing-no-edit td.footable-editing,
|
|
||||||
table.footable-editing-no-view td.footable-editing {
|
|
||||||
width: 70px;
|
|
||||||
max-width: 70px;
|
|
||||||
}
|
|
||||||
table.footable-editing-no-delete.footable-editing-no-view td.footable-editing,
|
|
||||||
table.footable-editing-no-edit.footable-editing-no-delete td.footable-editing,
|
|
||||||
table.footable-editing-no-edit.footable-editing-no-view td.footable-editing {
|
|
||||||
width: 50px;
|
|
||||||
max-width: 50px;
|
|
||||||
}
|
|
||||||
table.footable-editing-no-edit.footable-editing-no-delete.footable-editing-no-view td.footable-editing,
|
|
||||||
table.footable-editing-no-edit.footable-editing-no-delete.footable-editing-no-view th.footable-editing {
|
|
||||||
width: 0;
|
|
||||||
max-width: 0;
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
table.footable-editing-left td.footable-editing,
|
|
||||||
table.footable-editing-left tr.footable-editing {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
table.footable-editing button.footable-add,
|
|
||||||
table.footable-editing button.footable-hide,
|
|
||||||
table.footable-editing-show button.footable-show,
|
|
||||||
table.footable-editing.footable-editing-always-show button.footable-hide,
|
|
||||||
table.footable-editing.footable-editing-always-show button.footable-show,
|
|
||||||
table.footable-editing.footable-editing-always-show.footable-editing-no-add tr.footable-editing {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
table.footable-editing.footable-editing-always-show button.footable-add,
|
|
||||||
table.footable-editing.footable-editing-show button.footable-add,
|
|
||||||
table.footable-editing.footable-editing-show button.footable-hide {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
+1
-1
File diff suppressed because one or more lines are too long
+10
-10
File diff suppressed because one or more lines are too long
Vendored
Vendored
@@ -0,0 +1,693 @@
|
|||||||
|
/*
|
||||||
|
* This combined file was created by the DataTables downloader builder:
|
||||||
|
* https://datatables.net/download
|
||||||
|
*
|
||||||
|
* To rebuild or modify this file with the latest versions of the included
|
||||||
|
* software please visit:
|
||||||
|
* https://datatables.net/download/#bs5/dt-1.12.0/r-2.3.0/sl-1.4.0
|
||||||
|
*
|
||||||
|
* Included libraries:
|
||||||
|
* DataTables 1.12.0, Responsive 2.3.0, Select 1.4.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
@charset "UTF-8";
|
||||||
|
table.dataTable td.dt-control {
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
table.dataTable td.dt-control:before {
|
||||||
|
height: 1em;
|
||||||
|
width: 1em;
|
||||||
|
margin-top: -9px;
|
||||||
|
display: inline-block;
|
||||||
|
color: white;
|
||||||
|
border: 0.15em solid white;
|
||||||
|
border-radius: 1em;
|
||||||
|
box-shadow: 0 0 0.2em #444;
|
||||||
|
box-sizing: content-box;
|
||||||
|
text-align: center;
|
||||||
|
text-indent: 0 !important;
|
||||||
|
font-family: "Courier New", Courier, monospace;
|
||||||
|
line-height: 1em;
|
||||||
|
content: "+";
|
||||||
|
background-color: #31b131;
|
||||||
|
}
|
||||||
|
table.dataTable tr.dt-hasChild td.dt-control:before {
|
||||||
|
content: "-";
|
||||||
|
background-color: #d33333;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.dataTable thead > tr > th.sorting, table.dataTable thead > tr > th.sorting_asc, table.dataTable thead > tr > th.sorting_desc, table.dataTable thead > tr > th.sorting_asc_disabled, table.dataTable thead > tr > th.sorting_desc_disabled,
|
||||||
|
table.dataTable thead > tr > td.sorting,
|
||||||
|
table.dataTable thead > tr > td.sorting_asc,
|
||||||
|
table.dataTable thead > tr > td.sorting_desc,
|
||||||
|
table.dataTable thead > tr > td.sorting_asc_disabled,
|
||||||
|
table.dataTable thead > tr > td.sorting_desc_disabled {
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
padding-right: 26px;
|
||||||
|
}
|
||||||
|
table.dataTable thead > tr > th.sorting:before, table.dataTable thead > tr > th.sorting:after, table.dataTable thead > tr > th.sorting_asc:before, table.dataTable thead > tr > th.sorting_asc:after, table.dataTable thead > tr > th.sorting_desc:before, table.dataTable thead > tr > th.sorting_desc:after, table.dataTable thead > tr > th.sorting_asc_disabled:before, table.dataTable thead > tr > th.sorting_asc_disabled:after, table.dataTable thead > tr > th.sorting_desc_disabled:before, table.dataTable thead > tr > th.sorting_desc_disabled:after,
|
||||||
|
table.dataTable thead > tr > td.sorting:before,
|
||||||
|
table.dataTable thead > tr > td.sorting:after,
|
||||||
|
table.dataTable thead > tr > td.sorting_asc:before,
|
||||||
|
table.dataTable thead > tr > td.sorting_asc:after,
|
||||||
|
table.dataTable thead > tr > td.sorting_desc:before,
|
||||||
|
table.dataTable thead > tr > td.sorting_desc:after,
|
||||||
|
table.dataTable thead > tr > td.sorting_asc_disabled:before,
|
||||||
|
table.dataTable thead > tr > td.sorting_asc_disabled:after,
|
||||||
|
table.dataTable thead > tr > td.sorting_desc_disabled:before,
|
||||||
|
table.dataTable thead > tr > td.sorting_desc_disabled:after {
|
||||||
|
position: absolute;
|
||||||
|
display: block;
|
||||||
|
opacity: 0.125;
|
||||||
|
right: 10px;
|
||||||
|
line-height: 9px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
table.dataTable thead > tr > th.sorting:before, table.dataTable thead > tr > th.sorting_asc:before, table.dataTable thead > tr > th.sorting_desc:before, table.dataTable thead > tr > th.sorting_asc_disabled:before, table.dataTable thead > tr > th.sorting_desc_disabled:before,
|
||||||
|
table.dataTable thead > tr > td.sorting:before,
|
||||||
|
table.dataTable thead > tr > td.sorting_asc:before,
|
||||||
|
table.dataTable thead > tr > td.sorting_desc:before,
|
||||||
|
table.dataTable thead > tr > td.sorting_asc_disabled:before,
|
||||||
|
table.dataTable thead > tr > td.sorting_desc_disabled:before {
|
||||||
|
bottom: 50%;
|
||||||
|
content: "▴";
|
||||||
|
}
|
||||||
|
table.dataTable thead > tr > th.sorting:after, table.dataTable thead > tr > th.sorting_asc:after, table.dataTable thead > tr > th.sorting_desc:after, table.dataTable thead > tr > th.sorting_asc_disabled:after, table.dataTable thead > tr > th.sorting_desc_disabled:after,
|
||||||
|
table.dataTable thead > tr > td.sorting:after,
|
||||||
|
table.dataTable thead > tr > td.sorting_asc:after,
|
||||||
|
table.dataTable thead > tr > td.sorting_desc:after,
|
||||||
|
table.dataTable thead > tr > td.sorting_asc_disabled:after,
|
||||||
|
table.dataTable thead > tr > td.sorting_desc_disabled:after {
|
||||||
|
top: 50%;
|
||||||
|
content: "▾";
|
||||||
|
}
|
||||||
|
table.dataTable thead > tr > th.sorting_asc:before, table.dataTable thead > tr > th.sorting_desc:after,
|
||||||
|
table.dataTable thead > tr > td.sorting_asc:before,
|
||||||
|
table.dataTable thead > tr > td.sorting_desc:after {
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
table.dataTable thead > tr > th.sorting_desc_disabled:after, table.dataTable thead > tr > th.sorting_asc_disabled:before,
|
||||||
|
table.dataTable thead > tr > td.sorting_desc_disabled:after,
|
||||||
|
table.dataTable thead > tr > td.sorting_asc_disabled:before {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
table.dataTable thead > tr > th:active,
|
||||||
|
table.dataTable thead > tr > td:active {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.dataTables_scrollBody table.dataTable thead > tr > th:before, div.dataTables_scrollBody table.dataTable thead > tr > th:after,
|
||||||
|
div.dataTables_scrollBody table.dataTable thead > tr > td:before,
|
||||||
|
div.dataTables_scrollBody table.dataTable thead > tr > td:after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.dataTables_processing {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
width: 200px;
|
||||||
|
margin-left: -100px;
|
||||||
|
margin-top: -26px;
|
||||||
|
text-align: center;
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
div.dataTables_processing > div:last-child {
|
||||||
|
position: relative;
|
||||||
|
width: 80px;
|
||||||
|
height: 15px;
|
||||||
|
margin: 1em auto;
|
||||||
|
}
|
||||||
|
div.dataTables_processing > div:last-child > div {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
width: 13px;
|
||||||
|
height: 13px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: rgba(13, 110, 253, 0.9);
|
||||||
|
animation-timing-function: cubic-bezier(0, 1, 1, 0);
|
||||||
|
}
|
||||||
|
div.dataTables_processing > div:last-child > div:nth-child(1) {
|
||||||
|
left: 8px;
|
||||||
|
animation: datatables-loader-1 0.6s infinite;
|
||||||
|
}
|
||||||
|
div.dataTables_processing > div:last-child > div:nth-child(2) {
|
||||||
|
left: 8px;
|
||||||
|
animation: datatables-loader-2 0.6s infinite;
|
||||||
|
}
|
||||||
|
div.dataTables_processing > div:last-child > div:nth-child(3) {
|
||||||
|
left: 32px;
|
||||||
|
animation: datatables-loader-2 0.6s infinite;
|
||||||
|
}
|
||||||
|
div.dataTables_processing > div:last-child > div:nth-child(4) {
|
||||||
|
left: 56px;
|
||||||
|
animation: datatables-loader-3 0.6s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes datatables-loader-1 {
|
||||||
|
0% {
|
||||||
|
transform: scale(0);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes datatables-loader-3 {
|
||||||
|
0% {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes datatables-loader-2 {
|
||||||
|
0% {
|
||||||
|
transform: translate(0, 0);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translate(24px, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
table.dataTable.nowrap th, table.dataTable.nowrap td {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
table.dataTable th.dt-left,
|
||||||
|
table.dataTable td.dt-left {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
table.dataTable th.dt-center,
|
||||||
|
table.dataTable td.dt-center,
|
||||||
|
table.dataTable td.dataTables_empty {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
table.dataTable th.dt-right,
|
||||||
|
table.dataTable td.dt-right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
table.dataTable th.dt-justify,
|
||||||
|
table.dataTable td.dt-justify {
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
|
table.dataTable th.dt-nowrap,
|
||||||
|
table.dataTable td.dt-nowrap {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
table.dataTable thead th,
|
||||||
|
table.dataTable thead td,
|
||||||
|
table.dataTable tfoot th,
|
||||||
|
table.dataTable tfoot td {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
table.dataTable thead th.dt-head-left,
|
||||||
|
table.dataTable thead td.dt-head-left,
|
||||||
|
table.dataTable tfoot th.dt-head-left,
|
||||||
|
table.dataTable tfoot td.dt-head-left {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
table.dataTable thead th.dt-head-center,
|
||||||
|
table.dataTable thead td.dt-head-center,
|
||||||
|
table.dataTable tfoot th.dt-head-center,
|
||||||
|
table.dataTable tfoot td.dt-head-center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
table.dataTable thead th.dt-head-right,
|
||||||
|
table.dataTable thead td.dt-head-right,
|
||||||
|
table.dataTable tfoot th.dt-head-right,
|
||||||
|
table.dataTable tfoot td.dt-head-right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
table.dataTable thead th.dt-head-justify,
|
||||||
|
table.dataTable thead td.dt-head-justify,
|
||||||
|
table.dataTable tfoot th.dt-head-justify,
|
||||||
|
table.dataTable tfoot td.dt-head-justify {
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
|
table.dataTable thead th.dt-head-nowrap,
|
||||||
|
table.dataTable thead td.dt-head-nowrap,
|
||||||
|
table.dataTable tfoot th.dt-head-nowrap,
|
||||||
|
table.dataTable tfoot td.dt-head-nowrap {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
table.dataTable tbody th.dt-body-left,
|
||||||
|
table.dataTable tbody td.dt-body-left {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
table.dataTable tbody th.dt-body-center,
|
||||||
|
table.dataTable tbody td.dt-body-center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
table.dataTable tbody th.dt-body-right,
|
||||||
|
table.dataTable tbody td.dt-body-right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
table.dataTable tbody th.dt-body-justify,
|
||||||
|
table.dataTable tbody td.dt-body-justify {
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
|
table.dataTable tbody th.dt-body-nowrap,
|
||||||
|
table.dataTable tbody td.dt-body-nowrap {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Bootstrap 5 integration for DataTables
|
||||||
|
*
|
||||||
|
* ©2020 SpryMedia Ltd, all rights reserved.
|
||||||
|
* License: MIT datatables.net/license/mit
|
||||||
|
*/
|
||||||
|
table.dataTable {
|
||||||
|
clear: both;
|
||||||
|
margin-top: 6px !important;
|
||||||
|
margin-bottom: 6px !important;
|
||||||
|
max-width: none !important;
|
||||||
|
border-collapse: separate !important;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
table.dataTable td,
|
||||||
|
table.dataTable th {
|
||||||
|
-webkit-box-sizing: content-box;
|
||||||
|
box-sizing: content-box;
|
||||||
|
}
|
||||||
|
table.dataTable td.dataTables_empty,
|
||||||
|
table.dataTable th.dataTables_empty {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
table.dataTable.nowrap th,
|
||||||
|
table.dataTable.nowrap td {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
table.dataTable.table-striped > tbody > tr:nth-of-type(2n+1) > * {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
table.dataTable > tbody > tr {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
table.dataTable > tbody > tr.selected > * {
|
||||||
|
box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.9);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
table.dataTable.table-striped > tbody > tr.odd > * {
|
||||||
|
box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
table.dataTable.table-striped > tbody > tr.odd.selected > * {
|
||||||
|
box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.95);
|
||||||
|
}
|
||||||
|
table.dataTable.table-hover > tbody > tr:hover > * {
|
||||||
|
box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.075);
|
||||||
|
}
|
||||||
|
table.dataTable.table-hover > tbody > tr.selected:hover > * {
|
||||||
|
box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.975);
|
||||||
|
}
|
||||||
|
|
||||||
|
div.dataTables_wrapper div.dataTables_length label {
|
||||||
|
font-weight: normal;
|
||||||
|
text-align: left;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
div.dataTables_wrapper div.dataTables_length select {
|
||||||
|
width: auto;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
div.dataTables_wrapper div.dataTables_filter {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
div.dataTables_wrapper div.dataTables_filter label {
|
||||||
|
font-weight: normal;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
div.dataTables_wrapper div.dataTables_filter input {
|
||||||
|
margin-left: 0.5em;
|
||||||
|
display: inline-block;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
div.dataTables_wrapper div.dataTables_info {
|
||||||
|
padding-top: 0.85em;
|
||||||
|
}
|
||||||
|
div.dataTables_wrapper div.dataTables_paginate {
|
||||||
|
margin: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
div.dataTables_wrapper div.dataTables_paginate ul.pagination {
|
||||||
|
margin: 2px 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.dataTables_scrollHead table.dataTable {
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.dataTables_scrollBody > table {
|
||||||
|
border-top: none;
|
||||||
|
margin-top: 0 !important;
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
div.dataTables_scrollBody > table > thead .sorting:before,
|
||||||
|
div.dataTables_scrollBody > table > thead .sorting_asc:before,
|
||||||
|
div.dataTables_scrollBody > table > thead .sorting_desc:before,
|
||||||
|
div.dataTables_scrollBody > table > thead .sorting:after,
|
||||||
|
div.dataTables_scrollBody > table > thead .sorting_asc:after,
|
||||||
|
div.dataTables_scrollBody > table > thead .sorting_desc:after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
div.dataTables_scrollBody > table > tbody tr:first-child th,
|
||||||
|
div.dataTables_scrollBody > table > tbody tr:first-child td {
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.dataTables_scrollFoot > .dataTables_scrollFootInner {
|
||||||
|
box-sizing: content-box;
|
||||||
|
}
|
||||||
|
div.dataTables_scrollFoot > .dataTables_scrollFootInner > table {
|
||||||
|
margin-top: 0 !important;
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 767px) {
|
||||||
|
div.dataTables_wrapper div.dataTables_length,
|
||||||
|
div.dataTables_wrapper div.dataTables_filter,
|
||||||
|
div.dataTables_wrapper div.dataTables_info,
|
||||||
|
div.dataTables_wrapper div.dataTables_paginate {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
div.dataTables_wrapper div.dataTables_paginate ul.pagination {
|
||||||
|
justify-content: center !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
table.dataTable.table-sm > thead > tr > th:not(.sorting_disabled) {
|
||||||
|
padding-right: 20px;
|
||||||
|
}
|
||||||
|
table.dataTable.table-sm .sorting:before,
|
||||||
|
table.dataTable.table-sm .sorting_asc:before,
|
||||||
|
table.dataTable.table-sm .sorting_desc:before {
|
||||||
|
top: 5px;
|
||||||
|
right: 0.85em;
|
||||||
|
}
|
||||||
|
table.dataTable.table-sm .sorting:after,
|
||||||
|
table.dataTable.table-sm .sorting_asc:after,
|
||||||
|
table.dataTable.table-sm .sorting_desc:after {
|
||||||
|
top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.table-bordered.dataTable {
|
||||||
|
border-right-width: 0;
|
||||||
|
}
|
||||||
|
table.table-bordered.dataTable thead tr:first-child th,
|
||||||
|
table.table-bordered.dataTable thead tr:first-child td {
|
||||||
|
border-top-width: 1px;
|
||||||
|
}
|
||||||
|
table.table-bordered.dataTable th,
|
||||||
|
table.table-bordered.dataTable td {
|
||||||
|
border-left-width: 0;
|
||||||
|
}
|
||||||
|
table.table-bordered.dataTable th:first-child, table.table-bordered.dataTable th:first-child,
|
||||||
|
table.table-bordered.dataTable td:first-child,
|
||||||
|
table.table-bordered.dataTable td:first-child {
|
||||||
|
border-left-width: 1px;
|
||||||
|
}
|
||||||
|
table.table-bordered.dataTable th:last-child, table.table-bordered.dataTable th:last-child,
|
||||||
|
table.table-bordered.dataTable td:last-child,
|
||||||
|
table.table-bordered.dataTable td:last-child {
|
||||||
|
border-right-width: 1px;
|
||||||
|
}
|
||||||
|
table.table-bordered.dataTable th,
|
||||||
|
table.table-bordered.dataTable td {
|
||||||
|
border-bottom-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.dataTables_scrollHead table.table-bordered {
|
||||||
|
border-bottom-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.table-responsive > div.dataTables_wrapper > div.row {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
div.table-responsive > div.dataTables_wrapper > div.row > div[class^=col-]:first-child {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
div.table-responsive > div.dataTables_wrapper > div.row > div[class^=col-]:last-child {
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
table.dataTable.dtr-inline.collapsed > tbody > tr > td.child,
|
||||||
|
table.dataTable.dtr-inline.collapsed > tbody > tr > th.child,
|
||||||
|
table.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty {
|
||||||
|
cursor: default !important;
|
||||||
|
}
|
||||||
|
table.dataTable.dtr-inline.collapsed > tbody > tr > td.child:before,
|
||||||
|
table.dataTable.dtr-inline.collapsed > tbody > tr > th.child:before,
|
||||||
|
table.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty:before {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
table.dataTable.dtr-inline.collapsed > tbody > tr > td.dtr-control,
|
||||||
|
table.dataTable.dtr-inline.collapsed > tbody > tr > th.dtr-control {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 30px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
table.dataTable.dtr-inline.collapsed > tbody > tr > td.dtr-control:before,
|
||||||
|
table.dataTable.dtr-inline.collapsed > tbody > tr > th.dtr-control:before {
|
||||||
|
top: 50%;
|
||||||
|
left: 5px;
|
||||||
|
height: 1em;
|
||||||
|
width: 1em;
|
||||||
|
margin-top: -9px;
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
color: white;
|
||||||
|
border: 0.15em solid white;
|
||||||
|
border-radius: 1em;
|
||||||
|
box-shadow: 0 0 0.2em #444;
|
||||||
|
box-sizing: content-box;
|
||||||
|
text-align: center;
|
||||||
|
text-indent: 0 !important;
|
||||||
|
font-family: "Courier New", Courier, monospace;
|
||||||
|
line-height: 1em;
|
||||||
|
content: "+";
|
||||||
|
background-color: #0d6efd;
|
||||||
|
}
|
||||||
|
table.dataTable.dtr-inline.collapsed > tbody > tr.parent > td.dtr-control:before,
|
||||||
|
table.dataTable.dtr-inline.collapsed > tbody > tr.parent > th.dtr-control:before {
|
||||||
|
content: "-";
|
||||||
|
background-color: #d33333;
|
||||||
|
}
|
||||||
|
table.dataTable.dtr-inline.collapsed.compact > tbody > tr > td.dtr-control,
|
||||||
|
table.dataTable.dtr-inline.collapsed.compact > tbody > tr > th.dtr-control {
|
||||||
|
padding-left: 27px;
|
||||||
|
}
|
||||||
|
table.dataTable.dtr-inline.collapsed.compact > tbody > tr > td.dtr-control:before,
|
||||||
|
table.dataTable.dtr-inline.collapsed.compact > tbody > tr > th.dtr-control:before {
|
||||||
|
left: 4px;
|
||||||
|
height: 14px;
|
||||||
|
width: 14px;
|
||||||
|
border-radius: 14px;
|
||||||
|
line-height: 14px;
|
||||||
|
text-indent: 3px;
|
||||||
|
}
|
||||||
|
table.dataTable.dtr-column > tbody > tr > td.dtr-control,
|
||||||
|
table.dataTable.dtr-column > tbody > tr > th.dtr-control,
|
||||||
|
table.dataTable.dtr-column > tbody > tr > td.control,
|
||||||
|
table.dataTable.dtr-column > tbody > tr > th.control {
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
table.dataTable.dtr-column > tbody > tr > td.dtr-control:before,
|
||||||
|
table.dataTable.dtr-column > tbody > tr > th.dtr-control:before,
|
||||||
|
table.dataTable.dtr-column > tbody > tr > td.control:before,
|
||||||
|
table.dataTable.dtr-column > tbody > tr > th.control:before {
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
height: 0.8em;
|
||||||
|
width: 0.8em;
|
||||||
|
margin-top: -0.5em;
|
||||||
|
margin-left: -0.5em;
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
color: white;
|
||||||
|
border: 0.15em solid white;
|
||||||
|
border-radius: 1em;
|
||||||
|
box-shadow: 0 0 0.2em #444;
|
||||||
|
box-sizing: content-box;
|
||||||
|
text-align: center;
|
||||||
|
text-indent: 0 !important;
|
||||||
|
font-family: "Courier New", Courier, monospace;
|
||||||
|
line-height: 1em;
|
||||||
|
content: "+";
|
||||||
|
background-color: #0d6efd;
|
||||||
|
}
|
||||||
|
table.dataTable.dtr-column > tbody > tr.parent td.dtr-control:before,
|
||||||
|
table.dataTable.dtr-column > tbody > tr.parent th.dtr-control:before,
|
||||||
|
table.dataTable.dtr-column > tbody > tr.parent td.control:before,
|
||||||
|
table.dataTable.dtr-column > tbody > tr.parent th.control:before {
|
||||||
|
content: "-";
|
||||||
|
background-color: #d33333;
|
||||||
|
}
|
||||||
|
table.dataTable > tbody > tr.child {
|
||||||
|
padding: 0.5em 1em;
|
||||||
|
}
|
||||||
|
table.dataTable > tbody > tr.child:hover {
|
||||||
|
background: transparent !important;
|
||||||
|
}
|
||||||
|
table.dataTable > tbody > tr.child ul.dtr-details {
|
||||||
|
display: inline-block;
|
||||||
|
list-style-type: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
table.dataTable > tbody > tr.child ul.dtr-details > li {
|
||||||
|
border-bottom: 1px solid #efefef;
|
||||||
|
padding: 0.5em 0;
|
||||||
|
}
|
||||||
|
table.dataTable > tbody > tr.child ul.dtr-details > li:first-child {
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
table.dataTable > tbody > tr.child ul.dtr-details > li:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
table.dataTable > tbody > tr.child span.dtr-title {
|
||||||
|
display: inline-block;
|
||||||
|
min-width: 75px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
div.dtr-modal {
|
||||||
|
position: fixed;
|
||||||
|
box-sizing: border-box;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 100;
|
||||||
|
padding: 10em 1em;
|
||||||
|
}
|
||||||
|
div.dtr-modal div.dtr-modal-display {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
width: 50%;
|
||||||
|
height: 50%;
|
||||||
|
overflow: auto;
|
||||||
|
margin: auto;
|
||||||
|
z-index: 102;
|
||||||
|
overflow: auto;
|
||||||
|
background-color: #f5f5f7;
|
||||||
|
border: 1px solid black;
|
||||||
|
border-radius: 0.5em;
|
||||||
|
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.6);
|
||||||
|
}
|
||||||
|
div.dtr-modal div.dtr-modal-content {
|
||||||
|
position: relative;
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
div.dtr-modal div.dtr-modal-close {
|
||||||
|
position: absolute;
|
||||||
|
top: 6px;
|
||||||
|
right: 6px;
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
border: 1px solid #eaeaea;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 3px;
|
||||||
|
cursor: pointer;
|
||||||
|
z-index: 12;
|
||||||
|
}
|
||||||
|
div.dtr-modal div.dtr-modal-close:hover {
|
||||||
|
background-color: #eaeaea;
|
||||||
|
}
|
||||||
|
div.dtr-modal div.dtr-modal-background {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 101;
|
||||||
|
background: rgba(0, 0, 0, 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 767px) {
|
||||||
|
div.dtr-modal div.dtr-modal-display {
|
||||||
|
width: 95%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div.dtr-bs-modal table.table tr:first-child td {
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.dataTable.table-bordered th.dtr-control.dtr-hidden + *,
|
||||||
|
table.dataTable.table-bordered td.dtr-control.dtr-hidden + * {
|
||||||
|
border-left-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
table.dataTable > tbody > tr > .selected {
|
||||||
|
background-color: rgba(13, 110, 253, 0.9);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
table.dataTable tbody td.select-checkbox,
|
||||||
|
table.dataTable tbody th.select-checkbox {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
table.dataTable tbody td.select-checkbox:before, table.dataTable tbody td.select-checkbox:after,
|
||||||
|
table.dataTable tbody th.select-checkbox:before,
|
||||||
|
table.dataTable tbody th.select-checkbox:after {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: 1.2em;
|
||||||
|
left: 50%;
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
table.dataTable tbody td.select-checkbox:before,
|
||||||
|
table.dataTable tbody th.select-checkbox:before {
|
||||||
|
content: " ";
|
||||||
|
margin-top: -5px;
|
||||||
|
margin-left: -6px;
|
||||||
|
border: 1px solid black;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
table.dataTable tr.selected td.select-checkbox:before,
|
||||||
|
table.dataTable tr.selected th.select-checkbox:before {
|
||||||
|
border: 1px solid white;
|
||||||
|
}
|
||||||
|
table.dataTable tr.selected td.select-checkbox:after,
|
||||||
|
table.dataTable tr.selected th.select-checkbox:after {
|
||||||
|
content: "✓";
|
||||||
|
font-size: 20px;
|
||||||
|
margin-top: -19px;
|
||||||
|
margin-left: -6px;
|
||||||
|
text-align: center;
|
||||||
|
text-shadow: 1px 1px #B0BED9, -1px -1px #B0BED9, 1px -1px #B0BED9, -1px 1px #B0BED9;
|
||||||
|
}
|
||||||
|
table.dataTable.compact tbody td.select-checkbox:before,
|
||||||
|
table.dataTable.compact tbody th.select-checkbox:before {
|
||||||
|
margin-top: -12px;
|
||||||
|
}
|
||||||
|
table.dataTable.compact tr.selected td.select-checkbox:after,
|
||||||
|
table.dataTable.compact tr.selected th.select-checkbox:after {
|
||||||
|
margin-top: -16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.dataTables_wrapper span.select-info,
|
||||||
|
div.dataTables_wrapper span.select-item {
|
||||||
|
margin-left: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 640px) {
|
||||||
|
div.dataTables_wrapper span.select-info,
|
||||||
|
div.dataTables_wrapper span.select-item {
|
||||||
|
margin-left: 0;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
table.dataTable.table-sm tbody td.select-checkbox::before {
|
||||||
|
margin-top: -9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Vendored
-1
@@ -1 +0,0 @@
|
|||||||
@keyframes chartjs-render-animation{from{opacity:.99}to{opacity:1}}.chartjs-render-monitor{animation:chartjs-render-animation 1ms}.chartjs-size-monitor,.chartjs-size-monitor-expand,.chartjs-size-monitor-shrink{position:absolute;direction:ltr;left:0;top:0;right:0;bottom:0;overflow:hidden;pointer-events:none;visibility:hidden;z-index:-1}.chartjs-size-monitor-expand>div{position:absolute;width:1000000px;height:1000000px;left:0;top:0}.chartjs-size-monitor-shrink>div{position:absolute;width:200%;height:200%;left:0;top:0}
|
|
||||||
+279
-2
@@ -1,7 +1,7 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: "bootstrap-icons";
|
font-family: "bootstrap-icons";
|
||||||
src: url("/fonts/bootstrap-icons.woff2?45695e8b569b2b0178db2713ca47065c") format("woff2"),
|
src: url("/fonts/bootstrap-icons.woff2?524846017b983fc8ded9325d94ed40f3") format("woff2"),
|
||||||
url("/fonts/bootstrap-icons.woff?45695e8b569b2b0178db2713ca47065c") format("woff");
|
url("/fonts/bootstrap-icons.woff?524846017b983fc8ded9325d94ed40f3") format("woff");
|
||||||
}
|
}
|
||||||
|
|
||||||
.bi::before,
|
.bi::before,
|
||||||
@@ -19,6 +19,7 @@ url("/fonts/bootstrap-icons.woff?45695e8b569b2b0178db2713ca47065c") format("woff
|
|||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bi-123::before { content: "\f67f"; }
|
||||||
.bi-alarm-fill::before { content: "\f101"; }
|
.bi-alarm-fill::before { content: "\f101"; }
|
||||||
.bi-alarm::before { content: "\f102"; }
|
.bi-alarm::before { content: "\f102"; }
|
||||||
.bi-align-bottom::before { content: "\f103"; }
|
.bi-align-bottom::before { content: "\f103"; }
|
||||||
@@ -1425,3 +1426,279 @@ url("/fonts/bootstrap-icons.woff?45695e8b569b2b0178db2713ca47065c") format("woff
|
|||||||
.bi-webcam-fill::before { content: "\f67c"; }
|
.bi-webcam-fill::before { content: "\f67c"; }
|
||||||
.bi-webcam::before { content: "\f67d"; }
|
.bi-webcam::before { content: "\f67d"; }
|
||||||
.bi-yin-yang::before { content: "\f67e"; }
|
.bi-yin-yang::before { content: "\f67e"; }
|
||||||
|
.bi-bandaid-fill::before { content: "\f680"; }
|
||||||
|
.bi-bandaid::before { content: "\f681"; }
|
||||||
|
.bi-bluetooth::before { content: "\f682"; }
|
||||||
|
.bi-body-text::before { content: "\f683"; }
|
||||||
|
.bi-boombox::before { content: "\f684"; }
|
||||||
|
.bi-boxes::before { content: "\f685"; }
|
||||||
|
.bi-dpad-fill::before { content: "\f686"; }
|
||||||
|
.bi-dpad::before { content: "\f687"; }
|
||||||
|
.bi-ear-fill::before { content: "\f688"; }
|
||||||
|
.bi-ear::before { content: "\f689"; }
|
||||||
|
.bi-envelope-check-1::before { content: "\f68a"; }
|
||||||
|
.bi-envelope-check-fill::before { content: "\f68b"; }
|
||||||
|
.bi-envelope-check::before { content: "\f68c"; }
|
||||||
|
.bi-envelope-dash-1::before { content: "\f68d"; }
|
||||||
|
.bi-envelope-dash-fill::before { content: "\f68e"; }
|
||||||
|
.bi-envelope-dash::before { content: "\f68f"; }
|
||||||
|
.bi-envelope-exclamation-1::before { content: "\f690"; }
|
||||||
|
.bi-envelope-exclamation-fill::before { content: "\f691"; }
|
||||||
|
.bi-envelope-exclamation::before { content: "\f692"; }
|
||||||
|
.bi-envelope-plus-fill::before { content: "\f693"; }
|
||||||
|
.bi-envelope-plus::before { content: "\f694"; }
|
||||||
|
.bi-envelope-slash-1::before { content: "\f695"; }
|
||||||
|
.bi-envelope-slash-fill::before { content: "\f696"; }
|
||||||
|
.bi-envelope-slash::before { content: "\f697"; }
|
||||||
|
.bi-envelope-x-1::before { content: "\f698"; }
|
||||||
|
.bi-envelope-x-fill::before { content: "\f699"; }
|
||||||
|
.bi-envelope-x::before { content: "\f69a"; }
|
||||||
|
.bi-explicit-fill::before { content: "\f69b"; }
|
||||||
|
.bi-explicit::before { content: "\f69c"; }
|
||||||
|
.bi-git::before { content: "\f69d"; }
|
||||||
|
.bi-infinity::before { content: "\f69e"; }
|
||||||
|
.bi-list-columns-reverse::before { content: "\f69f"; }
|
||||||
|
.bi-list-columns::before { content: "\f6a0"; }
|
||||||
|
.bi-meta::before { content: "\f6a1"; }
|
||||||
|
.bi-mortorboard-fill::before { content: "\f6a2"; }
|
||||||
|
.bi-mortorboard::before { content: "\f6a3"; }
|
||||||
|
.bi-nintendo-switch::before { content: "\f6a4"; }
|
||||||
|
.bi-pc-display-horizontal::before { content: "\f6a5"; }
|
||||||
|
.bi-pc-display::before { content: "\f6a6"; }
|
||||||
|
.bi-pc-horizontal::before { content: "\f6a7"; }
|
||||||
|
.bi-pc::before { content: "\f6a8"; }
|
||||||
|
.bi-playstation::before { content: "\f6a9"; }
|
||||||
|
.bi-plus-slash-minus::before { content: "\f6aa"; }
|
||||||
|
.bi-projector-fill::before { content: "\f6ab"; }
|
||||||
|
.bi-projector::before { content: "\f6ac"; }
|
||||||
|
.bi-qr-code-scan::before { content: "\f6ad"; }
|
||||||
|
.bi-qr-code::before { content: "\f6ae"; }
|
||||||
|
.bi-quora::before { content: "\f6af"; }
|
||||||
|
.bi-quote::before { content: "\f6b0"; }
|
||||||
|
.bi-robot::before { content: "\f6b1"; }
|
||||||
|
.bi-send-check-fill::before { content: "\f6b2"; }
|
||||||
|
.bi-send-check::before { content: "\f6b3"; }
|
||||||
|
.bi-send-dash-fill::before { content: "\f6b4"; }
|
||||||
|
.bi-send-dash::before { content: "\f6b5"; }
|
||||||
|
.bi-send-exclamation-1::before { content: "\f6b6"; }
|
||||||
|
.bi-send-exclamation-fill::before { content: "\f6b7"; }
|
||||||
|
.bi-send-exclamation::before { content: "\f6b8"; }
|
||||||
|
.bi-send-fill::before { content: "\f6b9"; }
|
||||||
|
.bi-send-plus-fill::before { content: "\f6ba"; }
|
||||||
|
.bi-send-plus::before { content: "\f6bb"; }
|
||||||
|
.bi-send-slash-fill::before { content: "\f6bc"; }
|
||||||
|
.bi-send-slash::before { content: "\f6bd"; }
|
||||||
|
.bi-send-x-fill::before { content: "\f6be"; }
|
||||||
|
.bi-send-x::before { content: "\f6bf"; }
|
||||||
|
.bi-send::before { content: "\f6c0"; }
|
||||||
|
.bi-steam::before { content: "\f6c1"; }
|
||||||
|
.bi-terminal-dash-1::before { content: "\f6c2"; }
|
||||||
|
.bi-terminal-dash::before { content: "\f6c3"; }
|
||||||
|
.bi-terminal-plus::before { content: "\f6c4"; }
|
||||||
|
.bi-terminal-split::before { content: "\f6c5"; }
|
||||||
|
.bi-ticket-detailed-fill::before { content: "\f6c6"; }
|
||||||
|
.bi-ticket-detailed::before { content: "\f6c7"; }
|
||||||
|
.bi-ticket-fill::before { content: "\f6c8"; }
|
||||||
|
.bi-ticket-perforated-fill::before { content: "\f6c9"; }
|
||||||
|
.bi-ticket-perforated::before { content: "\f6ca"; }
|
||||||
|
.bi-ticket::before { content: "\f6cb"; }
|
||||||
|
.bi-tiktok::before { content: "\f6cc"; }
|
||||||
|
.bi-window-dash::before { content: "\f6cd"; }
|
||||||
|
.bi-window-desktop::before { content: "\f6ce"; }
|
||||||
|
.bi-window-fullscreen::before { content: "\f6cf"; }
|
||||||
|
.bi-window-plus::before { content: "\f6d0"; }
|
||||||
|
.bi-window-split::before { content: "\f6d1"; }
|
||||||
|
.bi-window-stack::before { content: "\f6d2"; }
|
||||||
|
.bi-window-x::before { content: "\f6d3"; }
|
||||||
|
.bi-xbox::before { content: "\f6d4"; }
|
||||||
|
.bi-ethernet::before { content: "\f6d5"; }
|
||||||
|
.bi-hdmi-fill::before { content: "\f6d6"; }
|
||||||
|
.bi-hdmi::before { content: "\f6d7"; }
|
||||||
|
.bi-usb-c-fill::before { content: "\f6d8"; }
|
||||||
|
.bi-usb-c::before { content: "\f6d9"; }
|
||||||
|
.bi-usb-fill::before { content: "\f6da"; }
|
||||||
|
.bi-usb-plug-fill::before { content: "\f6db"; }
|
||||||
|
.bi-usb-plug::before { content: "\f6dc"; }
|
||||||
|
.bi-usb-symbol::before { content: "\f6dd"; }
|
||||||
|
.bi-usb::before { content: "\f6de"; }
|
||||||
|
.bi-boombox-fill::before { content: "\f6df"; }
|
||||||
|
.bi-displayport-1::before { content: "\f6e0"; }
|
||||||
|
.bi-displayport::before { content: "\f6e1"; }
|
||||||
|
.bi-gpu-card::before { content: "\f6e2"; }
|
||||||
|
.bi-memory::before { content: "\f6e3"; }
|
||||||
|
.bi-modem-fill::before { content: "\f6e4"; }
|
||||||
|
.bi-modem::before { content: "\f6e5"; }
|
||||||
|
.bi-motherboard-fill::before { content: "\f6e6"; }
|
||||||
|
.bi-motherboard::before { content: "\f6e7"; }
|
||||||
|
.bi-optical-audio-fill::before { content: "\f6e8"; }
|
||||||
|
.bi-optical-audio::before { content: "\f6e9"; }
|
||||||
|
.bi-pci-card::before { content: "\f6ea"; }
|
||||||
|
.bi-router-fill::before { content: "\f6eb"; }
|
||||||
|
.bi-router::before { content: "\f6ec"; }
|
||||||
|
.bi-ssd-fill::before { content: "\f6ed"; }
|
||||||
|
.bi-ssd::before { content: "\f6ee"; }
|
||||||
|
.bi-thunderbolt-fill::before { content: "\f6ef"; }
|
||||||
|
.bi-thunderbolt::before { content: "\f6f0"; }
|
||||||
|
.bi-usb-drive-fill::before { content: "\f6f1"; }
|
||||||
|
.bi-usb-drive::before { content: "\f6f2"; }
|
||||||
|
.bi-usb-micro-fill::before { content: "\f6f3"; }
|
||||||
|
.bi-usb-micro::before { content: "\f6f4"; }
|
||||||
|
.bi-usb-mini-fill::before { content: "\f6f5"; }
|
||||||
|
.bi-usb-mini::before { content: "\f6f6"; }
|
||||||
|
.bi-cloud-haze2::before { content: "\f6f7"; }
|
||||||
|
.bi-device-hdd-fill::before { content: "\f6f8"; }
|
||||||
|
.bi-device-hdd::before { content: "\f6f9"; }
|
||||||
|
.bi-device-ssd-fill::before { content: "\f6fa"; }
|
||||||
|
.bi-device-ssd::before { content: "\f6fb"; }
|
||||||
|
.bi-displayport-fill::before { content: "\f6fc"; }
|
||||||
|
.bi-mortarboard-fill::before { content: "\f6fd"; }
|
||||||
|
.bi-mortarboard::before { content: "\f6fe"; }
|
||||||
|
.bi-terminal-x::before { content: "\f6ff"; }
|
||||||
|
.bi-arrow-through-heart-fill::before { content: "\f700"; }
|
||||||
|
.bi-arrow-through-heart::before { content: "\f701"; }
|
||||||
|
.bi-badge-sd-fill::before { content: "\f702"; }
|
||||||
|
.bi-badge-sd::before { content: "\f703"; }
|
||||||
|
.bi-bag-heart-fill::before { content: "\f704"; }
|
||||||
|
.bi-bag-heart::before { content: "\f705"; }
|
||||||
|
.bi-balloon-fill::before { content: "\f706"; }
|
||||||
|
.bi-balloon-heart-fill::before { content: "\f707"; }
|
||||||
|
.bi-balloon-heart::before { content: "\f708"; }
|
||||||
|
.bi-balloon::before { content: "\f709"; }
|
||||||
|
.bi-box2-fill::before { content: "\f70a"; }
|
||||||
|
.bi-box2-heart-fill::before { content: "\f70b"; }
|
||||||
|
.bi-box2-heart::before { content: "\f70c"; }
|
||||||
|
.bi-box2::before { content: "\f70d"; }
|
||||||
|
.bi-braces-asterisk::before { content: "\f70e"; }
|
||||||
|
.bi-calendar-heart-fill::before { content: "\f70f"; }
|
||||||
|
.bi-calendar-heart::before { content: "\f710"; }
|
||||||
|
.bi-calendar2-heart-fill::before { content: "\f711"; }
|
||||||
|
.bi-calendar2-heart::before { content: "\f712"; }
|
||||||
|
.bi-chat-heart-fill::before { content: "\f713"; }
|
||||||
|
.bi-chat-heart::before { content: "\f714"; }
|
||||||
|
.bi-chat-left-heart-fill::before { content: "\f715"; }
|
||||||
|
.bi-chat-left-heart::before { content: "\f716"; }
|
||||||
|
.bi-chat-right-heart-fill::before { content: "\f717"; }
|
||||||
|
.bi-chat-right-heart::before { content: "\f718"; }
|
||||||
|
.bi-chat-square-heart-fill::before { content: "\f719"; }
|
||||||
|
.bi-chat-square-heart::before { content: "\f71a"; }
|
||||||
|
.bi-clipboard-check-fill::before { content: "\f71b"; }
|
||||||
|
.bi-clipboard-data-fill::before { content: "\f71c"; }
|
||||||
|
.bi-clipboard-fill::before { content: "\f71d"; }
|
||||||
|
.bi-clipboard-heart-fill::before { content: "\f71e"; }
|
||||||
|
.bi-clipboard-heart::before { content: "\f71f"; }
|
||||||
|
.bi-clipboard-minus-fill::before { content: "\f720"; }
|
||||||
|
.bi-clipboard-plus-fill::before { content: "\f721"; }
|
||||||
|
.bi-clipboard-pulse::before { content: "\f722"; }
|
||||||
|
.bi-clipboard-x-fill::before { content: "\f723"; }
|
||||||
|
.bi-clipboard2-check-fill::before { content: "\f724"; }
|
||||||
|
.bi-clipboard2-check::before { content: "\f725"; }
|
||||||
|
.bi-clipboard2-data-fill::before { content: "\f726"; }
|
||||||
|
.bi-clipboard2-data::before { content: "\f727"; }
|
||||||
|
.bi-clipboard2-fill::before { content: "\f728"; }
|
||||||
|
.bi-clipboard2-heart-fill::before { content: "\f729"; }
|
||||||
|
.bi-clipboard2-heart::before { content: "\f72a"; }
|
||||||
|
.bi-clipboard2-minus-fill::before { content: "\f72b"; }
|
||||||
|
.bi-clipboard2-minus::before { content: "\f72c"; }
|
||||||
|
.bi-clipboard2-plus-fill::before { content: "\f72d"; }
|
||||||
|
.bi-clipboard2-plus::before { content: "\f72e"; }
|
||||||
|
.bi-clipboard2-pulse-fill::before { content: "\f72f"; }
|
||||||
|
.bi-clipboard2-pulse::before { content: "\f730"; }
|
||||||
|
.bi-clipboard2-x-fill::before { content: "\f731"; }
|
||||||
|
.bi-clipboard2-x::before { content: "\f732"; }
|
||||||
|
.bi-clipboard2::before { content: "\f733"; }
|
||||||
|
.bi-emoji-kiss-fill::before { content: "\f734"; }
|
||||||
|
.bi-emoji-kiss::before { content: "\f735"; }
|
||||||
|
.bi-envelope-heart-fill::before { content: "\f736"; }
|
||||||
|
.bi-envelope-heart::before { content: "\f737"; }
|
||||||
|
.bi-envelope-open-heart-fill::before { content: "\f738"; }
|
||||||
|
.bi-envelope-open-heart::before { content: "\f739"; }
|
||||||
|
.bi-envelope-paper-fill::before { content: "\f73a"; }
|
||||||
|
.bi-envelope-paper-heart-fill::before { content: "\f73b"; }
|
||||||
|
.bi-envelope-paper-heart::before { content: "\f73c"; }
|
||||||
|
.bi-envelope-paper::before { content: "\f73d"; }
|
||||||
|
.bi-filetype-aac::before { content: "\f73e"; }
|
||||||
|
.bi-filetype-ai::before { content: "\f73f"; }
|
||||||
|
.bi-filetype-bmp::before { content: "\f740"; }
|
||||||
|
.bi-filetype-cs::before { content: "\f741"; }
|
||||||
|
.bi-filetype-css::before { content: "\f742"; }
|
||||||
|
.bi-filetype-csv::before { content: "\f743"; }
|
||||||
|
.bi-filetype-doc::before { content: "\f744"; }
|
||||||
|
.bi-filetype-docx::before { content: "\f745"; }
|
||||||
|
.bi-filetype-exe::before { content: "\f746"; }
|
||||||
|
.bi-filetype-gif::before { content: "\f747"; }
|
||||||
|
.bi-filetype-heic::before { content: "\f748"; }
|
||||||
|
.bi-filetype-html::before { content: "\f749"; }
|
||||||
|
.bi-filetype-java::before { content: "\f74a"; }
|
||||||
|
.bi-filetype-jpg::before { content: "\f74b"; }
|
||||||
|
.bi-filetype-js::before { content: "\f74c"; }
|
||||||
|
.bi-filetype-jsx::before { content: "\f74d"; }
|
||||||
|
.bi-filetype-key::before { content: "\f74e"; }
|
||||||
|
.bi-filetype-m4p::before { content: "\f74f"; }
|
||||||
|
.bi-filetype-md::before { content: "\f750"; }
|
||||||
|
.bi-filetype-mdx::before { content: "\f751"; }
|
||||||
|
.bi-filetype-mov::before { content: "\f752"; }
|
||||||
|
.bi-filetype-mp3::before { content: "\f753"; }
|
||||||
|
.bi-filetype-mp4::before { content: "\f754"; }
|
||||||
|
.bi-filetype-otf::before { content: "\f755"; }
|
||||||
|
.bi-filetype-pdf::before { content: "\f756"; }
|
||||||
|
.bi-filetype-php::before { content: "\f757"; }
|
||||||
|
.bi-filetype-png::before { content: "\f758"; }
|
||||||
|
.bi-filetype-ppt-1::before { content: "\f759"; }
|
||||||
|
.bi-filetype-ppt::before { content: "\f75a"; }
|
||||||
|
.bi-filetype-psd::before { content: "\f75b"; }
|
||||||
|
.bi-filetype-py::before { content: "\f75c"; }
|
||||||
|
.bi-filetype-raw::before { content: "\f75d"; }
|
||||||
|
.bi-filetype-rb::before { content: "\f75e"; }
|
||||||
|
.bi-filetype-sass::before { content: "\f75f"; }
|
||||||
|
.bi-filetype-scss::before { content: "\f760"; }
|
||||||
|
.bi-filetype-sh::before { content: "\f761"; }
|
||||||
|
.bi-filetype-svg::before { content: "\f762"; }
|
||||||
|
.bi-filetype-tiff::before { content: "\f763"; }
|
||||||
|
.bi-filetype-tsx::before { content: "\f764"; }
|
||||||
|
.bi-filetype-ttf::before { content: "\f765"; }
|
||||||
|
.bi-filetype-txt::before { content: "\f766"; }
|
||||||
|
.bi-filetype-wav::before { content: "\f767"; }
|
||||||
|
.bi-filetype-woff::before { content: "\f768"; }
|
||||||
|
.bi-filetype-xls-1::before { content: "\f769"; }
|
||||||
|
.bi-filetype-xls::before { content: "\f76a"; }
|
||||||
|
.bi-filetype-xml::before { content: "\f76b"; }
|
||||||
|
.bi-filetype-yml::before { content: "\f76c"; }
|
||||||
|
.bi-heart-arrow::before { content: "\f76d"; }
|
||||||
|
.bi-heart-pulse-fill::before { content: "\f76e"; }
|
||||||
|
.bi-heart-pulse::before { content: "\f76f"; }
|
||||||
|
.bi-heartbreak-fill::before { content: "\f770"; }
|
||||||
|
.bi-heartbreak::before { content: "\f771"; }
|
||||||
|
.bi-hearts::before { content: "\f772"; }
|
||||||
|
.bi-hospital-fill::before { content: "\f773"; }
|
||||||
|
.bi-hospital::before { content: "\f774"; }
|
||||||
|
.bi-house-heart-fill::before { content: "\f775"; }
|
||||||
|
.bi-house-heart::before { content: "\f776"; }
|
||||||
|
.bi-incognito::before { content: "\f777"; }
|
||||||
|
.bi-magnet-fill::before { content: "\f778"; }
|
||||||
|
.bi-magnet::before { content: "\f779"; }
|
||||||
|
.bi-person-heart::before { content: "\f77a"; }
|
||||||
|
.bi-person-hearts::before { content: "\f77b"; }
|
||||||
|
.bi-phone-flip::before { content: "\f77c"; }
|
||||||
|
.bi-plugin::before { content: "\f77d"; }
|
||||||
|
.bi-postage-fill::before { content: "\f77e"; }
|
||||||
|
.bi-postage-heart-fill::before { content: "\f77f"; }
|
||||||
|
.bi-postage-heart::before { content: "\f780"; }
|
||||||
|
.bi-postage::before { content: "\f781"; }
|
||||||
|
.bi-postcard-fill::before { content: "\f782"; }
|
||||||
|
.bi-postcard-heart-fill::before { content: "\f783"; }
|
||||||
|
.bi-postcard-heart::before { content: "\f784"; }
|
||||||
|
.bi-postcard::before { content: "\f785"; }
|
||||||
|
.bi-search-heart-fill::before { content: "\f786"; }
|
||||||
|
.bi-search-heart::before { content: "\f787"; }
|
||||||
|
.bi-sliders2-vertical::before { content: "\f788"; }
|
||||||
|
.bi-sliders2::before { content: "\f789"; }
|
||||||
|
.bi-trash3-fill::before { content: "\f78a"; }
|
||||||
|
.bi-trash3::before { content: "\f78b"; }
|
||||||
|
.bi-valentine::before { content: "\f78c"; }
|
||||||
|
.bi-valentine2::before { content: "\f78d"; }
|
||||||
|
.bi-wrench-adjustable-circle-fill::before { content: "\f78e"; }
|
||||||
|
.bi-wrench-adjustable-circle::before { content: "\f78f"; }
|
||||||
|
.bi-wrench-adjustable::before { content: "\f790"; }
|
||||||
|
.bi-filetype-json::before { content: "\f791"; }
|
||||||
|
.bi-filetype-pptx::before { content: "\f792"; }
|
||||||
|
.bi-filetype-xlsx::before { content: "\f793"; }
|
||||||
@@ -63,6 +63,17 @@
|
|||||||
.navbar-nav {
|
.navbar-nav {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
.navbar-nav .nav-item {
|
||||||
|
flex-direction: column;
|
||||||
|
display: flex;
|
||||||
|
padding: 0 10px !important;
|
||||||
|
}
|
||||||
|
.navbar-nav .nav-link {
|
||||||
|
height: 44px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 10px !important;
|
||||||
|
}
|
||||||
.navbar-fixed-bottom .navbar-collapse,
|
.navbar-fixed-bottom .navbar-collapse,
|
||||||
.navbar-fixed-top .navbar-collapse {
|
.navbar-fixed-top .navbar-collapse {
|
||||||
max-height: 1000px
|
max-height: 1000px
|
||||||
@@ -75,6 +86,12 @@
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-size: inherit;
|
font-size: inherit;
|
||||||
}
|
}
|
||||||
|
.btn-group-xs > .btn, .btn-xs {
|
||||||
|
padding: .25rem .4rem;
|
||||||
|
font-size: .875rem;
|
||||||
|
line-height: 1rem;
|
||||||
|
border-radius: .2rem;
|
||||||
|
}
|
||||||
.icon-spin {
|
.icon-spin {
|
||||||
animation-name: spin;
|
animation-name: spin;
|
||||||
animation-duration: 2000ms;
|
animation-duration: 2000ms;
|
||||||
@@ -105,13 +122,22 @@
|
|||||||
transform: rotate(359deg);
|
transform: rotate(359deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word;}
|
@keyframes blink {
|
||||||
.footable-sortable {
|
50% {
|
||||||
-webkit-user-select: none;
|
color: transparent
|
||||||
-moz-user-select: none;
|
}
|
||||||
-ms-user-select: none;
|
|
||||||
user-select: none;
|
|
||||||
}
|
}
|
||||||
|
.loader-dot {
|
||||||
|
animation: 1s blink infinite
|
||||||
|
}
|
||||||
|
.loader-dot:nth-child(2) {
|
||||||
|
animation-delay: 250ms
|
||||||
|
}
|
||||||
|
.loader-dot:nth-child(3) {
|
||||||
|
animation-delay: 500ms
|
||||||
|
}
|
||||||
|
|
||||||
|
pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word;}
|
||||||
/* Fix modal moving content left */
|
/* Fix modal moving content left */
|
||||||
body.modal-open {
|
body.modal-open {
|
||||||
overflow: inherit;
|
overflow: inherit;
|
||||||
@@ -166,19 +192,11 @@ legend {
|
|||||||
top: 0; right: 0; bottom: 0; left: 0;
|
top: 0; right: 0; bottom: 0; left: 0;
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
#top {
|
|
||||||
padding-top: 70px;
|
|
||||||
}
|
|
||||||
.bootstrap-select.btn-group .no-results {
|
.bootstrap-select.btn-group .no-results {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.dropdown-desc {
|
.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-secondary {
|
||||||
display: block;
|
color: rgb(197, 197, 197) !important;
|
||||||
padding: 3px 10px;
|
|
||||||
clear: both;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #5a5a5a;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
}
|
||||||
.haveibeenpwned {
|
.haveibeenpwned {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -206,7 +224,8 @@ legend {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
.footer .version {
|
.footer .version {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
.slave-info {
|
.slave-info {
|
||||||
padding: 15px 0px 15px 15px;
|
padding: 15px 0px 15px 15px;
|
||||||
@@ -224,12 +243,8 @@ legend {
|
|||||||
.btn-input-missing:active:hover,
|
.btn-input-missing:active:hover,
|
||||||
.btn-input-missing:active:focus {
|
.btn-input-missing:active:focus {
|
||||||
color: #000 !important;
|
color: #000 !important;
|
||||||
background-color: #ff4136;
|
background-color: #ff2f24 !important;
|
||||||
border-color: #ff291c;
|
border-color: #e21207 !important;
|
||||||
}
|
|
||||||
table.footable>tbody>tr.footable-empty>td {
|
|
||||||
font-style:italic;
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
}
|
||||||
.navbar-nav > li {
|
.navbar-nav > li {
|
||||||
font-size: 1rem !important;
|
font-size: 1rem !important;
|
||||||
@@ -255,3 +270,103 @@ code {
|
|||||||
.flag-icon {
|
.flag-icon {
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dropdown-header {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.tag-box {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
.tag-badge {
|
||||||
|
transition: 200ms linear;
|
||||||
|
margin-top: 5px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
margin-left: 2px;
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
.tag-badge.btn-badge {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.tag-badge .bi {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.tag-badge.btn-badge:hover {
|
||||||
|
filter: brightness(0.9);
|
||||||
|
}
|
||||||
|
.tag-input {
|
||||||
|
margin-left: 10px;
|
||||||
|
border: 0 !important;
|
||||||
|
flex: 1;
|
||||||
|
height: 24px;
|
||||||
|
min-width: 150px;
|
||||||
|
}
|
||||||
|
.tag-input:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
.tag-add {
|
||||||
|
padding: 0 5px 0 5px;
|
||||||
|
align-items: center;
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dnstable {
|
||||||
|
overflow-x: auto!important;
|
||||||
|
}
|
||||||
|
.well {
|
||||||
|
border: 1px solid #dfdfdf;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.btn-check-label {
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
.caret {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
a[aria-expanded='true'] > .caret,
|
||||||
|
button[aria-expanded='true'] > .caret {
|
||||||
|
transform: rotate(-180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-group-details {
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
.list-group-header {
|
||||||
|
background: #f7f7f7;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.bg-primary, .alert-primary, .btn-primary {
|
||||||
|
background-color: #0F688D !important;
|
||||||
|
border-color: #0d526d !important;
|
||||||
|
}
|
||||||
|
.bg-info, .alert-info, .btn-info {
|
||||||
|
background-color: #148DBC !important;
|
||||||
|
border-color: #127ea8 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-secondary {
|
||||||
|
color: rgb(137 137 137)!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress {
|
||||||
|
background-color: #d5d5d5;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.btn-outline-secondary:hover {
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
}
|
||||||
|
.btn.btn-outline-secondary {
|
||||||
|
border-color: #cfcfcf !important;
|
||||||
|
}
|
||||||
|
.btn-check:checked+.btn-outline-secondary, .btn-check:active+.btn-outline-secondary, .btn-outline-secondary:active, .btn-outline-secondary.active, .btn-outline-secondary.dropdown-toggle.show {
|
||||||
|
background-color: #f0f0f0 !important;
|
||||||
|
}
|
||||||
@@ -1,7 +1,3 @@
|
|||||||
.space20 {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-xs-lg>.lang-sm:after {
|
.btn-xs-lg>.lang-sm:after {
|
||||||
margin-left: 4px;
|
margin-left: 4px;
|
||||||
}
|
}
|
||||||
@@ -10,110 +6,67 @@
|
|||||||
max-width: 350px;
|
max-width: 350px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel-login .apps .btn {
|
.card-login .apps .btn {
|
||||||
width: auto;
|
width: auto;
|
||||||
float: left;
|
float: left;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
}
|
}
|
||||||
.panel-login .apps .btn:hover {
|
.card-login .apps .btn:hover {
|
||||||
margin-top: 1px !important;
|
margin-top: 1px !important;
|
||||||
border-bottom-width: 3px;
|
border-bottom-width: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.responsive-tabs .nav-tabs {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dataTables_paginate.paging_simple_numbers .pagination {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
.responsive-tabs .nav-tabs {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.responsive-tabs .card .card-body.collapse {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@media (max-width: 767px) {
|
@media (max-width: 767px) {
|
||||||
.panel-login .apps .btn {
|
.responsive-tabs .tab-pane {
|
||||||
|
display: block !important;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-login .apps .btn {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
float: none;
|
float: none;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel-login .apps .btn {
|
.card-login .apps .btn {
|
||||||
border-bottom-width: 4px;
|
border-bottom-width: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.media-clearfix::after {
|
|
||||||
clear: both;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-clearfix::before {
|
|
||||||
display: table;
|
|
||||||
content: " ";
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.xs-show {
|
.xs-show {
|
||||||
display: block !important;
|
display: block !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.js-tabcollapse-panel-group .panel{
|
|
||||||
border: none;
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.js-tabcollapse-panel-group .panel-body {
|
|
||||||
padding: 10px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.js-tabcollapse-panel-group .js-tabcollapse-panel-body .panel-body {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.js-tabcollapse-panel-body .panel-heading {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.js-tabcollapse-panel-body .well,
|
|
||||||
.panel-body .form-inline.well {
|
|
||||||
border: none;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
box-shadow: none;
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.js-tabcollapse-panel-heading {
|
|
||||||
display: block;
|
|
||||||
height: 37px;
|
|
||||||
line-height: 37px;
|
|
||||||
text-indent: 15px;
|
|
||||||
}
|
|
||||||
.js-tabcollapse-panel-heading:hover {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
.js-tabcollapse-panel-heading {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.js-tabcollapse-panel-heading:after {
|
|
||||||
content: '';
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
top: 17px;
|
|
||||||
right: 17px;
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
margin-left: 2px;
|
|
||||||
vertical-align: middle;
|
|
||||||
border-bottom: 4px dashed;
|
|
||||||
border-right: 4px solid transparent;
|
|
||||||
border-left: 4px solid transparent;
|
|
||||||
}
|
|
||||||
.js-tabcollapse-panel-heading.collapsed:after {
|
|
||||||
border-bottom: none;
|
|
||||||
border-top: 4px dashed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.recent-login-success {
|
.recent-login-success {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
margin-top: 10px !important;
|
margin-top: 10px !important;
|
||||||
}
|
}
|
||||||
.pull-xs-right {
|
.pull-xs-right {
|
||||||
float: right !important;
|
float: right !important;
|
||||||
}
|
}
|
||||||
.pull-xs-right .dropdown-menu {
|
.pull-xs-right .dropdown-menu {
|
||||||
right: 0;
|
right: 0;
|
||||||
left: auto;
|
left: auto;
|
||||||
}
|
}
|
||||||
.text-xs-left {
|
.text-xs-left {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
@@ -125,36 +78,29 @@
|
|||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
text-align: justify;
|
text-align: justify;
|
||||||
}
|
}
|
||||||
.help-block {
|
.btn.d-block {
|
||||||
text-align: justify;
|
|
||||||
}
|
|
||||||
.btn.visible-xs-block {
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
float: none;
|
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
}
|
}
|
||||||
.btn-group.footable-actions .btn.btn-xs-half,
|
.btn.btn-xs-half,
|
||||||
.btn.visible-xs-block.btn-xs-half {
|
.btn.d-block.btn-xs-half {
|
||||||
width: 50%;
|
width: 50%;
|
||||||
float: left;
|
|
||||||
}
|
}
|
||||||
.btn-group.footable-actions .btn.btn-xs-third,
|
.btn.btn-xs-third,
|
||||||
.btn.visible-xs-block.btn-xs-third {
|
.btn.d-block.btn-xs-third {
|
||||||
width: 33.33%;
|
width: 33.33%;
|
||||||
float: left;
|
|
||||||
}
|
}
|
||||||
.btn-group.footable-actions .btn.btn-xs-quart,
|
.btn.btn-xs-quart,
|
||||||
.btn.visible-xs-block.btn-xs-quart {
|
.btn.d-block.btn-xs-quart {
|
||||||
width: 25%;
|
width: 25%;
|
||||||
float: left;
|
|
||||||
}
|
}
|
||||||
.btn.visible-xs-block.btn-sm,
|
.btn.d-block.btn-sm,
|
||||||
.btn-xs-lg {
|
.btn-xs-lg {
|
||||||
padding: 15px 16px 13px;
|
padding: .5rem 1rem;
|
||||||
line-height: 15px;
|
line-height: 20px;
|
||||||
}
|
}
|
||||||
.input-xs-lg {
|
.input-xs-lg {
|
||||||
height: 47px;
|
height: 47px;
|
||||||
padding: 13px 16px;
|
padding: 13px 16px;
|
||||||
}
|
}
|
||||||
.btn-group:not(.input-group-btn) {
|
.btn-group:not(.input-group-btn) {
|
||||||
@@ -167,27 +113,27 @@
|
|||||||
.btn-group.nowrap .dropdown-menu {
|
.btn-group.nowrap .dropdown-menu {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
.panel-login .btn-group {
|
.card-login .btn-group {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
.mass-actions-user .btn-group {
|
.mass-actions-user .btn-group {
|
||||||
float: none;
|
float: none;
|
||||||
}
|
}
|
||||||
div[class^='mass-actions'] .dropdown-menu,
|
div[class^='mass-actions'] .dropdown-menu,
|
||||||
.panel-xs-lg .dropdown-menu,
|
.card-xs-lg .dropdown-menu,
|
||||||
.dropdown-menu.login {
|
.dropdown-menu.login {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
div[class^='mass-actions'] .btn-group .dropdown-menu {
|
div[class^='mass-actions'] .btn-group .dropdown-menu {
|
||||||
top: 50%;
|
top: 50%;
|
||||||
}
|
}
|
||||||
div[class^='mass-actions'] .btn-group .btn-group .dropdown-menu,
|
div[class^='mass-actions'] .btn-group .btn-group .dropdown-menu,
|
||||||
div.mass-actions-quarantine .btn-group .dropdown-menu,
|
div.mass-actions-quarantine .btn-group .dropdown-menu,
|
||||||
.panel-xs-lg .dropdown-menu {
|
.card-xs-lg .dropdown-menu {
|
||||||
top: 100%;
|
top: 100%;
|
||||||
}
|
}
|
||||||
div[class^='mass-actions'] .dropdown-menu>li>a,
|
div[class^='mass-actions'] .dropdown-menu>li>a,
|
||||||
.panel-xs-lg .dropdown-menu>li>a,
|
.card-xs-lg .dropdown-menu>li>a,
|
||||||
.dropdown-menu.login>li>a {
|
.dropdown-menu.login>li>a {
|
||||||
padding: 8px 20px;
|
padding: 8px 20px;
|
||||||
}
|
}
|
||||||
@@ -195,9 +141,6 @@
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
.space20 {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
.top100 {
|
.top100 {
|
||||||
top: 100% !important;
|
top: 100% !important;
|
||||||
}
|
}
|
||||||
@@ -210,34 +153,17 @@
|
|||||||
.btn-xs-lg>.lang-sm:after {
|
.btn-xs-lg>.lang-sm:after {
|
||||||
top: 1px;
|
top: 1px;
|
||||||
}
|
}
|
||||||
table.footable>tfoot>tr.footable-paging>td {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
.footable-first-visible {
|
|
||||||
min-width: 55px;
|
|
||||||
}
|
|
||||||
table>tbody>tr>td>span.footable-toggle {
|
|
||||||
font-size: 24px;
|
|
||||||
margin-right: 14px !important;
|
|
||||||
}
|
|
||||||
table>tbody>tr>td>span.footable-toggle + input {
|
|
||||||
position: absolute;
|
|
||||||
left: 38px;
|
|
||||||
}
|
|
||||||
.pagination {
|
.pagination {
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
}
|
}
|
||||||
tr.footable-filtering>th>form {
|
|
||||||
width: 270px;
|
|
||||||
}
|
|
||||||
.mass-actions-mailbox {
|
.mass-actions-mailbox {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
.panel-xs-lg .panel-heading {
|
.card-xs-lg .card-header {
|
||||||
height: 66px;
|
height: 66px;
|
||||||
line-height: 47px;
|
line-height: 47px;
|
||||||
}
|
}
|
||||||
.panel-xs-lg .btn-group .btn {
|
.card-xs-lg .btn-group .btn {
|
||||||
padding-right: 5px;
|
padding-right: 5px;
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
}
|
}
|
||||||
@@ -250,55 +176,29 @@
|
|||||||
.bootstrap-select {
|
.bootstrap-select {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
.img-responsive {
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
.btn-group.footable-actions {
|
|
||||||
position: absolute;
|
|
||||||
width: 90vw !important;
|
|
||||||
left: 0;
|
|
||||||
height: 36px;
|
|
||||||
margin-top: -8px;
|
|
||||||
}
|
|
||||||
.btn-group.footable-actions .btn {
|
|
||||||
padding: 10px 16px 7px;
|
|
||||||
line-height: 15px;
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.btn-group.footable-actions:after {
|
|
||||||
content: "";
|
|
||||||
display: block;
|
|
||||||
clear: both;
|
|
||||||
}
|
|
||||||
.bootstrap-select.btn-group.show-tick .dropdown-menu li a span.text {
|
.bootstrap-select.btn-group.show-tick .dropdown-menu li a span.text {
|
||||||
margin-right: 14px;
|
margin-right: 14px;
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
}
|
}
|
||||||
.clearfix {
|
|
||||||
flex-basis: 100%;
|
|
||||||
height: 0;
|
|
||||||
}
|
|
||||||
.btn-group > .btn-group {
|
.btn-group > .btn-group {
|
||||||
flex-basis: 100%;
|
flex-basis: 100%;
|
||||||
}
|
}
|
||||||
.btn-group .btn {
|
.btn-group .btn {
|
||||||
display: flex !important;
|
display: flex !important;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
.btn-group .btn i {
|
.btn-group .btn i {
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
.btn-group .btn .caret {
|
.card-login .btn-group .btn {
|
||||||
margin-left: 5px;
|
|
||||||
}
|
|
||||||
.panel-login .btn-group .btn {
|
|
||||||
display: block !important;
|
display: block !important;
|
||||||
}
|
}
|
||||||
.panel-login .clearfix {
|
|
||||||
height: auto;
|
.dt-sm-head-hidden .dtr-title {
|
||||||
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 350px) {
|
@media (max-width: 350px) {
|
||||||
@@ -306,3 +206,9 @@
|
|||||||
max-width: 250px;
|
max-width: 250px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1400px) {
|
||||||
|
.container-xxl, .container-xl, .container-lg, .container-md, .container-sm, .container {
|
||||||
|
max-width: 1600px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
.dataTables_info {
|
||||||
|
margin: 15px 0 !important;
|
||||||
|
padding: 0px !important;
|
||||||
|
}
|
||||||
|
.dataTables_paginate, .dataTables_length, .dataTables_filter {
|
||||||
|
margin: 15px 0 !important;
|
||||||
|
}
|
||||||
|
.dtr-details {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.table-striped>tbody>tr:nth-of-type(odd) {
|
||||||
|
background-color: #F2F2F2;
|
||||||
|
}
|
||||||
|
td.child>ul>li {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
table.dataTable>tbody>tr.child ul.dtr-details>li {
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.129);
|
||||||
|
padding: 0.5em 0;
|
||||||
|
}
|
||||||
|
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dtr-control:before:hover,
|
||||||
|
table.dataTable.dtr-inline.collapsed>tbody>tr>th.dtr-control:before:hover {
|
||||||
|
background-color: #5e5e5e;
|
||||||
|
}
|
||||||
|
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dtr-control:before,
|
||||||
|
table.dataTable.dtr-inline.collapsed>tbody>tr>th.dtr-control:before,
|
||||||
|
table.dataTable td.dt-control:before {
|
||||||
|
background-color: #979797 !important;
|
||||||
|
border: 1.5px solid #616161 !important;
|
||||||
|
border-radius: 2px !important;
|
||||||
|
color: #fff;
|
||||||
|
height: 1em;
|
||||||
|
width: 1em;
|
||||||
|
line-height: 1.25em;
|
||||||
|
border-radius: 0px;
|
||||||
|
box-shadow: none;
|
||||||
|
font-size: 14px;
|
||||||
|
transition: 0.5s all;
|
||||||
|
}
|
||||||
|
table.dataTable.dtr-inline.collapsed>tbody>tr.parent>td.dtr-control:before,
|
||||||
|
table.dataTable.dtr-inline.collapsed>tbody>tr.parent>th.dtr-control:before,
|
||||||
|
table.dataTable td.dt-control:before {
|
||||||
|
background-color: #979797 !important;
|
||||||
|
}
|
||||||
|
table.dataTable.dtr-inline.collapsed>tbody>tr>td.child,
|
||||||
|
table.dataTable.dtr-inline.collapsed>tbody>tr>th.child,
|
||||||
|
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty {
|
||||||
|
background-color: #fbfbfb;
|
||||||
|
}
|
||||||
|
table.dataTable.table-striped>tbody>tr>td {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
table.dataTable.table-striped>tbody>tr>td>input[type="checkbox"] {
|
||||||
|
margin-top: 7px;
|
||||||
|
}
|
||||||
|
td.dtr-col-lg {
|
||||||
|
min-width: 350px;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
td.dtr-col-md {
|
||||||
|
min-width: 250px;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
td.dtr-col-sm {
|
||||||
|
min-width: 125px;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
.dt-data-w100 .dtr-data {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
li .dtr-data {
|
||||||
|
word-break: break-all;
|
||||||
|
flex: 1;
|
||||||
|
padding-left: 5px;
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
table.dataTable>tbody>tr.child span.dtr-title {
|
||||||
|
width: 30%;
|
||||||
|
max-width: 250px;
|
||||||
|
}
|
||||||
@@ -25,7 +25,6 @@ body.modal-open {
|
|||||||
}
|
}
|
||||||
.mass-actions-admin {
|
.mass-actions-admin {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
padding:10px 0 10px 0;
|
|
||||||
}
|
}
|
||||||
.inputMissingAttr {
|
.inputMissingAttr {
|
||||||
border-color: #FF4136;
|
border-color: #FF4136;
|
||||||
|
|||||||
@@ -26,7 +26,6 @@
|
|||||||
}
|
}
|
||||||
.mass-actions-debug {
|
.mass-actions-debug {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
padding:10px 0 10px 10px;
|
|
||||||
}
|
}
|
||||||
.inputMissingAttr {
|
.inputMissingAttr {
|
||||||
border-color: #FF4136;
|
border-color: #FF4136;
|
||||||
|
|||||||
@@ -21,7 +21,6 @@
|
|||||||
}
|
}
|
||||||
.mass-actions-user {
|
.mass-actions-user {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
padding:10px 0 10px 0;
|
|
||||||
}
|
}
|
||||||
.inputMissingAttr {
|
.inputMissingAttr {
|
||||||
border-color: #FF4136;
|
border-color: #FF4136;
|
||||||
|
|||||||
@@ -32,7 +32,6 @@
|
|||||||
}
|
}
|
||||||
.mass-actions-mailbox {
|
.mass-actions-mailbox {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
padding:10px 0 10px 10px;
|
|
||||||
}
|
}
|
||||||
.inputMissingAttr {
|
.inputMissingAttr {
|
||||||
border-color: #FF4136;
|
border-color: #FF4136;
|
||||||
|
|||||||
@@ -35,7 +35,6 @@
|
|||||||
|
|
||||||
.mass-actions-quarantine {
|
.mass-actions-quarantine {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
padding: 10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.inputMissingAttr {
|
.inputMissingAttr {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user