mirror of
https://github.com/mailcow/mailcow-dockerized.git
synced 2026-10-07 12:47:12 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
86beba6f5a | ||
|
|
f0d9948aee | ||
|
|
8e3d2f7010 | ||
|
|
fc1c5a505d | ||
|
|
18cb06fbc7 | ||
|
|
1af785a94f | ||
|
|
7626becb38 | ||
|
|
5d5e959729 | ||
|
|
49bbdd064e | ||
|
|
9279ee2e76 | ||
|
|
a76e6b32f7 | ||
|
|
4c6f8c4f60 | ||
|
|
826d32413b | ||
|
|
b6799d9fcb | ||
|
|
8782304e8d | ||
|
|
9c55d46bc6 | ||
|
|
099db33e44 | ||
|
|
152431a7d7 | ||
|
|
36fa5dc633 | ||
|
|
814f4aed15 | ||
|
|
e990856629 | ||
|
|
c97afbfa0b | ||
|
|
93b3e0302a | ||
|
|
27c87de4ed | ||
|
|
028ad4ceb9 | ||
|
|
e501642b8e | ||
|
|
7966f010a2 | ||
|
|
b22f74cb59 | ||
|
|
c928948b15 | ||
|
|
606eaad8f7 | ||
|
|
c44281f62d | ||
|
|
1e98784eee | ||
|
|
dd9296ffc2 | ||
|
|
fc0e6b6efb | ||
|
|
68f5fbf65c | ||
|
|
9727e4084f | ||
|
|
5c2f48e94c | ||
|
|
cb098df743 | ||
|
|
b3c54ed07a | ||
|
|
c601eca25d | ||
|
|
48a13255f3 | ||
|
|
08f93c7d58 | ||
|
|
e5c9752681 | ||
|
|
afa1ed1eff | ||
|
|
072cbe62de | ||
|
|
9fe8bfadf3 | ||
|
|
75e4953070 | ||
|
|
de30650dc7 | ||
|
|
690c34bc1d | ||
|
|
4d2e32ee40 | ||
|
|
02b2988beb | ||
|
|
3f1a5af88b | ||
|
|
850fd85d4d | ||
|
|
24acd42589 | ||
|
|
eaa0dea63b | ||
|
|
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 | ||
|
|
e53f431273 | ||
|
|
8e0ee67108 | ||
|
|
3d82d9af1b | ||
|
|
8a0bd23985 | ||
|
|
4387e4764f | ||
|
|
3b8e17c21f | ||
|
|
e74af0db89 | ||
|
|
5ff62d8f22 | ||
|
|
4427173a6c | ||
|
|
db66fe33fa | ||
|
|
cf5fa96a93 | ||
|
|
9e76b6ee70 | ||
|
|
45e97b3753 | ||
|
|
ecc16c69e6 | ||
|
|
77e6124b00 | ||
|
|
a3ddb58566 | ||
|
|
be7252f620 | ||
|
|
f34d3620b1 | ||
|
|
70e99447f9 | ||
|
|
db8af3d1e0 | ||
|
|
7f70b0f703 | ||
|
|
2e10cc8e79 | ||
|
|
047d9143c0 | ||
|
|
a7a0eef125 | ||
|
|
5d35af9d69 | ||
|
|
ea21bca7df | ||
|
|
a3c0737ba8 | ||
|
|
7b57b3392c | ||
|
|
492451bfee | ||
|
|
9747995510 | ||
|
|
ad9112010f | ||
|
|
a4ec2d1d86 | ||
|
|
b7f07951f6 | ||
|
|
0e3363e61c | ||
|
|
a1e8077f45 | ||
|
|
956e4e2aa7 | ||
|
|
c2e0a275e1 | ||
|
|
514079fe96 | ||
|
|
e26d5b8ba5 | ||
|
|
8987ebca36 | ||
|
|
d3cd21956a | ||
|
|
b149da28c8 | ||
|
|
e5cb2dd00e | ||
|
|
c9b883dff5 | ||
|
|
ad43253a90 | ||
|
|
979de67c2b | ||
|
|
8416caf798 | ||
|
|
80d9dfe420 | ||
|
|
27e9210d52 | ||
|
|
8a49b50f33 | ||
|
|
1b6e5b7116 | ||
|
|
0dab215e27 | ||
|
|
6ec136e63f | ||
|
|
bba5671eaf | ||
|
|
88d7593d89 | ||
|
|
bd23b80d45 | ||
|
|
f96e0c4071 | ||
|
|
cbd8e40f14 | ||
|
|
2d2c033ba7 | ||
|
|
496c68d2af | ||
|
|
c505943e8b | ||
|
|
2841c09c1f | ||
|
|
18444bd284 | ||
|
|
9d3a89d362 | ||
|
|
2d0ab4a1b8 | ||
|
|
2fec7ccd58 | ||
|
|
052959f435 | ||
|
|
560df58bb4 | ||
|
|
5629d47cb6 | ||
|
|
37b4ff811d | ||
|
|
7384aab2f4 | ||
|
|
4ce05d4d4d | ||
|
|
fdb56de0a8 | ||
|
|
df56d73cec | ||
|
|
4ba0e155f3 | ||
|
|
304655f7ff | ||
|
|
6210f06bc0 | ||
|
|
09ae37410e | ||
|
|
351c803623 | ||
|
|
6a027b70e7 | ||
|
|
cdd2adbc73 | ||
|
|
cb6a5d4069 | ||
|
|
f13530d8a1 | ||
|
|
8a86fa491e | ||
|
|
3e6a241c69 | ||
|
|
160dceff3e | ||
|
|
0ece065cb0 | ||
|
|
fb7e00c158 | ||
|
|
a0567beee5 | ||
|
|
96c8e01a3b | ||
|
|
88bd7bff1e | ||
|
|
7075b9f0c0 | ||
|
|
b19666f7e0 | ||
|
|
e663f3db72 | ||
|
|
fd1ffdba80 | ||
|
|
a12538b3a8 | ||
|
|
cdff1ba37b | ||
|
|
f6a51f6b6f | ||
|
|
45dd0611d9 | ||
|
|
e62069d3db | ||
|
|
5088636d5f | ||
|
|
003d70990e | ||
|
|
051d08b499 | ||
|
|
b980e7af29 | ||
|
|
4d0799dead | ||
|
|
d3dca1ddc2 | ||
|
|
9b8039440c | ||
|
|
eea5c9df2f | ||
|
|
aa9aff800c | ||
|
|
0b3b5e230b | ||
|
|
db0d91beb1 | ||
|
|
4758033445 | ||
|
|
1e48fb8cda | ||
|
|
1d8da117d6 | ||
|
|
635fa795d2 | ||
|
|
c1792df819 | ||
|
|
36944f8073 | ||
|
|
4d59cb0351 |
No files matched your search
+1
-1
@@ -1 +1 @@
|
|||||||
custom: https://mailcow.github.io/mailcow-dockerized-docs/#help-mailcow
|
custom: ["https://www.servercow.de/mailcow?lang=en#sal"]
|
||||||
@@ -7,8 +7,8 @@ body:
|
|||||||
label: Contribution guidelines
|
label: Contribution guidelines
|
||||||
description: Please read the contribution guidelines before proceeding.
|
description: Please read the contribution guidelines before proceeding.
|
||||||
options:
|
options:
|
||||||
- label: I've read the [contribution guidelines](https://github.com/mailcow/mailcow-dockerized/blob/master/CONTRIBUTING.md) and wholeheartedly agree
|
- label: I've read the [contribution guidelines](https://github.com/mailcow/mailcow-dockerized/blob/master/CONTRIBUTING.md) and wholeheartedly agree
|
||||||
required: true
|
required: true
|
||||||
- type: checkboxes
|
- type: checkboxes
|
||||||
attributes:
|
attributes:
|
||||||
label: I've found a bug and checked that ...
|
label: I've found a bug and checked that ...
|
||||||
@@ -26,70 +26,132 @@ body:
|
|||||||
attributes:
|
attributes:
|
||||||
label: Description
|
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.
|
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:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: Logs
|
label: "Logs:"
|
||||||
description: 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. This will be automatically formatted into code, so no need for backticks.
|
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: bash
|
render: plain text
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: Steps to reproduce
|
label: "Steps to reproduce:"
|
||||||
description: Please describe the steps to reproduce the bug. Screenshots can be added, if helpful.
|
description: "Please describe the steps to reproduce the bug. Screenshots can be added, if helpful."
|
||||||
|
render: plain text
|
||||||
placeholder: |-
|
placeholder: |-
|
||||||
1. ...
|
1. ...
|
||||||
2. ...
|
2. ...
|
||||||
3. ...
|
3. ...
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
label: System information
|
value: |
|
||||||
description: In this stage we would kindly ask you to attach general system information about your setup.
|
## System information
|
||||||
value: |-
|
### In this stage we would kindly ask you to attach general system information about your setup.
|
||||||
| Question | Answer |
|
- type: dropdown
|
||||||
| --- | --- |
|
attributes:
|
||||||
| My operating system | I_DO_REPLY_HERE |
|
label: "Which branch are you using?"
|
||||||
| Is Apparmor, SELinux or similar active? | I_DO_REPLY_HERE |
|
description: "#### `git rev-parse --abbrev-ref HEAD`"
|
||||||
| Virtualization technology (KVM, VMware, Xen, etc - **LXC and OpenVZ are not supported** | I_DO_REPLY_HERE |
|
multiple: false
|
||||||
| Server/VM specifications (Memory, CPU Cores) | I_DO_REPLY_HERE |
|
options:
|
||||||
| Docker version (`docker version`) | I_DO_REPLY_HERE |
|
- master
|
||||||
| docker-compose version (`docker-compose version`) | I_DO_REPLY_HERE |
|
- nightly
|
||||||
| mailcow version (```git describe --tags `git rev-list --tags --max-count=1` ```) | I_DO_REPLY_HERE |
|
validations:
|
||||||
| Reverse proxy (custom solution) | I_DO_REPLY_HERE |
|
required: true
|
||||||
|
- type: input
|
||||||
Output of `git diff origin/master`, any other changes to the code? If so, **please post them**:
|
attributes:
|
||||||
```
|
label: "Operating System:"
|
||||||
YOUR OUTPUT GOES HERE
|
placeholder: "e.g. Ubuntu 22.04 LTS"
|
||||||
```
|
validations:
|
||||||
|
required: true
|
||||||
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:
|
- type: input
|
||||||
iptables -L -vn:
|
attributes:
|
||||||
```
|
label: "Server/VM specifications:"
|
||||||
YOUR OUTPUT GOES HERE
|
placeholder: "Memory, CPU Cores"
|
||||||
```
|
validations:
|
||||||
|
required: true
|
||||||
ip6tables -L -vn:
|
- type: input
|
||||||
```
|
attributes:
|
||||||
YOUR OUTPUT GOES HERE
|
label: "Is Apparmor, SELinux or similar active?"
|
||||||
```
|
placeholder: "yes/no"
|
||||||
|
validations:
|
||||||
iptables -L -vn -t nat:
|
required: true
|
||||||
```
|
- type: input
|
||||||
YOUR OUTPUT GOES HERE
|
attributes:
|
||||||
```
|
label: "Virtualization technology:"
|
||||||
|
placeholder: "KVM, VMware, Xen, etc - **LXC and OpenVZ are not supported**"
|
||||||
ip6tables -L -vn -t nat:
|
validations:
|
||||||
```
|
required: true
|
||||||
YOUR OUTPUT GOES HERE
|
- type: input
|
||||||
```
|
attributes:
|
||||||
|
label: "Docker version:"
|
||||||
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:
|
description: "#### `docker version`"
|
||||||
```
|
placeholder: "20.10.21"
|
||||||
YOUR OUTPUT GOES HERE
|
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:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
@@ -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,31 @@
|
|||||||
|
{
|
||||||
|
"enabled": true,
|
||||||
|
"timezone": "Europe/Berlin",
|
||||||
|
"dependencyDashboard": true,
|
||||||
|
"dependencyDashboardTitle": "Renovate Dashboard",
|
||||||
|
"commitBody": "Signed-off-by: milkmaker <milkmaker@mailcow.de>",
|
||||||
|
"rebaseWhen": "auto",
|
||||||
|
"labels": ["renovate"],
|
||||||
|
"assignees": [
|
||||||
|
"@magiccc"
|
||||||
|
],
|
||||||
|
"baseBranches": ["staging"],
|
||||||
|
"enabledManagers": ["github-actions", "regex", "docker-compose"],
|
||||||
|
"ignorePaths": [
|
||||||
|
"data\/web\/inc\/lib\/vendor\/matthiasmullie\/minify\/**"
|
||||||
|
],
|
||||||
|
"regexManagers": [
|
||||||
|
{
|
||||||
|
"fileMatch": ["^helper-scripts\/nextcloud.sh$"],
|
||||||
|
"matchStrings": [
|
||||||
|
"#\\srenovate:\\sdatasource=(?<datasource>.*?) depName=(?<depName>.*?)( versioning=(?<versioning>.*?))?( extractVersion=(?<extractVersion>.*?))?\\s.*?_VERSION=(?<currentValue>.*)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fileMatch": ["(^|/)Dockerfile[^/]*$"],
|
||||||
|
"matchStrings": [
|
||||||
|
"#\\srenovate:\\sdatasource=(?<datasource>.*?) depName=(?<depName>.*?)( versioning=(?<versioning>.*?))?\\s(ENV|ARG) .*?_VERSION=(?<currentValue>.*)\\s"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
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@v2.3.1
|
||||||
|
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@v6.0.0
|
uses: actions/stale@v7.0.0
|
||||||
with:
|
with:
|
||||||
repo-token: ${{ secrets.STALE_ACTION_PAT }}
|
repo-token: ${{ secrets.STALE_ACTION_PAT }}
|
||||||
days-before-stale: 60
|
days-before-stale: 60
|
||||||
|
|||||||
@@ -33,13 +33,11 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
curl -sSL https://get.docker.com/ | CHANNEL=stable sudo sh
|
curl -sSL https://get.docker.com/ | CHANNEL=stable sudo sh
|
||||||
sudo service docker start
|
sudo service docker start
|
||||||
sudo curl -L https://github.com/docker/compose/releases/download/v$(curl -Ls https://www.servercow.de/docker-compose/latest.php)/docker-compose-$(uname -s)-$(uname -m) > /usr/local/bin/docker-compose
|
|
||||||
sudo chmod +x /usr/local/bin/docker-compose
|
|
||||||
- name: Prepair Image Builds
|
- name: Prepair Image Builds
|
||||||
run: |
|
run: |
|
||||||
cp helper-scripts/docker-compose.override.yml.d/BUILD_FLAGS/docker-compose.override.yml docker-compose.override.yml
|
cp helper-scripts/docker-compose.override.yml.d/BUILD_FLAGS/docker-compose.override.yml docker-compose.override.yml
|
||||||
- name: Build Docker Images
|
- name: Build Docker Images
|
||||||
run: |
|
run: |
|
||||||
docker-compose build ${image}
|
docker compose build ${image}
|
||||||
env:
|
env:
|
||||||
image: ${{ matrix.images }}
|
image: ${{ matrix.images }}
|
||||||
@@ -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
|
||||||
@@ -4,14 +4,17 @@ on:
|
|||||||
types: [published]
|
types: [published]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
tweet:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
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
|
- name: Tweet-trigger-publish-release
|
||||||
uses: mugi111/tweet-trigger-release@v1.1
|
uses: mugi111/tweet-trigger-release@v1.2
|
||||||
with:
|
with:
|
||||||
consumer_key: ${{ secrets.CONSUMER_KEY }}
|
consumer_key: ${{ secrets.CONSUMER_KEY }}
|
||||||
consumer_secret: ${{ secrets.CONSUMER_SECRET }}
|
consumer_secret: ${{ secrets.CONSUMER_SECRET }}
|
||||||
access_token_key: ${{ secrets.ACCESS_TOKEN_KEY }}
|
access_token_key: ${{ secrets.ACCESS_TOKEN_KEY }}
|
||||||
access_token_secret: ${{ secrets.ACCESS_TOKEN_SECRET }}
|
access_token_secret: ${{ secrets.ACCESS_TOKEN_SECRET }}
|
||||||
tweet_body: 'A new mailcow-dockerized Release has been Released on GitHub! Checkout our GitHub Page for the latest Release: github.com/mailcow/mailcow-dockerized/releases/latest'
|
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'
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
# mailcow: dockerized - 🐮 + 🐋 = 💕
|
# mailcow: dockerized - 🐮 + 🐋 = 💕
|
||||||
|
|
||||||
## We stand with 🇺🇦
|
|
||||||
|
|
||||||
[](https://github.com/mailcow/mailcow-dockerized/actions/workflows/integration_tests.yml)
|
[](https://github.com/mailcow/mailcow-dockerized/actions/workflows/integration_tests.yml)
|
||||||
[](https://translate.mailcow.email/engage/mailcow-dockerized/)
|
[](https://translate.mailcow.email/engage/mailcow-dockerized/)
|
||||||
[](https://twitter.com/mailcow_email)
|
[](https://twitter.com/mailcow_email)
|
||||||
@@ -36,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é)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM alpine:3.16
|
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,4 +1,4 @@
|
|||||||
FROM clamav/clamav:0.105.1_base
|
FROM clamav/clamav:1.0_base
|
||||||
|
|
||||||
LABEL maintainer "André Peters <andre.peters@servercow.de>"
|
LABEL maintainer "André Peters <andre.peters@servercow.de>"
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM alpine:3.16
|
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
|
|
||||||
for line in cmd_response.split("\n"):
|
|
||||||
if '$2$' in line:
|
|
||||||
hash = line.strip()
|
|
||||||
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"
|
cmd = "./set_worker_password.sh '" + request_json['raw'].replace("'", "'\\''") + "' 2> /dev/null"
|
||||||
cmd = '''/bin/echo 'enable_password = "%s";' > %s && cat %s''' % (rspamd_passphrase_hash, rspamd_password_filename, rspamd_password_filename)
|
rspamd_password_exec = await container.exec(cmd, user='_rspamd')
|
||||||
cmd_response = exec_cmd_container(container, cmd, user="_rspamd")
|
async with rspamd_password_exec.start(detach=False) as stream:
|
||||||
|
rspamd_password_return = await stream.read_out()
|
||||||
|
|
||||||
if rspamd_passphrase_hash.startswith("$2$") and rspamd_passphrase_hash in cmd_response:
|
matched = False
|
||||||
container.restart()
|
if "OK" in rspamd_password_return.data.decode('utf-8'):
|
||||||
matched = True
|
matched = True
|
||||||
|
await container.restart()
|
||||||
|
|
||||||
if matched:
|
if matched:
|
||||||
return jsonify(type='success', msg='command completed successfully')
|
res = {
|
||||||
else:
|
'type': 'success',
|
||||||
return jsonify(type='danger', msg='command did not complete')
|
'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")
|
||||||
|
|
||||||
def exec_cmd_container(container, cmd, user, timeout=2, shell_cmd="/bin/bash"):
|
|
||||||
|
|
||||||
def recv_socket_data(c_socket, timeout):
|
|
||||||
c_socket.setblocking(0)
|
|
||||||
total_data=[];
|
|
||||||
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 :
|
async def exec_run_handler(type, exec_obj):
|
||||||
socket = container.exec_run([shell_cmd], stdin=True, socket=True, user=user).output._sock
|
async with exec_obj.start(detach=False) as stream:
|
||||||
if not cmd.endswith("\n"):
|
exec_return = await stream.read_out()
|
||||||
cmd = cmd + "\n"
|
|
||||||
socket.send(cmd.encode('utf-8'))
|
|
||||||
data = recv_socket_data(socket, timeout)
|
|
||||||
socket.close()
|
|
||||||
return data
|
|
||||||
|
|
||||||
except Exception as e:
|
if exec_return == None:
|
||||||
print("error - exec_cmd_container: %s" % str(e))
|
exec_return = ""
|
||||||
traceback.print_exc(file=sys.stdout)
|
else:
|
||||||
|
exec_return = exec_return.data.decode('utf-8')
|
||||||
|
|
||||||
def exec_run_handler(type, output):
|
|
||||||
if type == 'generic':
|
if type == 'generic':
|
||||||
if output.exit_code == 0:
|
exec_details = await exec_obj.inspect()
|
||||||
return jsonify(type='success', msg='command completed successfully')
|
if exec_details["ExitCode"] == None or exec_details["ExitCode"] == 0:
|
||||||
|
res = {
|
||||||
|
"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')
|
||||||
@@ -2,9 +2,12 @@ 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.19.1
|
# renovate: datasource=github-tags depName=dovecot/core versioning=semver-coerced
|
||||||
|
ARG DOVECOT=2.3.20
|
||||||
|
# renovate: datasource=github-releases depName=tianon/gosu versioning=semver-coerced
|
||||||
|
ARG GOSU_VERSION=1.16
|
||||||
ENV LC_ALL C
|
ENV LC_ALL C
|
||||||
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 \
|
||||||
|
|||||||
@@ -166,17 +166,11 @@ while ($row = $sth->fetchrow_arrayref()) {
|
|||||||
$success = 1;
|
$success = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
$keep_job_active = 1;
|
$update = $dbh->prepare("UPDATE imapsync SET returned_text = ?, success = ?, exit_status = ? WHERE id = ?");
|
||||||
if (defined $exit_status && $exit_status eq "EXIT_AUTHENTICATION_FAILURE_USER1") {
|
|
||||||
$keep_job_active = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
$update = $dbh->prepare("UPDATE imapsync SET returned_text = ?, success = ?, exit_status = ?, active = ? WHERE id = ?");
|
|
||||||
$update->bind_param( 1, ${stdout} );
|
$update->bind_param( 1, ${stdout} );
|
||||||
$update->bind_param( 2, ${success} );
|
$update->bind_param( 2, ${success} );
|
||||||
$update->bind_param( 3, ${exit_status} );
|
$update->bind_param( 3, ${exit_status} );
|
||||||
$update->bind_param( 4, ${keep_job_active} );
|
$update->bind_param( 4, ${id} );
|
||||||
$update->bind_param( 5, ${id} );
|
|
||||||
$update->execute();
|
$update->execute();
|
||||||
} catch {
|
} catch {
|
||||||
$update = $dbh->prepare("UPDATE imapsync SET returned_text = 'Could not start or finish imapsync', success = 0 WHERE id = ?");
|
$update = $dbh->prepare("UPDATE imapsync SET returned_text = 'Could not start or finish imapsync', success = 0 WHERE id = ?");
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM alpine:3.16
|
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
|
||||||
|
|||||||
@@ -97,9 +97,9 @@ def refreshF2bregex():
|
|||||||
f2bregex[3] = 'warning: .*\[([0-9a-f\.:]+)\]: SASL .+ authentication failed: (?!.*Connection lost to authentication server).+'
|
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))
|
||||||
@@ -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,16 +358,23 @@ 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...')
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM alpine:3.16
|
FROM alpine:3.17
|
||||||
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
|
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
FROM php:8.0-fpm-alpine3.16
|
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.21
|
# renovate: datasource=github-tags depName=krakjoe/apcu versioning=semver-coerced
|
||||||
ENV IMAGICK_PECL 3.7.0
|
ARG APCU_PECL_VERSION=5.1.22
|
||||||
# Mailparse is pulled from master branch
|
# renovate: datasource=github-tags depName=Imagick/imagick versioning=semver-coerced
|
||||||
#ENV MAILPARSE_PECL 3.0.2
|
ARG IMAGICK_PECL_VERSION=3.7.0
|
||||||
ENV MEMCACHED_PECL 3.2.0
|
# renovate: datasource=github-tags depName=php/pecl-mail-mailparse versioning=semver-coerced
|
||||||
ENV REDIS_PECL 5.3.7
|
ARG MAILPARSE_PECL_VERSION=3.1.4
|
||||||
|
# renovate: datasource=github-tags depName=php-memcached-dev/php-memcached versioning=semver-coerced
|
||||||
|
ARG MEMCACHED_PECL_VERSION=3.2.0
|
||||||
|
# renovate: datasource=github-tags depName=phpredis/phpredis versioning=semver-coerced
|
||||||
|
ARG REDIS_PECL_VERSION=5.3.7
|
||||||
|
# renovate: datasource=github-tags depName=composer/composer versioning=semver-coerced
|
||||||
|
ARG COMPOSER_VERSION=2.5.1
|
||||||
|
|
||||||
RUN apk add -U --no-cache autoconf \
|
RUN apk add -U --no-cache autoconf \
|
||||||
aspell-dev \
|
aspell-dev \
|
||||||
@@ -18,6 +24,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 +34,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 +48,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 +61,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 APCu-${APCU_PECL_VERSION} \
|
||||||
&& cd pecl-mail-mailparse \
|
&& pecl install imagick-${IMAGICK_PECL_VERSION} \
|
||||||
&& pecl install package.xml \
|
&& pecl install mailparse-${MAILPARSE_PECL_VERSION} \
|
||||||
&& cd .. \
|
&& pecl install memcached-${MEMCACHED_PECL_VERSION} \
|
||||||
&& rm -r pecl-mail-mailparse \
|
&& pecl install redis-${REDIS_PECL_VERSION} \
|
||||||
&& 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_VERSION} \
|
||||||
&& 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 +86,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
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ RUN apt-get update && apt-get install -y \
|
|||||||
|
|
||||||
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
|
||||||
@@ -3,8 +3,9 @@ LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
|
|||||||
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
ARG SOGO_DEBIAN_REPOSITORY=http://packages.sogo.nu/nightly/5/debian/
|
ARG SOGO_DEBIAN_REPOSITORY=http://packages.sogo.nu/nightly/5/debian/
|
||||||
|
# renovate: datasource=github-releases depName=tianon/gosu versioning=semver-coerced
|
||||||
|
ARG GOSU_VERSION=1.16
|
||||||
ENV LC_ALL C
|
ENV LC_ALL C
|
||||||
ENV GOSU_VERSION 1.14
|
|
||||||
|
|
||||||
# Prerequisites
|
# Prerequisites
|
||||||
RUN echo "Building from repository $SOGO_DEBIAN_REPOSITORY" \
|
RUN echo "Building from repository $SOGO_DEBIAN_REPOSITORY" \
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ FROM solr:7.7-slim
|
|||||||
|
|
||||||
USER root
|
USER root
|
||||||
|
|
||||||
ENV GOSU_VERSION 1.11
|
# renovate: datasource=github-releases depName=tianon/gosu versioning=semver-coerced
|
||||||
|
ARG GOSU_VERSION=1.16
|
||||||
|
|
||||||
COPY solr.sh /
|
COPY solr.sh /
|
||||||
COPY solr-config-7.7.0.xml /
|
COPY solr-config-7.7.0.xml /
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM alpine:3.16
|
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.16
|
FROM alpine:3.17
|
||||||
LABEL maintainer "André Peters <andre.peters@servercow.de>"
|
LABEL maintainer "André Peters <andre.peters@servercow.de>"
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
+2
-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'),
|
||||||
@@ -109,9 +103,11 @@ $template_data = [
|
|||||||
'rsettings' => $rsettings,
|
'rsettings' => $rsettings,
|
||||||
'rspamd_regex_maps' => $rspamd_regex_maps,
|
'rspamd_regex_maps' => $rspamd_regex_maps,
|
||||||
'logo_specs' => customize('get', 'main_logo_specs'),
|
'logo_specs' => customize('get', 'main_logo_specs'),
|
||||||
|
'ip_check' => customize('get', 'ip_check'),
|
||||||
'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';
|
||||||
@@ -3349,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: ""
|
||||||
@@ -3392,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: ""
|
||||||
@@ -3413,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
|
||||||
@@ -5501,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
|
||||||
|
|||||||
-11
@@ -1,11 +0,0 @@
|
|||||||
/*!
|
|
||||||
* bootswatch v3.4.1
|
|
||||||
* Homepage: http://bootswatch.com
|
|
||||||
* Copyright 2012-2019 Thomas Park
|
|
||||||
* Licensed under MIT
|
|
||||||
* Based on Bootstrap
|
|
||||||
*//*!
|
|
||||||
* Bootstrap v3.4.1 (https://getbootstrap.com/)
|
|
||||||
* Copyright 2011-2019 Twitter, Inc.
|
|
||||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
|
||||||
*//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}*{box-sizing:border-box}:after,:before{box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:transparent}body{font-family:"Source Sans Pro","Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#158cba;text-decoration:none}a:focus,a:hover{color:#158cba;text-decoration:underline}a:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:5px}.img-thumbnail{padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #eee;border-radius:4px;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:400;line-height:1.1;color:#333}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#999}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-Line truncated
|
|
||||||
+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 */
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
/*!
|
|
||||||
* Bootstrap-select v1.12.2 (http://silviomoreto.github.io/bootstrap-select)
|
|
||||||
*
|
|
||||||
* Copyright 2013-2017 bootstrap-select
|
|
||||||
* Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
|
|
||||||
*/select.bs-select-hidden,select.selectpicker{display:none!important}.bootstrap-select{width:220px\9}.bootstrap-select>.dropdown-toggle{width:100%;padding-right:25px;z-index:1}.bootstrap-select>.dropdown-toggle.bs-placeholder,.bootstrap-select>.dropdown-toggle.bs-placeholder:active,.bootstrap-select>.dropdown-toggle.bs-placeholder:focus,.bootstrap-select>.dropdown-toggle.bs-placeholder:hover{color:#999}.bootstrap-select>select{position:absolute!important;bottom:0;left:50%;display:block!important;width:.5px!important;height:100%!important;padding:0!important;opacity:0!important;border:none}.bootstrap-select>select.mobile-device{top:0;left:0;display:block!important;width:100%!important;z-index:2}.error .bootstrap-select .dropdown-toggle,.has-error .bootstrap-select .dropdown-toggle{border-color:#b94a48}.bootstrap-select.fit-width{width:auto!important}.bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn){width:220px}.bootstrap-select .dropdown-toggle:focus{outline:thin dotted #333!important;outline:5px auto -webkit-focus-ring-color!important;outline-offset:-2px}.bootstrap-select.form-control{margin-bottom:0;padding:0;border:none}.bootstrap-select.form-control:not([class*=col-]){width:100%}.bootstrap-select.form-control.input-group-btn{z-index:auto}.bootstrap-select.form-control.input-group-btn:not(:first-child):not(:last-child)>.btn{border-radius:0}.bootstrap-select.btn-group:not(.input-group-btn),.bootstrap-select.btn-group[class*=col-]{float:none;display:inline-block;margin-left:0}.bootstrap-select.btn-group.dropdown-menu-right,.bootstrap-select.btn-group[class*=col-].dropdown-menu-right,.row .bootstrap-select.btn-group[class*=col-].dropdown-menu-right{float:right}.form-group .bootstrap-select.btn-group,.form-horizontal .bootstrap-select.btn-group,.form-inline .bootstrap-select.btn-group{margin-bottom:0}.form-group-lg .bootstrap-select.btn-group.form-control,.form-group-sm .bootstrap-select.btn-group.form-control{padding:0}.form-group-lg .bootstrap-select.btn-group.form-control .dropdown-toggle,.form-group-sm .bootstrap-select.btn-group.form-control .dropdown-toggle{height:100%;font-size:inherit;line-height:inherit;border-radius:inherit}.form-inline .bootstrap-select.btn-group .form-control{width:100%}.bootstrap-select.btn-group.disabled,.bootstrap-select.btn-group>.disabled{cursor:not-allowed}.bootstrap-select.btn-group.disabled:focus,.bootstrap-select.btn-group>.disabled:focus{outline:0!important}.bootstrap-select.btn-group.bs-container{position:absolute;height:0!important;padding:0!important}.bootstrap-select.btn-group.bs-container .dropdown-menu{z-index:1060}.bootstrap-select.btn-group .dropdown-toggle .filter-option{display:inline-block;overflow:hidden;width:100%;text-align:left}.bootstrap-select.btn-group .dropdown-toggle .caret{position:absolute;top:50%;right:12px;margin-top:-2px;vertical-align:middle}.bootstrap-select.btn-group[class*=col-] .dropdown-toggle{width:100%}.bootstrap-select.btn-group .dropdown-menu{min-width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.bootstrap-select.btn-group .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.btn-group .dropdown-menu li{position:relative}.bootstrap-select.btn-group .dropdown-menu li.active small{color:#fff}.bootstrap-select.btn-group .dropdown-menu li.disabled a{cursor:not-allowed}.bootstrap-select.btn-group .dropdown-menu li a{cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.bootstrap-select.btn-group .dropdown-menu li a.opt{position:relative;padding-left:2.25em}.bootstrap-select.btn-group .dropdown-menu li a span.check-mark{display:none}.bootstrap-select.btn-group .dropdown-menu li a span.text{display:inline-block}.bootstrap-select.btn-group .dropdown-menu li small{padding-left:.5em}.bootstrap-select.btn-group .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,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05);pointer-events:none;opacity:.9;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.bootstrap-select.btn-group .no-results{padding:3px;background:#f5f5f5;margin:0 5px;white-space:nowrap}.bootstrap-select.btn-group.fit-width .dropdown-toggle .filter-option{position:static}.bootstrap-select.btn-group.fit-width .dropdown-toggle .caret{position:static;top:auto;margin-top:-1px}.bootstrap-select.btn-group.show-tick .dropdown-menu li.selected a span.check-mark{position:absolute;display:inline-block;right:15px;margin-top:5px}.bootstrap-select.btn-group.show-tick .dropdown-menu li a span.text{margin-right:34px}.bootstrap-select.show-menu-arrow.open>.dropdown-toggle{z-index:1061}.bootstrap-select.show-menu-arrow .dropdown-toggle:before{content:'';border-left:7px solidLine truncated
|
|
||||||
-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
@@ -1 +1 @@
|
|||||||
.flag-icon-background{background-size:contain;background-position:50%;background-repeat:no-repeat}.flag-icon{background-size:contain;background-position:50%;background-repeat:no-repeat;position:relative;display:inline-block;width:1.33333333em;line-height:1em}.flag-icon:before{content:'\00a0'}.flag-icon.flag-icon-squared{width:1em}.flag-icon-ad{background-image:url(../flags/4x3/ad.svg)}.flag-icon-ad.flag-icon-squared{background-image:url(../flags/1x1/ad.svg)}.flag-icon-ae{background-image:url(../flags/4x3/ae.svg)}.flag-icon-ae.flag-icon-squared{background-image:url(../flags/1x1/ae.svg)}.flag-icon-af{background-image:url(../flags/4x3/af.svg)}.flag-icon-af.flag-icon-squared{background-image:url(../flags/1x1/af.svg)}.flag-icon-ag{background-image:url(../flags/4x3/ag.svg)}.flag-icon-ag.flag-icon-squared{background-image:url(../flags/1x1/ag.svg)}.flag-icon-ai{background-image:url(../flags/4x3/ai.svg)}.flag-icon-ai.flag-icon-squared{background-image:url(../flags/1x1/ai.svg)}.flag-icon-al{background-image:url(../flags/4x3/al.svg)}.flag-icon-al.flag-icon-squared{background-image:url(../flags/1x1/al.svg)}.flag-icon-am{background-image:url(../flags/4x3/am.svg)}.flag-icon-am.flag-icon-squared{background-image:url(../flags/1x1/am.svg)}.flag-icon-ao{background-image:url(../flags/4x3/ao.svg)}.flag-icon-ao.flag-icon-squared{background-image:url(../flags/1x1/ao.svg)}.flag-icon-aq{background-image:url(../flags/4x3/aq.svg)}.flag-icon-aq.flag-icon-squared{background-image:url(../flags/1x1/aq.svg)}.flag-icon-ar{background-image:url(../flags/4x3/ar.svg)}.flag-icon-ar.flag-icon-squared{background-image:url(../flags/1x1/ar.svg)}.flag-icon-as{background-image:url(../flags/4x3/as.svg)}.flag-icon-as.flag-icon-squared{background-image:url(../flags/1x1/as.svg)}.flag-icon-at{background-image:url(../flags/4x3/at.svg)}.flag-icon-at.flag-icon-squared{background-image:url(../flags/1x1/at.svg)}.flag-icon-au{background-image:url(../flags/4x3/au.svg)}.flag-icon-au.flag-icon-squared{background-image:url(../flags/1x1/au.svg)}.flag-icon-aw{background-image:url(../flags/4x3/aw.svg)}.flag-icon-aw.flag-icon-squared{background-image:url(../flags/1x1/aw.svg)}.flag-icon-ax{background-image:url(../flags/4x3/ax.svg)}.flag-icon-ax.flag-icon-squared{background-image:url(../flags/1x1/ax.svg)}.flag-icon-az{background-image:url(../flags/4x3/az.svg)}.flag-icon-az.flag-icon-squared{background-image:url(../flags/1x1/az.svg)}.flag-icon-ba{background-image:url(../flags/4x3/ba.svg)}.flag-icon-ba.flag-icon-squared{background-image:url(../flags/1x1/ba.svg)}.flag-icon-bb{background-image:url(../flags/4x3/bb.svg)}.flag-icon-bb.flag-icon-squared{background-image:url(../flags/1x1/bb.svg)}.flag-icon-bd{background-image:url(../flags/4x3/bd.svg)}.flag-icon-bd.flag-icon-squared{background-image:url(../flags/1x1/bd.svg)}.flag-icon-be{background-image:url(../flags/4x3/be.svg)}.flag-icon-be.flag-icon-squared{background-image:url(../flags/1x1/be.svg)}.flag-icon-bf{background-image:url(../flags/4x3/bf.svg)}.flag-icon-bf.flag-icon-squared{background-image:url(../flags/1x1/bf.svg)}.flag-icon-bg{background-image:url(../flags/4x3/bg.svg)}.flag-icon-bg.flag-icon-squared{background-image:url(../flags/1x1/bg.svg)}.flag-icon-bh{background-image:url(../flags/4x3/bh.svg)}.flag-icon-bh.flag-icon-squared{background-image:url(../flags/1x1/bh.svg)}.flag-icon-bi{background-image:url(../flags/4x3/bi.svg)}.flag-icon-bi.flag-icon-squared{background-image:url(../flags/1x1/bi.svg)}.flag-icon-bj{background-image:url(../flags/4x3/bj.svg)}.flag-icon-bj.flag-icon-squared{background-image:url(../flags/1x1/bj.svg)}.flag-icon-bl{background-image:url(../flags/4x3/bl.svg)}.flag-icon-bl.flag-icon-squared{background-image:url(../flags/1x1/bl.svg)}.flag-icon-bm{background-image:url(../flags/4x3/bm.svg)}.flag-icon-bm.flag-icon-squared{background-image:url(../flags/1x1/bm.svg)}.flag-icon-bn{background-image:url(../flags/4x3/bn.svg)}.flag-icon-bn.flag-icon-squared{background-image:url(../flags/1x1/bn.svg)}.flag-icon-bo{background-image:url(../flags/4x3/bo.svg)}.flag-icon-bo.flag-icon-squared{background-image:url(../flags/1x1/bo.svg)}.flag-icon-bq{background-image:url(../flags/4x3/bq.svg)}.flag-icon-bq.flag-icon-squared{background-image:url(../flags/1x1/bq.svg)}.flag-icon-br{background-image:url(../flags/4x3/br.svg)}.flag-icon-br.flag-icon-squared{background-image:url(../flags/1x1/br.svg)}.flag-icon-bs{background-image:url(../flags/4x3/bs.svg)}.flag-icon-bs.flag-icon-squared{background-image:url(../flags/1x1/bs.svg)}.flag-icon-bt{background-image:url(../flags/4x3/bt.svg)}.flag-icon-bt.flag-icon-squared{background-image:url(../flags/1x1/bt.svg)}.flag-icon-bv{background-image:url(../flags/4x3/bv.svg)}.flag-icon-bv.flag-icon-squared{background-image:url(../flags/1x1/bv.svg)}.flag-icon-bw{background-image:url(../flags/4x3/bw.svg)}.flag-icon-bw.flag-icon-squared{background-image:url(../flags/1x1/bw.svg)}.flag-icon-by{background-image:url(../flags/4x3/by.svg)}.flag-icon-by.flag-icon-squared{background-image:url(../flagsLine truncated
|
.flag-icon-background{background-size:contain;background-position:50%;background-repeat:no-repeat}.flag-icon{background-size:contain;background-position:50%;background-repeat:no-repeat;position:relative;display:inline-block;width:1.33333333em;line-height:1em}.flag-icon:before{content:'\00a0'}.flag-icon.flag-icon-squared{width:1em}.flag-icon-ad{background-image:url(../flags/4x3/ad.svg)}.flag-icon-ad.flag-icon-squared{background-image:url(../flags/1x1/ad.svg)}.flag-icon-ae{background-image:url(../flags/4x3/ae.svg)}.flag-icon-ae.flag-icon-squared{background-image:url(../flags/1x1/ae.svg)}.flag-icon-af{background-image:url(../flags/4x3/af.svg)}.flag-icon-af.flag-icon-squared{background-image:url(../flags/1x1/af.svg)}.flag-icon-ag{background-image:url(../flags/4x3/ag.svg)}.flag-icon-ag.flag-icon-squared{background-image:url(../flags/1x1/ag.svg)}.flag-icon-ai{background-image:url(../flags/4x3/ai.svg)}.flag-icon-ai.flag-icon-squared{background-image:url(../flags/1x1/ai.svg)}.flag-icon-al{background-image:url(../flags/4x3/al.svg)}.flag-icon-al.flag-icon-squared{background-image:url(../flags/1x1/al.svg)}.flag-icon-am{background-image:url(../flags/4x3/am.svg)}.flag-icon-am.flag-icon-squared{background-image:url(../flags/1x1/am.svg)}.flag-icon-ao{background-image:url(../flags/4x3/ao.svg)}.flag-icon-ao.flag-icon-squared{background-image:url(../flags/1x1/ao.svg)}.flag-icon-aq{background-image:url(../flags/4x3/aq.svg)}.flag-icon-aq.flag-icon-squared{background-image:url(../flags/1x1/aq.svg)}.flag-icon-ar{background-image:url(../flags/4x3/ar.svg)}.flag-icon-ar.flag-icon-squared{background-image:url(../flags/1x1/ar.svg)}.flag-icon-as{background-image:url(../flags/4x3/as.svg)}.flag-icon-as.flag-icon-squared{background-image:url(../flags/1x1/as.svg)}.flag-icon-at{background-image:url(../flags/4x3/at.svg)}.flag-icon-at.flag-icon-squared{background-image:url(../flags/1x1/at.svg)}.flag-icon-au{background-image:url(../flags/4x3/au.svg)}.flag-icon-au.flag-icon-squared{background-image:url(../flags/1x1/au.svg)}.flag-icon-aw{background-image:url(../flags/4x3/aw.svg)}.flag-icon-aw.flag-icon-squared{background-image:url(../flags/1x1/aw.svg)}.flag-icon-ax{background-image:url(../flags/4x3/ax.svg)}.flag-icon-ax.flag-icon-squared{background-image:url(../flags/1x1/ax.svg)}.flag-icon-az{background-image:url(../flags/4x3/az.svg)}.flag-icon-az.flag-icon-squared{background-image:url(../flags/1x1/az.svg)}.flag-icon-ba{background-image:url(../flags/4x3/ba.svg)}.flag-icon-ba.flag-icon-squared{background-image:url(../flags/1x1/ba.svg)}.flag-icon-bb{background-image:url(../flags/4x3/bb.svg)}.flag-icon-bb.flag-icon-squared{background-image:url(../flags/1x1/bb.svg)}.flag-icon-bd{background-image:url(../flags/4x3/bd.svg)}.flag-icon-bd.flag-icon-squared{background-image:url(../flags/1x1/bd.svg)}.flag-icon-be{background-image:url(../flags/4x3/be.svg)}.flag-icon-be.flag-icon-squared{background-image:url(../flags/1x1/be.svg)}.flag-icon-bf{background-image:url(../flags/4x3/bf.svg)}.flag-icon-bf.flag-icon-squared{background-image:url(../flags/1x1/bf.svg)}.flag-icon-bg{background-image:url(../flags/4x3/bg.svg)}.flag-icon-bg.flag-icon-squared{background-image:url(../flags/1x1/bg.svg)}.flag-icon-bh{background-image:url(../flags/4x3/bh.svg)}.flag-icon-bh.flag-icon-squared{background-image:url(../flags/1x1/bh.svg)}.flag-icon-bi{background-image:url(../flags/4x3/bi.svg)}.flag-icon-bi.flag-icon-squared{background-image:url(../flags/1x1/bi.svg)}.flag-icon-bj{background-image:url(../flags/4x3/bj.svg)}.flag-icon-bj.flag-icon-squared{background-image:url(../flags/1x1/bj.svg)}.flag-icon-bl{background-image:url(../flags/4x3/bl.svg)}.flag-icon-bl.flag-icon-squared{background-image:url(../flags/1x1/bl.svg)}.flag-icon-bm{background-image:url(../flags/4x3/bm.svg)}.flag-icon-bm.flag-icon-squared{background-image:url(../flags/1x1/bm.svg)}.flag-icon-bn{background-image:url(../flags/4x3/bn.svg)}.flag-icon-bn.flag-icon-squared{background-image:url(../flags/1x1/bn.svg)}.flag-icon-bo{background-image:url(../flags/4x3/bo.svg)}.flag-icon-bo.flag-icon-squared{background-image:url(../flags/1x1/bo.svg)}.flag-icon-bq{background-image:url(../flags/4x3/bq.svg)}.flag-icon-bq.flag-icon-squared{background-image:url(../flags/1x1/bq.svg)}.flag-icon-br{background-image:url(../flags/4x3/br.svg)}.flag-icon-br.flag-icon-squared{background-image:url(../flags/1x1/br.svg)}.flag-icon-bs{background-image:url(../flags/4x3/bs.svg)}.flag-icon-bs.flag-icon-squared{background-image:url(../flags/1x1/bs.svg)}.flag-icon-bt{background-image:url(../flags/4x3/bt.svg)}.flag-icon-bt.flag-icon-squared{background-image:url(../flags/1x1/bt.svg)}.flag-icon-bv{background-image:url(../flags/4x3/bv.svg)}.flag-icon-bv.flag-icon-squared{background-image:url(../flags/1x1/bv.svg)}.flag-icon-bw{background-image:url(../flags/4x3/bw.svg)}.flag-icon-bw.flag-icon-squared{background-image:url(../flags/1x1/bw.svg)}.flag-icon-by{background-image:url(../flags/4x3/by.svg)}.flag-icon-by.flag-icon-squared{background-image:url(../flagsLine truncated
|
||||||
File renamed without changes.
Vendored
File renamed without changes.
Vendored
File renamed without changes.
@@ -0,0 +1,687 @@
|
|||||||
|
/*
|
||||||
|
* 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.13.1/r-2.4.0/sl-1.5.0
|
||||||
|
*
|
||||||
|
* Included libraries:
|
||||||
|
* DataTables 1.13.1, Responsive 2.4.0, Select 1.5.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.8em;
|
||||||
|
}
|
||||||
|
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 > tbody > tr.selected a {
|
||||||
|
color: #090a0b;
|
||||||
|
}
|
||||||
|
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_wrapper div.dt-row {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.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 > tr > td.select-checkbox,
|
||||||
|
table.dataTable > tbody > tr > th.select-checkbox {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
table.dataTable > tbody > tr > td.select-checkbox:before, table.dataTable > tbody > tr > td.select-checkbox:after,
|
||||||
|
table.dataTable > tbody > tr > th.select-checkbox:before,
|
||||||
|
table.dataTable > tbody > tr > th.select-checkbox:after {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: 1.2em;
|
||||||
|
left: 50%;
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
table.dataTable > tbody > tr > td.select-checkbox:before,
|
||||||
|
table.dataTable > tbody > tr > th.select-checkbox:before {
|
||||||
|
content: " ";
|
||||||
|
margin-top: -5px;
|
||||||
|
margin-left: -6px;
|
||||||
|
border: 1px solid black;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
table.dataTable > tbody > tr.selected > td.select-checkbox:before,
|
||||||
|
table.dataTable > tbody > tr.selected > th.select-checkbox:before {
|
||||||
|
border: 1px solid white;
|
||||||
|
}
|
||||||
|
table.dataTable > tbody > tr.selected > td.select-checkbox:after,
|
||||||
|
table.dataTable > tbody > 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 > tr > td.select-checkbox:before,
|
||||||
|
table.dataTable.compact > tbody > tr > th.select-checkbox:before {
|
||||||
|
margin-top: -12px;
|
||||||
|
}
|
||||||
|
table.dataTable.compact > tbody > tr.selected > td.select-checkbox:after,
|
||||||
|
table.dataTable.compact > tbody > 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"; }
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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,7 @@ legend {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
.footer .version {
|
.footer .version {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
.slave-info {
|
.slave-info {
|
||||||
@@ -225,15 +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;
|
|
||||||
}
|
|
||||||
table>tbody>tr>td>span.footable-toggle {
|
|
||||||
opacity: 0.75;
|
|
||||||
}
|
}
|
||||||
.navbar-nav > li {
|
.navbar-nav > li {
|
||||||
font-size: 1rem !important;
|
font-size: 1rem !important;
|
||||||
@@ -260,18 +271,11 @@ code {
|
|||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-group-item.webauthn-authenticator-selection,
|
.dropdown-header {
|
||||||
.list-group-item.totp-authenticator-selection,
|
font-weight: 600;
|
||||||
.list-group-item.yubi_otp-authenticator-selection {
|
|
||||||
border-radius: 0px !important;
|
|
||||||
}
|
|
||||||
.pending-tfa-collapse {
|
|
||||||
padding: 10px;
|
|
||||||
background: #fbfbfb;
|
|
||||||
border: 1px solid #ededed;
|
|
||||||
min-height: 110px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.tag-box {
|
.tag-box {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
@@ -295,7 +299,7 @@ code {
|
|||||||
}
|
}
|
||||||
.tag-input {
|
.tag-input {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
border: 0;
|
border: 0 !important;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
min-width: 150px;
|
min-width: 150px;
|
||||||
@@ -308,3 +312,72 @@ code {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
display: inline-flex;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
div.dataTables_wrapper div.dataTables_filter {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
div.dataTables_wrapper div.dataTables_length {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.dataTables_paginate, .dataTables_length, .dataTables_filter {
|
||||||
|
margin: 10px 0!important;
|
||||||
|
}
|
||||||
@@ -1,308 +0,0 @@
|
|||||||
.space20 {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-xs-lg>.lang-sm:after {
|
|
||||||
margin-left: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bootstrap-select {
|
|
||||||
max-width: 350px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.panel-login .apps .btn {
|
|
||||||
width: auto;
|
|
||||||
float: left;
|
|
||||||
margin-right: 10px;
|
|
||||||
margin-top: auto;
|
|
||||||
}
|
|
||||||
.panel-login .apps .btn:hover {
|
|
||||||
margin-top: 1px !important;
|
|
||||||
border-bottom-width: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 767px) {
|
|
||||||
.panel-login .apps .btn {
|
|
||||||
width: 100%;
|
|
||||||
float: none;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.panel-login .apps .btn {
|
|
||||||
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 {
|
|
||||||
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 {
|
|
||||||
font-size: 14px;
|
|
||||||
margin-top: 10px !important;
|
|
||||||
}
|
|
||||||
.pull-xs-right {
|
|
||||||
float: right !important;
|
|
||||||
}
|
|
||||||
.pull-xs-right .dropdown-menu {
|
|
||||||
right: 0;
|
|
||||||
left: auto;
|
|
||||||
}
|
|
||||||
.text-xs-left {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
.text-xs-bold {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
.text-xs-bold .small {
|
|
||||||
font-weight: normal;
|
|
||||||
text-align: justify;
|
|
||||||
}
|
|
||||||
.help-block {
|
|
||||||
text-align: justify;
|
|
||||||
}
|
|
||||||
.btn.visible-xs-block {
|
|
||||||
width: 100%;
|
|
||||||
float: none;
|
|
||||||
white-space: normal;
|
|
||||||
}
|
|
||||||
.btn-group.footable-actions .btn.btn-xs-half,
|
|
||||||
.btn.visible-xs-block.btn-xs-half {
|
|
||||||
width: 50%;
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
.btn-group.footable-actions .btn.btn-xs-third,
|
|
||||||
.btn.visible-xs-block.btn-xs-third {
|
|
||||||
width: 33.33%;
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
.btn-group.footable-actions .btn.btn-xs-quart,
|
|
||||||
.btn.visible-xs-block.btn-xs-quart {
|
|
||||||
width: 25%;
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
.btn.visible-xs-block.btn-sm,
|
|
||||||
.btn-xs-lg {
|
|
||||||
padding: 15px 16px 13px;
|
|
||||||
line-height: 15px;
|
|
||||||
}
|
|
||||||
.input-xs-lg {
|
|
||||||
height: 47px;
|
|
||||||
padding: 13px 16px;
|
|
||||||
}
|
|
||||||
.btn-group:not(.input-group-btn) {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
.btn-group.nowrap {
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
}
|
|
||||||
.btn-group.nowrap .dropdown-menu {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.panel-login .btn-group {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
.mass-actions-user .btn-group {
|
|
||||||
float: none;
|
|
||||||
}
|
|
||||||
div[class^='mass-actions'] .dropdown-menu,
|
|
||||||
.panel-xs-lg .dropdown-menu,
|
|
||||||
.dropdown-menu.login {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
div[class^='mass-actions'] .btn-group .dropdown-menu {
|
|
||||||
top: 50%;
|
|
||||||
}
|
|
||||||
div[class^='mass-actions'] .btn-group .btn-group .dropdown-menu,
|
|
||||||
div.mass-actions-quarantine .btn-group .dropdown-menu,
|
|
||||||
.panel-xs-lg .dropdown-menu {
|
|
||||||
top: 100%;
|
|
||||||
}
|
|
||||||
div[class^='mass-actions'] .dropdown-menu>li>a,
|
|
||||||
.panel-xs-lg .dropdown-menu>li>a,
|
|
||||||
.dropdown-menu.login>li>a {
|
|
||||||
padding: 8px 20px;
|
|
||||||
}
|
|
||||||
div[class^='mass-actions'] .dropdown-header {
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
.space20 {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
.top100 {
|
|
||||||
top: 100% !important;
|
|
||||||
}
|
|
||||||
.top33 {
|
|
||||||
top: 33% !important;
|
|
||||||
}
|
|
||||||
.footable-filtering .form {
|
|
||||||
width: 65%;
|
|
||||||
}
|
|
||||||
.btn-xs-lg>.lang-sm:after {
|
|
||||||
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 {
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
tr.footable-filtering>th>form {
|
|
||||||
width: 270px;
|
|
||||||
}
|
|
||||||
.mass-actions-mailbox {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
.panel-xs-lg .panel-heading {
|
|
||||||
height: 66px;
|
|
||||||
line-height: 47px;
|
|
||||||
}
|
|
||||||
.panel-xs-lg .btn-group .btn {
|
|
||||||
padding-right: 5px;
|
|
||||||
padding-left: 5px;
|
|
||||||
}
|
|
||||||
.bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn) {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.btn-group:not(.bootstrap-select) {
|
|
||||||
width: auto !important;
|
|
||||||
}
|
|
||||||
.bootstrap-select {
|
|
||||||
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 {
|
|
||||||
margin-right: 14px;
|
|
||||||
white-space: normal;
|
|
||||||
}
|
|
||||||
.clearfix {
|
|
||||||
flex-basis: 100%;
|
|
||||||
height: 0;
|
|
||||||
}
|
|
||||||
.btn-group > .btn-group {
|
|
||||||
flex-basis: 100%;
|
|
||||||
}
|
|
||||||
.btn-group .btn {
|
|
||||||
display: flex !important;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
.btn-group .btn i {
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
.btn-group .btn .caret {
|
|
||||||
margin-left: 5px;
|
|
||||||
}
|
|
||||||
.panel-login .btn-group .btn {
|
|
||||||
display: block !important;
|
|
||||||
}
|
|
||||||
.panel-login .clearfix {
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 350px) {
|
|
||||||
.mailcow-logo img {
|
|
||||||
max-width: 250px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,218 @@
|
|||||||
|
.btn-xs-lg>.lang-sm:after {
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bootstrap-select {
|
||||||
|
max-width: 350px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-login .apps .btn {
|
||||||
|
width: auto;
|
||||||
|
float: left;
|
||||||
|
margin-right: 10px;
|
||||||
|
margin-top: auto;
|
||||||
|
}
|
||||||
|
.card-login .apps .btn:hover {
|
||||||
|
margin-top: 1px !important;
|
||||||
|
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) {
|
||||||
|
.responsive-tabs .tab-pane {
|
||||||
|
display: block !important;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-login .apps .btn {
|
||||||
|
width: 100%;
|
||||||
|
float: none;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-login .apps .btn {
|
||||||
|
border-bottom-width: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xs-show {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.recent-login-success {
|
||||||
|
font-size: 14px;
|
||||||
|
margin-top: 10px !important;
|
||||||
|
}
|
||||||
|
.pull-xs-right {
|
||||||
|
float: right !important;
|
||||||
|
}
|
||||||
|
.pull-xs-right .dropdown-menu {
|
||||||
|
right: 0;
|
||||||
|
left: auto;
|
||||||
|
}
|
||||||
|
.text-xs-left {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.text-xs-bold {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.text-xs-bold .small {
|
||||||
|
font-weight: normal;
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
|
.btn.d-block {
|
||||||
|
width: 100%;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
.btn.btn-xs-half,
|
||||||
|
.btn.d-block.btn-xs-half {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
.btn.btn-xs-third,
|
||||||
|
.btn.d-block.btn-xs-third {
|
||||||
|
width: 33.33%;
|
||||||
|
}
|
||||||
|
.btn.btn-xs-quart,
|
||||||
|
.btn.d-block.btn-xs-quart {
|
||||||
|
width: 25%;
|
||||||
|
}
|
||||||
|
.btn.d-block.btn-sm,
|
||||||
|
.btn-xs-lg {
|
||||||
|
padding: .5rem 1rem;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
.input-xs-lg {
|
||||||
|
height: 47px;
|
||||||
|
padding: 13px 16px;
|
||||||
|
}
|
||||||
|
.btn-group:not(.input-group-btn) {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.btn-group.nowrap {
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
}
|
||||||
|
.btn-group.nowrap .dropdown-menu {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.card-login .btn-group {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.mass-actions-user .btn-group {
|
||||||
|
float: none;
|
||||||
|
}
|
||||||
|
div[class^='mass-actions'] .dropdown-menu,
|
||||||
|
.card-xs-lg .dropdown-menu,
|
||||||
|
.dropdown-menu.login {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
div[class^='mass-actions'] .btn-group .dropdown-menu {
|
||||||
|
top: 50%;
|
||||||
|
}
|
||||||
|
div[class^='mass-actions'] .btn-group .btn-group .dropdown-menu,
|
||||||
|
div.mass-actions-quarantine .btn-group .dropdown-menu,
|
||||||
|
.card-xs-lg .dropdown-menu {
|
||||||
|
top: 100%;
|
||||||
|
}
|
||||||
|
div[class^='mass-actions'] .dropdown-menu>li>a,
|
||||||
|
.card-xs-lg .dropdown-menu>li>a,
|
||||||
|
.dropdown-menu.login>li>a {
|
||||||
|
padding: 8px 20px;
|
||||||
|
}
|
||||||
|
div[class^='mass-actions'] .dropdown-header {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.top100 {
|
||||||
|
top: 100% !important;
|
||||||
|
}
|
||||||
|
.top33 {
|
||||||
|
top: 33% !important;
|
||||||
|
}
|
||||||
|
.footable-filtering .form {
|
||||||
|
width: 65%;
|
||||||
|
}
|
||||||
|
.btn-xs-lg>.lang-sm:after {
|
||||||
|
top: 1px;
|
||||||
|
}
|
||||||
|
.pagination {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
.mass-actions-mailbox {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.card-xs-lg .card-header {
|
||||||
|
height: 66px;
|
||||||
|
line-height: 47px;
|
||||||
|
}
|
||||||
|
.card-xs-lg .btn-group .btn {
|
||||||
|
padding-right: 5px;
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
.bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.btn-group:not(.bootstrap-select) {
|
||||||
|
width: auto !important;
|
||||||
|
}
|
||||||
|
.bootstrap-select {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
.bootstrap-select.btn-group.show-tick .dropdown-menu li a span.text {
|
||||||
|
margin-right: 14px;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
.btn-group > .btn-group {
|
||||||
|
flex-basis: 100%;
|
||||||
|
}
|
||||||
|
.btn-group .btn {
|
||||||
|
display: flex !important;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.btn-group .btn i {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
.card-login .btn-group .btn {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dt-sm-head-hidden .dtr-title {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.dataTables_wrapper div.dataTables_length {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 350px) {
|
||||||
|
.mailcow-logo img {
|
||||||
|
max-width: 250px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1400px) {
|
||||||
|
.container-xxl, .container-xl, .container-lg, .container-md, .container-sm, .container {
|
||||||
|
max-width: 1600px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 {
|
||||||
|
|||||||
@@ -21,7 +21,6 @@
|
|||||||
}
|
}
|
||||||
.mass-actions-user {
|
.mass-actions-user {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
padding:10px 0;
|
|
||||||
}
|
}
|
||||||
.inputMissingAttr {
|
.inputMissingAttr {
|
||||||
border-color: #FF4136;
|
border-color: #FF4136;
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,368 @@
|
|||||||
|
body {
|
||||||
|
background-color: #414141;
|
||||||
|
color: #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
border: 1px solid #1c1c1c;
|
||||||
|
background-color: #3a3a3a;
|
||||||
|
}
|
||||||
|
legend {
|
||||||
|
color: #f5f5f5;
|
||||||
|
}
|
||||||
|
.card-header {
|
||||||
|
color: #bbb;
|
||||||
|
background-color: #2c2c2c;
|
||||||
|
border-color: transparent;
|
||||||
|
}
|
||||||
|
.btn-secondary, .paginate_button, .page-link, .btn-light {
|
||||||
|
color: #fff !important;
|
||||||
|
background-color: #7a7a7a !important;
|
||||||
|
border-color: #5c5c5c !important;
|
||||||
|
}
|
||||||
|
.btn-check:checked+.btn-secondary, .btn-check:active+.btn-secondary, .btn-secondary:active, .btn-secondary.active, .show>.btn-secondary.dropdown-toggle {
|
||||||
|
border-color: #7a7a7a !important;
|
||||||
|
}
|
||||||
|
.alert-secondary {
|
||||||
|
color: #fff !important;
|
||||||
|
background-color: #7a7a7a !important;
|
||||||
|
border-color: #5c5c5c !important;
|
||||||
|
}
|
||||||
|
.bg-secondary {
|
||||||
|
color: #fff !important;
|
||||||
|
background-color: #7a7a7a !important;
|
||||||
|
}
|
||||||
|
.alert-secondary, .alert-secondary a, .alert-secondary .alert-link {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.page-item.active .page-link {
|
||||||
|
background-color: #158cba !important;
|
||||||
|
border-color: #127ba3 !important;
|
||||||
|
}
|
||||||
|
.btn-secondary:focus, .btn-secondary:hover, .btn-group.open .dropdown-toggle.btn-secondary {
|
||||||
|
background-color: #7a7a7a;
|
||||||
|
border-color: #5c5c5c !important;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.btn-secondary:disabled, .btn-secondary.disabled {
|
||||||
|
border-color: #7a7a7a !important;
|
||||||
|
}
|
||||||
|
.modal-content {
|
||||||
|
background-color: #414141;
|
||||||
|
}
|
||||||
|
.modal-header {
|
||||||
|
border-bottom: 1px solid #161616;
|
||||||
|
}
|
||||||
|
.modal-title {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.modal .btn-close {
|
||||||
|
filter: invert(1) grayscale(100%) brightness(200%);
|
||||||
|
}
|
||||||
|
.navbar.bg-light {
|
||||||
|
background-color: #222222 !important;
|
||||||
|
border-color: #181818;
|
||||||
|
}
|
||||||
|
.nav-link {
|
||||||
|
color: #ccc !important;
|
||||||
|
}
|
||||||
|
.nav-tabs .nav-link.active, .nav-tabs .nav-item.show .nav-link {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
.nav-tabs .nav-link:not(.disabled):hover, .nav-tabs .nav-link:not(.disabled):focus, .nav-tabs .nav-link.active {
|
||||||
|
border-bottom-color: #414141;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table, .table-striped>tbody>tr:nth-of-type(odd)>*, tbody tr {
|
||||||
|
color: #ccc !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-menu {
|
||||||
|
background-color: #585858;
|
||||||
|
border: 1px solid #333;
|
||||||
|
}
|
||||||
|
.dropdown-menu>li>a:focus, .dropdown-menu>li>a:hover {
|
||||||
|
color: #fafafa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bootstrap-select>.dropdown-toggle.bs-placeholder, .bootstrap-select>.dropdown-toggle.bs-placeholder:active, .bootstrap-select>.dropdown-toggle.bs-placeholder:focus, .bootstrap-select>.dropdown-toggle.bs-placeholder:hover {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.bootstrap-select>.dropdown-toggle.bs-placeholder, .bootstrap-select>.dropdown-toggle.bs-placeholder.btn-secondary {
|
||||||
|
color: #d4d4d4 !important;
|
||||||
|
}
|
||||||
|
tbody tr {
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
.navbar-default .navbar-nav>.open>a, .navbar-default .navbar-nav>.open>a:focus, .navbar-default .navbar-nav>.open>a:hover {
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
.navbar-default .navbar-nav>.active>a, .navbar-default .navbar-nav>.active>a:focus, .navbar-default .navbar-nav>.active>a:hover {
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
.list-group-item {
|
||||||
|
background-color: #333;
|
||||||
|
border: 1px solid #555;
|
||||||
|
}
|
||||||
|
.table-striped>tbody>tr:nth-of-type(odd) {
|
||||||
|
background-color: #333;
|
||||||
|
}
|
||||||
|
table.dataTable>tbody>tr.child ul.dtr-details>li {
|
||||||
|
border-bottom: 1px solid rgba(255, 255, 255, 0.13);
|
||||||
|
}
|
||||||
|
tbody tr {
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
.label.label-last-login {
|
||||||
|
color: #ccc !important;
|
||||||
|
background-color: #555 !important;
|
||||||
|
}
|
||||||
|
.progress {
|
||||||
|
background-color: #555;
|
||||||
|
}
|
||||||
|
.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
div.numberedtextarea-number {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
.well {
|
||||||
|
border: 1px solid #555;
|
||||||
|
background-color: #333;
|
||||||
|
}
|
||||||
|
pre {
|
||||||
|
color: #ccc;
|
||||||
|
background-color: #333;
|
||||||
|
border: 1px solid #555;
|
||||||
|
}
|
||||||
|
input.form-control, textarea.form-control {
|
||||||
|
color: #e2e2e2 !important;
|
||||||
|
background-color: #555 !important;
|
||||||
|
border: 1px solid #999;
|
||||||
|
}
|
||||||
|
input.form-control:focus, textarea.form-control {
|
||||||
|
background-color: #555 !important;
|
||||||
|
}
|
||||||
|
input.form-control:disabled, textarea.form-disabled {
|
||||||
|
color: #a8a8a8 !important;
|
||||||
|
background-color: #6e6e6e !important;
|
||||||
|
}
|
||||||
|
.input-group-addon {
|
||||||
|
color: #ccc;
|
||||||
|
background-color: #555 !important;
|
||||||
|
border: 1px solid #999;
|
||||||
|
}
|
||||||
|
.input-group-text {
|
||||||
|
color: #ccc;
|
||||||
|
background-color: #242424;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.list-group-item {
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
.dropdown-item {
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
.dropdown-item:hover {
|
||||||
|
color: #616161 !important;
|
||||||
|
}
|
||||||
|
.dropdown-item.active:hover {
|
||||||
|
color: #fff !important;
|
||||||
|
background-color: #31b1e4;
|
||||||
|
}
|
||||||
|
.form-select {
|
||||||
|
color: #e2e2e2!important;
|
||||||
|
background-color: #555!important;
|
||||||
|
border: 1px solid #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.responsive-tabs .card-header button[data-bs-toggle="collapse"] {
|
||||||
|
color: #c7c7c7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-toggler {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.table-secondary {
|
||||||
|
--bs-table-bg: #7a7a7a;
|
||||||
|
--bs-table-striped-bg: #e4e4e4;
|
||||||
|
--bs-table-striped-color: #000;
|
||||||
|
--bs-table-active-bg: #d8d8d8;
|
||||||
|
--bs-table-active-color: #000;
|
||||||
|
--bs-table-hover-bg: #dedede;
|
||||||
|
--bs-table-hover-color: #000;
|
||||||
|
color: #000;
|
||||||
|
border-color: #d8d8d8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-light {
|
||||||
|
--bs-table-bg: #f6f6f6;
|
||||||
|
--bs-table-striped-bg: #eaeaea;
|
||||||
|
--bs-table-striped-color: #000;
|
||||||
|
--bs-table-active-bg: #dddddd;
|
||||||
|
--bs-table-active-color: #000;
|
||||||
|
--bs-table-hover-bg: #e4e4e4;
|
||||||
|
--bs-table-hover-color: #000;
|
||||||
|
color: #000;
|
||||||
|
border-color: #dddddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control-plaintext {
|
||||||
|
color: #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.breadcrumb {
|
||||||
|
color: #fff !important;
|
||||||
|
background-color: #7a7a7a !important;
|
||||||
|
border-color: #5c5c5c !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #6fc7e9;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
color: #3daedb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.breadcrumb-item.active {
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.list-group-item.disabled, .list-group-item:disabled {
|
||||||
|
color: #fff;
|
||||||
|
background-color: #a8a8a8 !important;
|
||||||
|
border-color: #a8a8a8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card.bg-light .card-title {
|
||||||
|
color: #000 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card.bg-light .card-text {
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.accordion-item {
|
||||||
|
background-color: #3a3a3a;
|
||||||
|
}
|
||||||
|
.accordion-button {
|
||||||
|
color: #bbb;
|
||||||
|
background-color: #2c2c2c;
|
||||||
|
}
|
||||||
|
.accordion-button:not(.collapsed) {
|
||||||
|
color: #6fc7e9;
|
||||||
|
background-color: #2c2c2c;
|
||||||
|
}
|
||||||
|
.accordion-button::after {
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
.accordion-button:not(.collapsed)::after {
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.toast-header {
|
||||||
|
background-color: #4c4c4c;
|
||||||
|
}
|
||||||
|
.toast-body {
|
||||||
|
background-color: #626262;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-pills .nav-link.active, .nav-pills .show > .nav-link {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag-box {
|
||||||
|
background-color: #555;
|
||||||
|
border: 1px solid #999;
|
||||||
|
}
|
||||||
|
.tag-input {
|
||||||
|
color: #fff;
|
||||||
|
background-color: #555;
|
||||||
|
}
|
||||||
|
.tag-add {
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
.tag-add:hover {
|
||||||
|
color: #d1d1d1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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: #7a7a7a !important;
|
||||||
|
}
|
||||||
|
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dtr-control:before,
|
||||||
|
table.dataTable.dtr-inline.collapsed>tbody>tr>th.dtr-control:before {
|
||||||
|
background-color: #7a7a7a !important;
|
||||||
|
border: 1.5px solid #5c5c5c !important;
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
table.dataTable.dtr-inline.collapsed>tbody>tr.parent>td.dtr-control:before,
|
||||||
|
table.dataTable.dtr-inline.collapsed>tbody>tr.parent>th.dtr-control:before {
|
||||||
|
background-color: #949494;
|
||||||
|
}
|
||||||
|
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: #444444;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-check-label {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.btn-outline-secondary:hover {
|
||||||
|
background-color: #c3c3c3;
|
||||||
|
}
|
||||||
|
.btn.btn-outline-secondary {
|
||||||
|
color: #fff !important;
|
||||||
|
border-color: #7a7a7a !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: #9b9b9b !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.btn-input-missing,
|
||||||
|
.btn-input-missing:hover,
|
||||||
|
.btn-input-missing:active,
|
||||||
|
.btn-input-missing:focus,
|
||||||
|
.btn-input-missing:active:hover,
|
||||||
|
.btn-input-missing:active:focus {
|
||||||
|
color: #fff !important;
|
||||||
|
background-color: #ff2f24 !important;
|
||||||
|
border-color: #e21207 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inputMissingAttr {
|
||||||
|
border-color: #FF4136 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.list-group-details {
|
||||||
|
background: #444444;
|
||||||
|
}
|
||||||
|
.list-group-header {
|
||||||
|
background: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.mail-address-item {
|
||||||
|
background-color: #333;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid #555;
|
||||||
|
padding: 2px 7px;
|
||||||
|
display: inline-block;
|
||||||
|
margin: 2px 6px 2px 0;
|
||||||
|
}
|
||||||
@@ -11,6 +11,11 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
|
|||||||
$solr_status = (preg_match("/^([yY][eE][sS]|[yY])+$/", $_ENV["SKIP_SOLR"])) ? false : solr_status();
|
$solr_status = (preg_match("/^([yY][eE][sS]|[yY])+$/", $_ENV["SKIP_SOLR"])) ? false : solr_status();
|
||||||
$clamd_status = (preg_match("/^([yY][eE][sS]|[yY])+$/", $_ENV["SKIP_CLAMD"])) ? false : true;
|
$clamd_status = (preg_match("/^([yY][eE][sS]|[yY])+$/", $_ENV["SKIP_CLAMD"])) ? false : true;
|
||||||
|
|
||||||
|
|
||||||
|
if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CACHE')) {
|
||||||
|
$_SESSION['gal'] = json_decode($license_cache, true);
|
||||||
|
}
|
||||||
|
|
||||||
$js_minifier->add('/web/js/site/debug.js');
|
$js_minifier->add('/web/js/site/debug.js');
|
||||||
|
|
||||||
// vmail df
|
// vmail df
|
||||||
@@ -44,15 +49,26 @@ foreach ($containers as $container => $container_info) {
|
|||||||
$containers[$container]['State']['StartedAtHR'] = $started;
|
$containers[$container]['State']['StartedAtHR'] = $started;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get mailcow data
|
||||||
|
$hostname = getenv('MAILCOW_HOSTNAME');
|
||||||
|
$timezone = getenv('TZ');
|
||||||
|
|
||||||
$template = 'debug.twig';
|
$template = 'debug.twig';
|
||||||
$template_data = [
|
$template_data = [
|
||||||
'log_lines' => getenv('LOG_LINES'),
|
'log_lines' => getenv('LOG_LINES'),
|
||||||
'vmail_df' => $vmail_df,
|
'vmail_df' => $vmail_df,
|
||||||
|
'hostname' => $hostname,
|
||||||
|
'timezone' => $timezone,
|
||||||
|
'gal' => @$_SESSION['gal'],
|
||||||
|
'license_guid' => license('guid'),
|
||||||
'solr_status' => $solr_status,
|
'solr_status' => $solr_status,
|
||||||
'solr_uptime' => round($solr_status['status']['dovecot-fts']['uptime'] / 1000 / 60 / 60),
|
'solr_uptime' => round($solr_status['status']['dovecot-fts']['uptime'] / 1000 / 60 / 60),
|
||||||
'clamd_status' => $clamd_status,
|
'clamd_status' => $clamd_status,
|
||||||
'containers' => $containers,
|
'containers' => $containers,
|
||||||
|
'ip_check' => customize('get', 'ip_check'),
|
||||||
'lang_admin' => json_encode($lang['admin']),
|
'lang_admin' => json_encode($lang['admin']),
|
||||||
|
'lang_debug' => json_encode($lang['debug']),
|
||||||
|
'lang_datatables' => json_encode($lang['datatables']),
|
||||||
];
|
];
|
||||||
|
|
||||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/footer.inc.php';
|
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/footer.inc.php';
|
||||||
|
|||||||
+65
-39
@@ -38,24 +38,46 @@ if (isset($_SESSION['mailcow_cc_role'])) {
|
|||||||
$template = 'edit/admin.twig';
|
$template = 'edit/admin.twig';
|
||||||
$template_data = ['admin' => $admin];
|
$template_data = ['admin' => $admin];
|
||||||
}
|
}
|
||||||
elseif (isset($_GET['domain']) &&
|
elseif (isset($_GET['domain'])) {
|
||||||
is_valid_domain_name($_GET["domain"]) &&
|
if (is_valid_domain_name($_GET["domain"]) &&
|
||||||
!empty($_GET["domain"])) {
|
!empty($_GET["domain"])) {
|
||||||
$domain = $_GET["domain"];
|
// edit domain
|
||||||
$result = mailbox('get', 'domain_details', $domain);
|
$domain = $_GET["domain"];
|
||||||
$quota_notification_bcc = quota_notification_bcc('get', $domain);
|
$result = mailbox('get', 'domain_details', $domain);
|
||||||
$rl = ratelimit('get', 'domain', $domain);
|
$quota_notification_bcc = quota_notification_bcc('get', $domain);
|
||||||
$rlyhosts = relayhost('get');
|
$rl = ratelimit('get', 'domain', $domain);
|
||||||
$template = 'edit/domain.twig';
|
$rlyhosts = relayhost('get');
|
||||||
|
$template = 'edit/domain.twig';
|
||||||
|
$template_data = [
|
||||||
|
'acl' => $_SESSION['acl'],
|
||||||
|
'domain' => $domain,
|
||||||
|
'quota_notification_bcc' => $quota_notification_bcc,
|
||||||
|
'rl' => $rl,
|
||||||
|
'rlyhosts' => $rlyhosts,
|
||||||
|
'dkim' => dkim('details', $domain),
|
||||||
|
'domain_details' => $result,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif (isset($_GET["template"])){
|
||||||
|
$domain_template = mailbox('get', 'domain_templates', $_GET["template"]);
|
||||||
|
if ($domain_template){
|
||||||
$template_data = [
|
$template_data = [
|
||||||
'acl' => $_SESSION['acl'],
|
'template' => $domain_template
|
||||||
'domain' => $domain,
|
|
||||||
'quota_notification_bcc' => $quota_notification_bcc,
|
|
||||||
'rl' => $rl,
|
|
||||||
'rlyhosts' => $rlyhosts,
|
|
||||||
'dkim' => dkim('details', $domain),
|
|
||||||
'domain_details' => $result,
|
|
||||||
];
|
];
|
||||||
|
$template = 'edit/domain-templates.twig';
|
||||||
|
$result = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$mailbox_template = mailbox('get', 'mailbox_templates', $_GET["template"]);
|
||||||
|
if ($mailbox_template){
|
||||||
|
$template_data = [
|
||||||
|
'template' => $mailbox_template
|
||||||
|
];
|
||||||
|
$template = 'edit/mailbox-templates.twig';
|
||||||
|
$result = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
elseif (isset($_GET['oauth2client']) &&
|
elseif (isset($_GET['oauth2client']) &&
|
||||||
is_numeric($_GET["oauth2client"]) &&
|
is_numeric($_GET["oauth2client"]) &&
|
||||||
@@ -79,29 +101,32 @@ if (isset($_SESSION['mailcow_cc_role'])) {
|
|||||||
'dkim' => dkim('details', $alias_domain),
|
'dkim' => dkim('details', $alias_domain),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
elseif (isset($_GET['mailbox']) && filter_var(html_entity_decode(rawurldecode($_GET["mailbox"])), FILTER_VALIDATE_EMAIL) && !empty($_GET["mailbox"])) {
|
elseif (isset($_GET['mailbox'])){
|
||||||
$mailbox = html_entity_decode(rawurldecode($_GET["mailbox"]));
|
if(filter_var(html_entity_decode(rawurldecode($_GET["mailbox"])), FILTER_VALIDATE_EMAIL) && !empty($_GET["mailbox"])) {
|
||||||
$result = mailbox('get', 'mailbox_details', $mailbox);
|
// edit mailbox
|
||||||
$rl = ratelimit('get', 'mailbox', $mailbox);
|
$mailbox = html_entity_decode(rawurldecode($_GET["mailbox"]));
|
||||||
$pushover_data = pushover('get', $mailbox);
|
$result = mailbox('get', 'mailbox_details', $mailbox);
|
||||||
$quarantine_notification = mailbox('get', 'quarantine_notification', $mailbox);
|
$rl = ratelimit('get', 'mailbox', $mailbox);
|
||||||
$quarantine_category = mailbox('get', 'quarantine_category', $mailbox);
|
$pushover_data = pushover('get', $mailbox);
|
||||||
$get_tls_policy = mailbox('get', 'tls_policy', $mailbox);
|
$quarantine_notification = mailbox('get', 'quarantine_notification', $mailbox);
|
||||||
$rlyhosts = relayhost('get');
|
$quarantine_category = mailbox('get', 'quarantine_category', $mailbox);
|
||||||
$template = 'edit/mailbox.twig';
|
$get_tls_policy = mailbox('get', 'tls_policy', $mailbox);
|
||||||
$template_data = [
|
$rlyhosts = relayhost('get');
|
||||||
'acl' => $_SESSION['acl'],
|
$template = 'edit/mailbox.twig';
|
||||||
'mailbox' => $mailbox,
|
$template_data = [
|
||||||
'rl' => $rl,
|
'acl' => $_SESSION['acl'],
|
||||||
'pushover_data' => $pushover_data,
|
'mailbox' => $mailbox,
|
||||||
'quarantine_notification' => $quarantine_notification,
|
'rl' => $rl,
|
||||||
'quarantine_category' => $quarantine_category,
|
'pushover_data' => $pushover_data,
|
||||||
'get_tls_policy' => $get_tls_policy,
|
'quarantine_notification' => $quarantine_notification,
|
||||||
'rlyhosts' => $rlyhosts,
|
'quarantine_category' => $quarantine_category,
|
||||||
'sender_acl_handles' => mailbox('get', 'sender_acl_handles', $mailbox),
|
'get_tls_policy' => $get_tls_policy,
|
||||||
'user_acls' => acl('get', 'user', $mailbox),
|
'rlyhosts' => $rlyhosts,
|
||||||
'mailbox_details' => $result
|
'sender_acl_handles' => mailbox('get', 'sender_acl_handles', $mailbox),
|
||||||
];
|
'user_acls' => acl('get', 'user', $mailbox),
|
||||||
|
'mailbox_details' => $result
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
elseif (isset($_GET['relayhost']) && is_numeric($_GET["relayhost"]) && !empty($_GET["relayhost"])) {
|
elseif (isset($_GET['relayhost']) && is_numeric($_GET["relayhost"]) && !empty($_GET["relayhost"])) {
|
||||||
$relayhost = intval($_GET["relayhost"]);
|
$relayhost = intval($_GET["relayhost"]);
|
||||||
@@ -189,5 +214,6 @@ $js_minifier->add('/web/js/site/pwgen.js');
|
|||||||
$template_data['result'] = $result;
|
$template_data['result'] = $result;
|
||||||
$template_data['return_to'] = $_SESSION['return_to'];
|
$template_data['return_to'] = $_SESSION['return_to'];
|
||||||
$template_data['lang_user'] = json_encode($lang['user']);
|
$template_data['lang_user'] = json_encode($lang['user']);
|
||||||
|
$template_data['lang_datatables'] = json_encode($lang['datatables']);
|
||||||
|
|
||||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/footer.inc.php';
|
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/footer.inc.php';
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File renamed without changes.
Binary file not shown.
|
After Width: | Height: | Size: 7.4 KiB |
@@ -436,7 +436,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
|
|||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
</table>
|
</table>
|
||||||
<a id='download-zonefile' class="btn btn-sm btn-default visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline" style="margin-top:10px" data-zonefile="<?=base64_encode($dns_data);?>" download='<?=$_GET['domain'];?>.txt' type='text/csv'>Download</a>
|
<a id='download-zonefile' class="btn btn-sm btn-secondary visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline mb-4" style="margin-top:10px" data-zonefile="<?=base64_encode($dns_data);?>" download='<?=$_GET['domain'];?>.txt' type='text/csv'>Download</a>
|
||||||
<script>
|
<script>
|
||||||
var zonefile_dl_link = document.getElementById('download-zonefile');
|
var zonefile_dl_link = document.getElementById('download-zonefile');
|
||||||
var zonefile = atob(zonefile_dl_link.getAttribute('data-zonefile'));
|
var zonefile = atob(zonefile_dl_link.getAttribute('data-zonefile'));
|
||||||
|
|||||||
@@ -127,6 +127,7 @@ elseif (!empty($_GET['id']) && ctype_alnum($_GET['id'])) {
|
|||||||
$data['fuzzy_hashes'] = json_decode($mailc['fuzzy_hashes']);
|
$data['fuzzy_hashes'] = json_decode($mailc['fuzzy_hashes']);
|
||||||
// Get text/plain content
|
// Get text/plain content
|
||||||
$data['text_plain'] = $mail_parser->getMessageBody('text');
|
$data['text_plain'] = $mail_parser->getMessageBody('text');
|
||||||
|
if (!json_encode($data['text_plain'])) $data['text_plain'] = '';
|
||||||
// Get html content and convert to text
|
// Get html content and convert to text
|
||||||
$data['text_html'] = $html2text->convert($mail_parser->getMessageBody('html'));
|
$data['text_html'] = $html2text->convert($mail_parser->getMessageBody('html'));
|
||||||
if (empty($data['text_plain']) && empty($data['text_html'])) {
|
if (empty($data['text_plain']) && empty($data['text_html'])) {
|
||||||
|
|||||||
@@ -2,8 +2,18 @@
|
|||||||
function customize($_action, $_item, $_data = null) {
|
function customize($_action, $_item, $_data = null) {
|
||||||
global $redis;
|
global $redis;
|
||||||
global $lang;
|
global $lang;
|
||||||
|
|
||||||
switch ($_action) {
|
switch ($_action) {
|
||||||
case 'add':
|
case 'add':
|
||||||
|
// disable functionality when demo mode is enabled
|
||||||
|
if ($GLOBALS["DEMO_MODE"]) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
||||||
|
'msg' => 'demo_mode_enabled'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
@@ -72,6 +82,15 @@ function customize($_action, $_item, $_data = null) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'edit':
|
case 'edit':
|
||||||
|
// disable functionality when demo mode is enabled
|
||||||
|
if ($GLOBALS["DEMO_MODE"]) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
||||||
|
'msg' => 'demo_mode_enabled'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
@@ -116,6 +135,7 @@ function customize($_action, $_item, $_data = null) {
|
|||||||
$ui_announcement_text = $_data['ui_announcement_text'];
|
$ui_announcement_text = $_data['ui_announcement_text'];
|
||||||
$ui_announcement_type = (in_array($_data['ui_announcement_type'], array('info', 'warning', 'danger'))) ? $_data['ui_announcement_type'] : false;
|
$ui_announcement_type = (in_array($_data['ui_announcement_type'], array('info', 'warning', 'danger'))) ? $_data['ui_announcement_type'] : false;
|
||||||
$ui_announcement_active = (!empty($_data['ui_announcement_active']) ? 1 : 0);
|
$ui_announcement_active = (!empty($_data['ui_announcement_active']) ? 1 : 0);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$redis->set('TITLE_NAME', htmlspecialchars($title_name));
|
$redis->set('TITLE_NAME', htmlspecialchars($title_name));
|
||||||
$redis->set('MAIN_NAME', htmlspecialchars($main_name));
|
$redis->set('MAIN_NAME', htmlspecialchars($main_name));
|
||||||
@@ -140,9 +160,37 @@ function customize($_action, $_item, $_data = null) {
|
|||||||
'msg' => 'ui_texts'
|
'msg' => 'ui_texts'
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
case 'ip_check':
|
||||||
|
$ip_check = ($_data['ip_check_opt_in'] == "1") ? 1 : 0;
|
||||||
|
try {
|
||||||
|
$redis->set('IP_CHECK', $ip_check);
|
||||||
|
}
|
||||||
|
catch (RedisException $e) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
||||||
|
'msg' => array('redis_error', $e)
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'success',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
||||||
|
'msg' => 'ip_check_opt_in_modified'
|
||||||
|
);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'delete':
|
case 'delete':
|
||||||
|
// disable functionality when demo mode is enabled
|
||||||
|
if ($GLOBALS["DEMO_MODE"]) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
||||||
|
'msg' => 'demo_mode_enabled'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
@@ -247,6 +295,20 @@ function customize($_action, $_item, $_data = null) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'ip_check':
|
||||||
|
try {
|
||||||
|
$ip_check = ($ip_check = $redis->get('IP_CHECK')) ? $ip_check : 0;
|
||||||
|
return $ip_check;
|
||||||
|
}
|
||||||
|
catch (RedisException $e) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
||||||
|
'msg' => array('redis_error', $e)
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $extra_headers = null) {
|
function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $extra_headers = null) {
|
||||||
global $DOCKER_TIMEOUT;
|
global $DOCKER_TIMEOUT;
|
||||||
|
global $redis;
|
||||||
$curl = curl_init();
|
$curl = curl_init();
|
||||||
curl_setopt($curl, CURLOPT_HTTPHEADER,array('Content-Type: application/json' ));
|
curl_setopt($curl, CURLOPT_HTTPHEADER,array('Content-Type: application/json' ));
|
||||||
// We are using our mail certificates for dockerapi, the names will not match, the certs are trusted anyway
|
// We are using our mail certificates for dockerapi, the names will not match, the certs are trusted anyway
|
||||||
@@ -32,6 +33,7 @@ function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $ex
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
break;
|
||||||
case 'containers':
|
case 'containers':
|
||||||
curl_setopt($curl, CURLOPT_URL, 'https://dockerapi:443/containers/json');
|
curl_setopt($curl, CURLOPT_URL, 'https://dockerapi:443/containers/json');
|
||||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||||||
@@ -51,6 +53,7 @@ function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $ex
|
|||||||
if (strtolower($container['Config']['Labels']['com.docker.compose.project']) == strtolower(getenv('COMPOSE_PROJECT_NAME'))) {
|
if (strtolower($container['Config']['Labels']['com.docker.compose.project']) == strtolower(getenv('COMPOSE_PROJECT_NAME'))) {
|
||||||
$out[$container['Config']['Labels']['com.docker.compose.service']]['State'] = $container['State'];
|
$out[$container['Config']['Labels']['com.docker.compose.service']]['State'] = $container['State'];
|
||||||
$out[$container['Config']['Labels']['com.docker.compose.service']]['Config'] = $container['Config'];
|
$out[$container['Config']['Labels']['com.docker.compose.service']]['Config'] = $container['Config'];
|
||||||
|
$out[$container['Config']['Labels']['com.docker.compose.service']]['Id'] = trim($container['Id']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -94,6 +97,7 @@ function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $ex
|
|||||||
unset($container['Config']['Env']);
|
unset($container['Config']['Env']);
|
||||||
$out[$container['Config']['Labels']['com.docker.compose.service']]['State'] = $container['State'];
|
$out[$container['Config']['Labels']['com.docker.compose.service']]['State'] = $container['State'];
|
||||||
$out[$container['Config']['Labels']['com.docker.compose.service']]['Config'] = $container['Config'];
|
$out[$container['Config']['Labels']['com.docker.compose.service']]['Config'] = $container['Config'];
|
||||||
|
$out[$container['Config']['Labels']['com.docker.compose.service']]['Id'] = trim($container['Id']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -103,6 +107,7 @@ function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $ex
|
|||||||
unset($container['Config']['Env']);
|
unset($container['Config']['Env']);
|
||||||
$out[$decoded_response['Config']['Labels']['com.docker.compose.service']]['State'] = $decoded_response['State'];
|
$out[$decoded_response['Config']['Labels']['com.docker.compose.service']]['State'] = $decoded_response['State'];
|
||||||
$out[$decoded_response['Config']['Labels']['com.docker.compose.service']]['Config'] = $decoded_response['Config'];
|
$out[$decoded_response['Config']['Labels']['com.docker.compose.service']]['Config'] = $decoded_response['Config'];
|
||||||
|
$out[$decoded_response['Config']['Labels']['com.docker.compose.service']]['Id'] = trim($decoded_response['Id']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -146,5 +151,46 @@ function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $ex
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'container_stats':
|
||||||
|
if (empty($service_name)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$container_id = $service_name;
|
||||||
|
curl_setopt($curl, CURLOPT_URL, 'https://dockerapi:443/container/' . $container_id . '/stats/update');
|
||||||
|
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||||||
|
curl_setopt($curl, CURLOPT_POST, 1);
|
||||||
|
curl_setopt($curl, CURLOPT_TIMEOUT, $DOCKER_TIMEOUT);
|
||||||
|
$response = curl_exec($curl);
|
||||||
|
if ($response === false) {
|
||||||
|
$err = curl_error($curl);
|
||||||
|
curl_close($curl);
|
||||||
|
return $err;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
curl_close($curl);
|
||||||
|
$stats = json_decode($response, true);
|
||||||
|
if (!empty($stats)) return $stats;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case 'host_stats':
|
||||||
|
curl_setopt($curl, CURLOPT_URL, 'https://dockerapi:443/host/stats');
|
||||||
|
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||||||
|
curl_setopt($curl, CURLOPT_POST, 0);
|
||||||
|
curl_setopt($curl, CURLOPT_TIMEOUT, $DOCKER_TIMEOUT);
|
||||||
|
$response = curl_exec($curl);
|
||||||
|
if ($response === false) {
|
||||||
|
$err = curl_error($curl);
|
||||||
|
curl_close($curl);
|
||||||
|
return $err;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
curl_close($curl);
|
||||||
|
$stats = json_decode($response, true);
|
||||||
|
if (!empty($stats)) return $stats;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -251,7 +251,7 @@ function password_check($password1, $password2) {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
function last_login($action, $username, $sasl_limit_days = 7) {
|
function last_login($action, $username, $sasl_limit_days = 7, $ui_offset = 1) {
|
||||||
global $pdo;
|
global $pdo;
|
||||||
global $redis;
|
global $redis;
|
||||||
$sasl_limit_days = intval($sasl_limit_days);
|
$sasl_limit_days = intval($sasl_limit_days);
|
||||||
@@ -319,8 +319,11 @@ function last_login($action, $username, $sasl_limit_days = 7) {
|
|||||||
$stmt = $pdo->prepare('SELECT `remote`, `time` FROM `logs`
|
$stmt = $pdo->prepare('SELECT `remote`, `time` FROM `logs`
|
||||||
WHERE JSON_EXTRACT(`call`, "$[0]") = "check_login"
|
WHERE JSON_EXTRACT(`call`, "$[0]") = "check_login"
|
||||||
AND JSON_EXTRACT(`call`, "$[1]") = :username
|
AND JSON_EXTRACT(`call`, "$[1]") = :username
|
||||||
AND `type` = "success" ORDER BY `time` DESC LIMIT 1 OFFSET 1');
|
AND `type` = "success" ORDER BY `time` DESC LIMIT 1 OFFSET :offset');
|
||||||
$stmt->execute(array(':username' => $username));
|
$stmt->execute(array(
|
||||||
|
':username' => $username,
|
||||||
|
':offset' => $ui_offset
|
||||||
|
));
|
||||||
$ui = $stmt->fetch(PDO::FETCH_ASSOC);
|
$ui = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -1020,6 +1020,13 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
if (empty($name)) {
|
if (empty($name)) {
|
||||||
$name = $local_part;
|
$name = $local_part;
|
||||||
}
|
}
|
||||||
|
if (isset($_data['protocol_access'])) {
|
||||||
|
$_data['protocol_access'] = (array)$_data['protocol_access'];
|
||||||
|
$_data['imap_access'] = (in_array('imap', $_data['protocol_access'])) ? 1 : 0;
|
||||||
|
$_data['pop3_access'] = (in_array('pop3', $_data['protocol_access'])) ? 1 : 0;
|
||||||
|
$_data['smtp_access'] = (in_array('smtp', $_data['protocol_access'])) ? 1 : 0;
|
||||||
|
$_data['sieve_access'] = (in_array('sieve', $_data['protocol_access'])) ? 1 : 0;
|
||||||
|
}
|
||||||
$active = intval($_data['active']);
|
$active = intval($_data['active']);
|
||||||
$force_pw_update = (isset($_data['force_pw_update'])) ? intval($_data['force_pw_update']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['force_pw_update']);
|
$force_pw_update = (isset($_data['force_pw_update'])) ? intval($_data['force_pw_update']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['force_pw_update']);
|
||||||
$tls_enforce_in = (isset($_data['tls_enforce_in'])) ? intval($_data['tls_enforce_in']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_in']);
|
$tls_enforce_in = (isset($_data['tls_enforce_in'])) ? intval($_data['tls_enforce_in']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_in']);
|
||||||
@@ -1200,10 +1207,63 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
':domain' => $domain,
|
':domain' => $domain,
|
||||||
':active' => $active
|
':active' => $active
|
||||||
));
|
));
|
||||||
$stmt = $pdo->prepare("INSERT INTO `user_acl` (`username`) VALUES (:username)");
|
|
||||||
$stmt->execute(array(
|
|
||||||
':username' => $username
|
if (isset($_data['acl'])) {
|
||||||
));
|
$_data['acl'] = (array)$_data['acl'];
|
||||||
|
$_data['spam_alias'] = (in_array('spam_alias', $_data['acl'])) ? 1 : 0;
|
||||||
|
$_data['tls_policy'] = (in_array('tls_policy', $_data['acl'])) ? 1 : 0;
|
||||||
|
$_data['spam_score'] = (in_array('spam_score', $_data['acl'])) ? 1 : 0;
|
||||||
|
$_data['spam_policy'] = (in_array('spam_policy', $_data['acl'])) ? 1 : 0;
|
||||||
|
$_data['delimiter_action'] = (in_array('delimiter_action', $_data['acl'])) ? 1 : 0;
|
||||||
|
$_data['syncjobs'] = (in_array('syncjobs', $_data['acl'])) ? 1 : 0;
|
||||||
|
$_data['eas_reset'] = (in_array('eas_reset', $_data['acl'])) ? 1 : 0;
|
||||||
|
$_data['sogo_profile_reset'] = (in_array('sogo_profile_reset', $_data['acl'])) ? 1 : 0;
|
||||||
|
$_data['pushover'] = (in_array('pushover', $_data['acl'])) ? 1 : 0;
|
||||||
|
$_data['quarantine'] = (in_array('quarantine', $_data['acl'])) ? 1 : 0;
|
||||||
|
$_data['quarantine_attachments'] = (in_array('quarantine_attachments', $_data['acl'])) ? 1 : 0;
|
||||||
|
$_data['quarantine_notification'] = (in_array('quarantine_notification', $_data['acl'])) ? 1 : 0;
|
||||||
|
$_data['quarantine_category'] = (in_array('quarantine_category', $_data['acl'])) ? 1 : 0;
|
||||||
|
$_data['app_passwds'] = (in_array('app_passwds', $_data['acl'])) ? 1 : 0;
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO `user_acl`
|
||||||
|
(`username`, `spam_alias`, `tls_policy`, `spam_score`, `spam_policy`, `delimiter_action`, `syncjobs`, `eas_reset`, `sogo_profile_reset`,
|
||||||
|
`pushover`, `quarantine`, `quarantine_attachments`, `quarantine_notification`, `quarantine_category`, `app_passwds`)
|
||||||
|
VALUES (:username, :spam_alias, :tls_policy, :spam_score, :spam_policy, :delimiter_action, :syncjobs, :eas_reset, :sogo_profile_reset,
|
||||||
|
:pushover, :quarantine, :quarantine_attachments, :quarantine_notification, :quarantine_category, :app_passwds) ");
|
||||||
|
$stmt->execute(array(
|
||||||
|
':username' => $username,
|
||||||
|
':spam_alias' => $_data['spam_alias'],
|
||||||
|
':tls_policy' => $_data['tls_policy'],
|
||||||
|
':spam_score' => $_data['spam_score'],
|
||||||
|
':spam_policy' => $_data['spam_policy'],
|
||||||
|
':delimiter_action' => $_data['delimiter_action'],
|
||||||
|
':syncjobs' => $_data['syncjobs'],
|
||||||
|
':eas_reset' => $_data['eas_reset'],
|
||||||
|
':sogo_profile_reset' => $_data['sogo_profile_reset'],
|
||||||
|
':pushover' => $_data['pushover'],
|
||||||
|
':quarantine' => $_data['quarantine'],
|
||||||
|
':quarantine_attachments' => $_data['quarantine_attachments'],
|
||||||
|
':quarantine_notification' => $_data['quarantine_notification'],
|
||||||
|
':quarantine_category' => $_data['quarantine_category'],
|
||||||
|
':app_passwds' => $_data['app_passwds']
|
||||||
|
));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO `user_acl` (`username`) VALUES (:username)");
|
||||||
|
$stmt->execute(array(
|
||||||
|
':username' => $username
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_data['rl_frame']) && isset($_data['rl_value'])){
|
||||||
|
ratelimit('edit', 'mailbox', array(
|
||||||
|
'object' => $username,
|
||||||
|
'rl_frame' => $_data['rl_frame'],
|
||||||
|
'rl_value' => $_data['rl_value']
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'success',
|
'type' => 'success',
|
||||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
@@ -1322,6 +1382,190 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
'msg' => array('resource_added', htmlspecialchars($name))
|
'msg' => array('resource_added', htmlspecialchars($name))
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
case 'domain_templates':
|
||||||
|
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
|
||||||
|
'msg' => 'access_denied'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (empty($_data["template"])){
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
|
||||||
|
'msg' => 'template_name_invalid'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if template name exists, return false
|
||||||
|
$stmt = $pdo->prepare("SELECT id FROM `templates` WHERE `type` = :type AND `template` = :template");
|
||||||
|
$stmt->execute(array(
|
||||||
|
":type" => "domain",
|
||||||
|
":template" => $_data["template"]
|
||||||
|
));
|
||||||
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (!empty($row)){
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
|
||||||
|
'msg' => array('template_exists', $_data["template"])
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check attributes
|
||||||
|
$attr = array();
|
||||||
|
$attr['tags'] = (isset($_data['tags'])) ? $_data['tags'] : array();
|
||||||
|
$attr['max_num_aliases_for_domain'] = (!empty($_data['max_num_aliases_for_domain'])) ? intval($_data['max_num_aliases_for_domain']) : 400;
|
||||||
|
$attr['max_num_mboxes_for_domain'] = (!empty($_data['max_num_mboxes_for_domain'])) ? intval($_data['max_num_mboxes_for_domain']) : 10;
|
||||||
|
$attr['def_quota_for_mbox'] = (!empty($_data['def_quota_for_mbox'])) ? intval($_data['def_quota_for_mbox']) * 1048576 : 3072 * 1048576;
|
||||||
|
$attr['max_quota_for_mbox'] = (!empty($_data['max_quota_for_mbox'])) ? intval($_data['max_quota_for_mbox']) * 1048576 : 10240 * 1048576;
|
||||||
|
$attr['max_quota_for_domain'] = (!empty($_data['max_quota_for_domain'])) ? intval($_data['max_quota_for_domain']) * 1048576 : 10240 * 1048576;
|
||||||
|
$attr['rl_frame'] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : "s";
|
||||||
|
$attr['rl_value'] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : "";
|
||||||
|
$attr['active'] = isset($_data['active']) ? intval($_data['active']) : 1;
|
||||||
|
$attr['gal'] = (isset($_data['gal'])) ? intval($_data['gal']) : 1;
|
||||||
|
$attr['backupmx'] = (isset($_data['backupmx'])) ? intval($_data['backupmx']) : 0;
|
||||||
|
$attr['relay_all_recipients'] = (isset($_data['relay_all_recipients'])) ? intval($_data['relay_all_recipients']) : 0;
|
||||||
|
$attr['relay_unknown_only'] = (isset($_data['relay_unknown_only'])) ? intval($_data['relay_unknown_only']) : 0;
|
||||||
|
$attr['dkim_selector'] = (isset($_data['dkim_selector'])) ? $_data['dkim_selector'] : "dkim";
|
||||||
|
$attr['key_size'] = isset($_data['key_size']) ? intval($_data['key_size']) : 2048;
|
||||||
|
|
||||||
|
// save template
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO `templates` (`type`, `template`, `attributes`)
|
||||||
|
VALUES (:type, :template, :attributes)");
|
||||||
|
$stmt->execute(array(
|
||||||
|
":type" => "domain",
|
||||||
|
":template" => $_data["template"],
|
||||||
|
":attributes" => json_encode($attr)
|
||||||
|
));
|
||||||
|
|
||||||
|
// success
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'success',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
|
'msg' => array('template_added', $_data["template"])
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
case 'mailbox_templates':
|
||||||
|
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
|
||||||
|
'msg' => 'access_denied'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (empty($_data["template"])){
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
|
||||||
|
'msg' => 'template_name_invalid'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if template name exists, return false
|
||||||
|
$stmt = $pdo->prepare("SELECT id FROM `templates` WHERE `type` = :type AND `template` = :template");
|
||||||
|
$stmt->execute(array(
|
||||||
|
":type" => "mailbox",
|
||||||
|
":template" => $_data["template"]
|
||||||
|
));
|
||||||
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
if (!empty($row)){
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
|
||||||
|
'msg' => array('template_exists', $_data["template"])
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// check attributes
|
||||||
|
$attr = array();
|
||||||
|
$attr["quota"] = isset($_data['quota']) ? intval($_data['quota']) * 1048576 : 0;
|
||||||
|
$attr['tags'] = (isset($_data['tags'])) ? $_data['tags'] : array();
|
||||||
|
$attr["quarantine_notification"] = (!empty($_data['quarantine_notification'])) ? $_data['quarantine_notification'] : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_notification']);
|
||||||
|
$attr["quarantine_category"] = (!empty($_data['quarantine_category'])) ? $_data['quarantine_category'] : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_category']);
|
||||||
|
$attr["rl_frame"] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : "s";
|
||||||
|
$attr["rl_value"] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : "";
|
||||||
|
$attr["force_pw_update"] = isset($_data['force_pw_update']) ? intval($_data['force_pw_update']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['force_pw_update']);
|
||||||
|
$attr["sogo_access"] = isset($_data['sogo_access']) ? intval($_data['sogo_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['sogo_access']);
|
||||||
|
$attr["active"] = isset($_data['active']) ? intval($_data['active']) : 1;
|
||||||
|
$attr["tls_enforce_in"] = isset($_data['tls_enforce_in']) ? intval($_data['tls_enforce_in']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_in']);
|
||||||
|
$attr["tls_enforce_out"] = isset($_data['tls_enforce_out']) ? intval($_data['tls_enforce_out']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_out']);
|
||||||
|
if (isset($_data['protocol_access'])) {
|
||||||
|
$_data['protocol_access'] = (array)$_data['protocol_access'];
|
||||||
|
$attr['imap_access'] = (in_array('imap', $_data['protocol_access'])) ? 1 : intval($MAILBOX_DEFAULT_ATTRIBUTES['imap_access']);
|
||||||
|
$attr['pop3_access'] = (in_array('pop3', $_data['protocol_access'])) ? 1 : intval($MAILBOX_DEFAULT_ATTRIBUTES['pop3_access']);
|
||||||
|
$attr['smtp_access'] = (in_array('smtp', $_data['protocol_access'])) ? 1 : intval($MAILBOX_DEFAULT_ATTRIBUTES['smtp_access']);
|
||||||
|
$attr['sieve_access'] = (in_array('sieve', $_data['protocol_access'])) ? 1 : intval($MAILBOX_DEFAULT_ATTRIBUTES['sieve_access']);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$attr['imap_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['imap_access']);
|
||||||
|
$attr['pop3_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['pop3_access']);
|
||||||
|
$attr['smtp_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['smtp_access']);
|
||||||
|
$attr['sieve_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['sieve_access']);
|
||||||
|
}
|
||||||
|
if (isset($_data['acl'])) {
|
||||||
|
$_data['acl'] = (array)$_data['acl'];
|
||||||
|
$attr['acl_spam_alias'] = (in_array('spam_alias', $_data['acl'])) ? 1 : 0;
|
||||||
|
$attr['acl_tls_policy'] = (in_array('tls_policy', $_data['acl'])) ? 1 : 0;
|
||||||
|
$attr['acl_spam_score'] = (in_array('spam_score', $_data['acl'])) ? 1 : 0;
|
||||||
|
$attr['acl_spam_policy'] = (in_array('spam_policy', $_data['acl'])) ? 1 : 0;
|
||||||
|
$attr['acl_delimiter_action'] = (in_array('delimiter_action', $_data['acl'])) ? 1 : 0;
|
||||||
|
$attr['acl_syncjobs'] = (in_array('syncjobs', $_data['acl'])) ? 1 : 0;
|
||||||
|
$attr['acl_eas_reset'] = (in_array('eas_reset', $_data['acl'])) ? 1 : 0;
|
||||||
|
$attr['acl_sogo_profile_reset'] = (in_array('sogo_profile_reset', $_data['acl'])) ? 1 : 0;
|
||||||
|
$attr['acl_pushover'] = (in_array('pushover', $_data['acl'])) ? 1 : 0;
|
||||||
|
$attr['acl_quarantine'] = (in_array('quarantine', $_data['acl'])) ? 1 : 0;
|
||||||
|
$attr['acl_quarantine_attachments'] = (in_array('quarantine_attachments', $_data['acl'])) ? 1 : 0;
|
||||||
|
$attr['acl_quarantine_notification'] = (in_array('quarantine_notification', $_data['acl'])) ? 1 : 0;
|
||||||
|
$attr['acl_quarantine_category'] = (in_array('quarantine_category', $_data['acl'])) ? 1 : 0;
|
||||||
|
$attr['acl_app_passwds'] = (in_array('app_passwds', $_data['acl'])) ? 1 : 0;
|
||||||
|
} else {
|
||||||
|
$_data['acl'] = (array)$_data['acl'];
|
||||||
|
$attr['acl_spam_alias'] = 1;
|
||||||
|
$attr['acl_tls_policy'] = 1;
|
||||||
|
$attr['acl_spam_score'] = 1;
|
||||||
|
$attr['acl_spam_policy'] = 1;
|
||||||
|
$attr['acl_delimiter_action'] = 1;
|
||||||
|
$attr['acl_syncjobs'] = 0;
|
||||||
|
$attr['acl_eas_reset'] = 1;
|
||||||
|
$attr['acl_sogo_profile_reset'] = 0;
|
||||||
|
$attr['acl_pushover'] = 1;
|
||||||
|
$attr['acl_quarantine'] = 1;
|
||||||
|
$attr['acl_quarantine_attachments'] = 1;
|
||||||
|
$attr['acl_quarantine_notification'] = 1;
|
||||||
|
$attr['acl_quarantine_category'] = 1;
|
||||||
|
$attr['acl_app_passwds'] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// save template
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO `templates` (`type`, `template`, `attributes`)
|
||||||
|
VALUES (:type, :template, :attributes)");
|
||||||
|
$stmt->execute(array(
|
||||||
|
":type" => "mailbox",
|
||||||
|
":template" => $_data["template"],
|
||||||
|
":attributes" => json_encode($attr)
|
||||||
|
));
|
||||||
|
|
||||||
|
// success
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'success',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
|
'msg' => array('template_added', $_data["template"])
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'edit':
|
case 'edit':
|
||||||
@@ -2472,6 +2716,79 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'domain_templates':
|
||||||
|
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
|
||||||
|
'msg' => 'access_denied'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!is_array($_data['ids'])) {
|
||||||
|
$ids = array();
|
||||||
|
$ids[] = $_data['ids'];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$ids = $_data['ids'];
|
||||||
|
}
|
||||||
|
foreach ($ids as $id) {
|
||||||
|
$is_now = mailbox("get", "domain_templates", $id);
|
||||||
|
if (empty($is_now) ||
|
||||||
|
$is_now["type"] != "domain"){
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
|
||||||
|
'msg' => 'template_id_invalid'
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check name
|
||||||
|
if ($is_now["template"] == "Default" && $is_now["template"] != $_data["template"]){
|
||||||
|
// keep template name of Default template
|
||||||
|
$_data["template"] = $is_now["template"];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$_data["template"] = (isset($_data["template"])) ? $_data["template"] : $is_now["template"];
|
||||||
|
}
|
||||||
|
// check attributes
|
||||||
|
$attr = array();
|
||||||
|
$attr['tags'] = (isset($_data['tags'])) ? $_data['tags'] : array();
|
||||||
|
$attr['max_num_aliases_for_domain'] = (isset($_data['max_num_aliases_for_domain'])) ? intval($_data['max_num_aliases_for_domain']) : 0;
|
||||||
|
$attr['max_num_mboxes_for_domain'] = (isset($_data['max_num_mboxes_for_domain'])) ? intval($_data['max_num_mboxes_for_domain']) : 0;
|
||||||
|
$attr['def_quota_for_mbox'] = (isset($_data['def_quota_for_mbox'])) ? intval($_data['def_quota_for_mbox']) * 1048576 : 0;
|
||||||
|
$attr['max_quota_for_mbox'] = (isset($_data['max_quota_for_mbox'])) ? intval($_data['max_quota_for_mbox']) * 1048576 : 0;
|
||||||
|
$attr['max_quota_for_domain'] = (isset($_data['max_quota_for_domain'])) ? intval($_data['max_quota_for_domain']) * 1048576 : 0;
|
||||||
|
$attr['rl_frame'] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : "s";
|
||||||
|
$attr['rl_value'] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : "";
|
||||||
|
$attr['active'] = isset($_data['active']) ? intval($_data['active']) : 1;
|
||||||
|
$attr['gal'] = (isset($_data['gal'])) ? intval($_data['gal']) : 1;
|
||||||
|
$attr['backupmx'] = (isset($_data['backupmx'])) ? intval($_data['backupmx']) : 0;
|
||||||
|
$attr['relay_all_recipients'] = (isset($_data['relay_all_recipients'])) ? intval($_data['relay_all_recipients']) : 0;
|
||||||
|
$attr['relay_unknown_only'] = (isset($_data['relay_unknown_only'])) ? intval($_data['relay_unknown_only']) : 0;
|
||||||
|
$attr['dkim_selector'] = (isset($_data['dkim_selector'])) ? $_data['dkim_selector'] : "dkim";
|
||||||
|
$attr['key_size'] = isset($_data['key_size']) ? intval($_data['key_size']) : 2048;
|
||||||
|
|
||||||
|
// update template
|
||||||
|
$stmt = $pdo->prepare("UPDATE `templates`
|
||||||
|
SET `template` = :template, `attributes` = :attributes
|
||||||
|
WHERE id = :id");
|
||||||
|
$stmt->execute(array(
|
||||||
|
":id" => $id ,
|
||||||
|
":template" => $_data["template"] ,
|
||||||
|
":attributes" => json_encode($attr)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'success',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
|
'msg' => array('template_modified', $_data["template"])
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
case 'mailbox':
|
case 'mailbox':
|
||||||
if (!is_array($_data['username'])) {
|
if (!is_array($_data['username'])) {
|
||||||
$usernames = array();
|
$usernames = array();
|
||||||
@@ -2562,67 +2879,68 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
'msg' => 'access_denied'
|
'msg' => 'extended_sender_acl_denied'
|
||||||
);
|
);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
$extra_acls = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['extended_sender_acl']));
|
else {
|
||||||
foreach ($extra_acls as $i => &$extra_acl) {
|
$extra_acls = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['extended_sender_acl']));
|
||||||
if (empty($extra_acl)) {
|
foreach ($extra_acls as $i => &$extra_acl) {
|
||||||
continue;
|
if (empty($extra_acl)) {
|
||||||
}
|
continue;
|
||||||
if (substr($extra_acl, 0, 1) === "@") {
|
}
|
||||||
$extra_acl = ltrim($extra_acl, '@');
|
if (substr($extra_acl, 0, 1) === "@") {
|
||||||
}
|
$extra_acl = ltrim($extra_acl, '@');
|
||||||
if (!filter_var($extra_acl, FILTER_VALIDATE_EMAIL) && !is_valid_domain_name($extra_acl)) {
|
}
|
||||||
$_SESSION['return'][] = array(
|
if (!filter_var($extra_acl, FILTER_VALIDATE_EMAIL) && !is_valid_domain_name($extra_acl)) {
|
||||||
'type' => 'danger',
|
|
||||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
|
||||||
'msg' => array('extra_acl_invalid', htmlspecialchars($extra_acl))
|
|
||||||
);
|
|
||||||
unset($extra_acls[$i]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$domains = array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains'));
|
|
||||||
if (filter_var($extra_acl, FILTER_VALIDATE_EMAIL)) {
|
|
||||||
$extra_acl_domain = idn_to_ascii(substr(strstr($extra_acl, '@'), 1), 0, INTL_IDNA_VARIANT_UTS46);
|
|
||||||
if (in_array($extra_acl_domain, $domains)) {
|
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
'msg' => array('extra_acl_invalid_domain', $extra_acl_domain)
|
'msg' => array('extra_acl_invalid', htmlspecialchars($extra_acl))
|
||||||
);
|
);
|
||||||
unset($extra_acls[$i]);
|
unset($extra_acls[$i]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
$domains = array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains'));
|
||||||
else {
|
if (filter_var($extra_acl, FILTER_VALIDATE_EMAIL)) {
|
||||||
if (in_array($extra_acl, $domains)) {
|
$extra_acl_domain = idn_to_ascii(substr(strstr($extra_acl, '@'), 1), 0, INTL_IDNA_VARIANT_UTS46);
|
||||||
$_SESSION['return'][] = array(
|
if (in_array($extra_acl_domain, $domains)) {
|
||||||
'type' => 'danger',
|
$_SESSION['return'][] = array(
|
||||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
'type' => 'danger',
|
||||||
'msg' => array('extra_acl_invalid_domain', $extra_acl_domain)
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
);
|
'msg' => array('extra_acl_invalid_domain', $extra_acl_domain)
|
||||||
unset($extra_acls[$i]);
|
);
|
||||||
continue;
|
unset($extra_acls[$i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (in_array($extra_acl, $domains)) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
|
'msg' => array('extra_acl_invalid_domain', $extra_acl_domain)
|
||||||
|
);
|
||||||
|
unset($extra_acls[$i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$extra_acl = '@' . $extra_acl;
|
||||||
}
|
}
|
||||||
$extra_acl = '@' . $extra_acl;
|
|
||||||
}
|
}
|
||||||
}
|
$extra_acls = array_filter($extra_acls);
|
||||||
$extra_acls = array_filter($extra_acls);
|
$extra_acls = array_values($extra_acls);
|
||||||
$extra_acls = array_values($extra_acls);
|
$extra_acls = array_unique($extra_acls);
|
||||||
$extra_acls = array_unique($extra_acls);
|
$stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `external` = 1 AND `logged_in_as` = :username");
|
||||||
$stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `external` = 1 AND `logged_in_as` = :username");
|
|
||||||
$stmt->execute(array(
|
|
||||||
':username' => $username
|
|
||||||
));
|
|
||||||
foreach ($extra_acls as $sender_acl_external) {
|
|
||||||
$stmt = $pdo->prepare("INSERT INTO `sender_acl` (`send_as`, `logged_in_as`, `external`)
|
|
||||||
VALUES (:sender_acl, :username, 1)");
|
|
||||||
$stmt->execute(array(
|
$stmt->execute(array(
|
||||||
':sender_acl' => $sender_acl_external,
|
|
||||||
':username' => $username
|
':username' => $username
|
||||||
));
|
));
|
||||||
|
foreach ($extra_acls as $sender_acl_external) {
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO `sender_acl` (`send_as`, `logged_in_as`, `external`)
|
||||||
|
VALUES (:sender_acl, :username, 1)");
|
||||||
|
$stmt->execute(array(
|
||||||
|
':sender_acl' => $sender_acl_external,
|
||||||
|
':username' => $username
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isset($_data['sender_acl'])) {
|
if (isset($_data['sender_acl'])) {
|
||||||
@@ -2814,6 +3132,110 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'mailbox_templates':
|
||||||
|
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
|
||||||
|
'msg' => 'access_denied'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!is_array($_data['ids'])) {
|
||||||
|
$ids = array();
|
||||||
|
$ids[] = $_data['ids'];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$ids = $_data['ids'];
|
||||||
|
}
|
||||||
|
foreach ($ids as $id) {
|
||||||
|
$is_now = mailbox("get", "mailbox_templates", $id);
|
||||||
|
if (empty($is_now) ||
|
||||||
|
$is_now["type"] != "mailbox"){
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
|
||||||
|
'msg' => 'template_id_invalid'
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// check name
|
||||||
|
if ($is_now["template"] == "Default" && $is_now["template"] != $_data["template"]){
|
||||||
|
// keep template name of Default template
|
||||||
|
$_data["template"] = $is_now["template"];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$_data["template"] = (isset($_data["template"])) ? $_data["template"] : $is_now["template"];
|
||||||
|
}
|
||||||
|
// check attributes
|
||||||
|
$attr = array();
|
||||||
|
$attr["quota"] = isset($_data['quota']) ? intval($_data['quota']) * 1048576 : 0;
|
||||||
|
$attr['tags'] = (isset($_data['tags'])) ? $_data['tags'] : $is_now['tags'];
|
||||||
|
$attr["quarantine_notification"] = (!empty($_data['quarantine_notification'])) ? $_data['quarantine_notification'] : $is_now['quarantine_notification'];
|
||||||
|
$attr["quarantine_category"] = (!empty($_data['quarantine_category'])) ? $_data['quarantine_category'] : $is_now['quarantine_category'];
|
||||||
|
$attr["rl_frame"] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : $is_now['rl_frame'];
|
||||||
|
$attr["rl_value"] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : $is_now['rl_value'];
|
||||||
|
$attr["force_pw_update"] = isset($_data['force_pw_update']) ? intval($_data['force_pw_update']) : $is_now['force_pw_update'];
|
||||||
|
$attr["sogo_access"] = isset($_data['sogo_access']) ? intval($_data['sogo_access']) : $is_now['sogo_access'];
|
||||||
|
$attr["active"] = isset($_data['active']) ? intval($_data['active']) : $is_now['active'];
|
||||||
|
$attr["tls_enforce_in"] = isset($_data['tls_enforce_in']) ? intval($_data['tls_enforce_in']) : $is_now['tls_enforce_in'];
|
||||||
|
$attr["tls_enforce_out"] = isset($_data['tls_enforce_out']) ? intval($_data['tls_enforce_out']) : $is_now['tls_enforce_out'];
|
||||||
|
if (isset($_data['protocol_access'])) {
|
||||||
|
$_data['protocol_access'] = (array)$_data['protocol_access'];
|
||||||
|
$attr['imap_access'] = (in_array('imap', $_data['protocol_access'])) ? 1 : 0;
|
||||||
|
$attr['pop3_access'] = (in_array('pop3', $_data['protocol_access'])) ? 1 : 0;
|
||||||
|
$attr['smtp_access'] = (in_array('smtp', $_data['protocol_access'])) ? 1 : 0;
|
||||||
|
$attr['sieve_access'] = (in_array('sieve', $_data['protocol_access'])) ? 1 : 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
foreach ($is_now as $key => $value){
|
||||||
|
$attr[$key] = $is_now[$key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isset($_data['acl'])) {
|
||||||
|
$_data['acl'] = (array)$_data['acl'];
|
||||||
|
$attr['acl_spam_alias'] = (in_array('spam_alias', $_data['acl'])) ? 1 : 0;
|
||||||
|
$attr['acl_tls_policy'] = (in_array('tls_policy', $_data['acl'])) ? 1 : 0;
|
||||||
|
$attr['acl_spam_score'] = (in_array('spam_score', $_data['acl'])) ? 1 : 0;
|
||||||
|
$attr['acl_spam_policy'] = (in_array('spam_policy', $_data['acl'])) ? 1 : 0;
|
||||||
|
$attr['acl_delimiter_action'] = (in_array('delimiter_action', $_data['acl'])) ? 1 : 0;
|
||||||
|
$attr['acl_syncjobs'] = (in_array('syncjobs', $_data['acl'])) ? 1 : 0;
|
||||||
|
$attr['acl_eas_reset'] = (in_array('eas_reset', $_data['acl'])) ? 1 : 0;
|
||||||
|
$attr['acl_sogo_profile_reset'] = (in_array('sogo_profile_reset', $_data['acl'])) ? 1 : 0;
|
||||||
|
$attr['acl_pushover'] = (in_array('pushover', $_data['acl'])) ? 1 : 0;
|
||||||
|
$attr['acl_quarantine'] = (in_array('quarantine', $_data['acl'])) ? 1 : 0;
|
||||||
|
$attr['acl_quarantine_attachments'] = (in_array('quarantine_attachments', $_data['acl'])) ? 1 : 0;
|
||||||
|
$attr['acl_quarantine_notification'] = (in_array('quarantine_notification', $_data['acl'])) ? 1 : 0;
|
||||||
|
$attr['acl_quarantine_category'] = (in_array('quarantine_category', $_data['acl'])) ? 1 : 0;
|
||||||
|
$attr['acl_app_passwds'] = (in_array('app_passwds', $_data['acl'])) ? 1 : 0;
|
||||||
|
} else {
|
||||||
|
foreach ($is_now as $key => $value){
|
||||||
|
$attr[$key] = $is_now[$key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// update template
|
||||||
|
$stmt = $pdo->prepare("UPDATE `templates`
|
||||||
|
SET `template` = :template, `attributes` = :attributes
|
||||||
|
WHERE id = :id");
|
||||||
|
$stmt->execute(array(
|
||||||
|
":id" => $id ,
|
||||||
|
":template" => $_data["template"] ,
|
||||||
|
":attributes" => json_encode($attr)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'success',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
|
'msg' => array('template_modified', $_data["template"])
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
case 'resource':
|
case 'resource':
|
||||||
if (!is_array($_data['name'])) {
|
if (!is_array($_data['name'])) {
|
||||||
$names = array();
|
$names = array();
|
||||||
@@ -3606,6 +4028,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
`mailboxes`,
|
`mailboxes`,
|
||||||
`defquota`,
|
`defquota`,
|
||||||
`maxquota`,
|
`maxquota`,
|
||||||
|
`created`,
|
||||||
|
`modified`,
|
||||||
`quota`,
|
`quota`,
|
||||||
`relayhost`,
|
`relayhost`,
|
||||||
`relay_all_recipients`,
|
`relay_all_recipients`,
|
||||||
@@ -3678,6 +4102,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
$domaindata['relay_all_recipients_int'] = $row['relay_all_recipients'];
|
$domaindata['relay_all_recipients_int'] = $row['relay_all_recipients'];
|
||||||
$domaindata['relay_unknown_only'] = $row['relay_unknown_only'];
|
$domaindata['relay_unknown_only'] = $row['relay_unknown_only'];
|
||||||
$domaindata['relay_unknown_only_int'] = $row['relay_unknown_only'];
|
$domaindata['relay_unknown_only_int'] = $row['relay_unknown_only'];
|
||||||
|
$domaindata['created'] = $row['created'];
|
||||||
|
$domaindata['modified'] = $row['modified'];
|
||||||
$stmt = $pdo->prepare("SELECT COUNT(`address`) AS `alias_count` FROM `alias`
|
$stmt = $pdo->prepare("SELECT COUNT(`address`) AS `alias_count` FROM `alias`
|
||||||
WHERE (`domain`= :domain OR `domain` IN (SELECT `alias_domain` FROM `alias_domain` WHERE `target_domain` = :domain2))
|
WHERE (`domain`= :domain OR `domain` IN (SELECT `alias_domain` FROM `alias_domain` WHERE `target_domain` = :domain2))
|
||||||
AND `address` NOT IN (
|
AND `address` NOT IN (
|
||||||
@@ -3711,6 +4137,43 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
|
|
||||||
return $domaindata;
|
return $domaindata;
|
||||||
break;
|
break;
|
||||||
|
case 'domain_templates':
|
||||||
|
if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$_data = (isset($_data)) ? intval($_data) : null;
|
||||||
|
|
||||||
|
if (isset($_data)){
|
||||||
|
$stmt = $pdo->prepare("SELECT * FROM `templates`
|
||||||
|
WHERE `id` = :id AND type = :type");
|
||||||
|
$stmt->execute(array(
|
||||||
|
":id" => $_data,
|
||||||
|
":type" => "domain"
|
||||||
|
));
|
||||||
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (empty($row)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$row["attributes"] = json_decode($row["attributes"], true);
|
||||||
|
return $row;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$stmt = $pdo->prepare("SELECT * FROM `templates` WHERE `type` = 'domain'");
|
||||||
|
$stmt->execute();
|
||||||
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (empty($rows)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach($rows as $key => $row){
|
||||||
|
$rows[$key]["attributes"] = json_decode($row["attributes"], true);
|
||||||
|
}
|
||||||
|
return $rows;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'mailbox_details':
|
case 'mailbox_details':
|
||||||
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
|
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -3725,6 +4188,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
`mailbox`.`domain`,
|
`mailbox`.`domain`,
|
||||||
`mailbox`.`local_part`,
|
`mailbox`.`local_part`,
|
||||||
`mailbox`.`quota`,
|
`mailbox`.`quota`,
|
||||||
|
`mailbox`.`created`,
|
||||||
|
`mailbox`.`modified`,
|
||||||
`quota2`.`bytes`,
|
`quota2`.`bytes`,
|
||||||
`attributes`,
|
`attributes`,
|
||||||
`quota2`.`messages`
|
`quota2`.`messages`
|
||||||
@@ -3743,6 +4208,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
`mailbox`.`domain`,
|
`mailbox`.`domain`,
|
||||||
`mailbox`.`local_part`,
|
`mailbox`.`local_part`,
|
||||||
`mailbox`.`quota`,
|
`mailbox`.`quota`,
|
||||||
|
`mailbox`.`created`,
|
||||||
|
`mailbox`.`modified`,
|
||||||
`quota2replica`.`bytes`,
|
`quota2replica`.`bytes`,
|
||||||
`attributes`,
|
`attributes`,
|
||||||
`quota2replica`.`messages`
|
`quota2replica`.`messages`
|
||||||
@@ -3769,6 +4236,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
$mailboxdata['attributes'] = json_decode($row['attributes'], true);
|
$mailboxdata['attributes'] = json_decode($row['attributes'], true);
|
||||||
$mailboxdata['quota_used'] = intval($row['bytes']);
|
$mailboxdata['quota_used'] = intval($row['bytes']);
|
||||||
$mailboxdata['percent_in_use'] = ($row['quota'] == 0) ? '- ' : round((intval($row['bytes']) / intval($row['quota'])) * 100);
|
$mailboxdata['percent_in_use'] = ($row['quota'] == 0) ? '- ' : round((intval($row['bytes']) / intval($row['quota'])) * 100);
|
||||||
|
$mailboxdata['created'] = $row['created'];
|
||||||
|
$mailboxdata['modified'] = $row['modified'];
|
||||||
|
|
||||||
if ($mailboxdata['percent_in_use'] === '- ') {
|
if ($mailboxdata['percent_in_use'] === '- ') {
|
||||||
$mailboxdata['percent_class'] = "info";
|
$mailboxdata['percent_class'] = "info";
|
||||||
@@ -3856,6 +4325,43 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
|
|
||||||
return $mailboxdata;
|
return $mailboxdata;
|
||||||
break;
|
break;
|
||||||
|
case 'mailbox_templates':
|
||||||
|
if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$_data = (isset($_data)) ? intval($_data) : null;
|
||||||
|
|
||||||
|
if (isset($_data)){
|
||||||
|
$stmt = $pdo->prepare("SELECT * FROM `templates`
|
||||||
|
WHERE `id` = :id AND type = :type");
|
||||||
|
$stmt->execute(array(
|
||||||
|
":id" => $_data,
|
||||||
|
":type" => "mailbox"
|
||||||
|
));
|
||||||
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (empty($row)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$row["attributes"] = json_decode($row["attributes"], true);
|
||||||
|
return $row;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$stmt = $pdo->prepare("SELECT * FROM `templates` WHERE `type` = 'mailbox'");
|
||||||
|
$stmt->execute();
|
||||||
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (empty($rows)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach($rows as $key => $row){
|
||||||
|
$rows[$key]["attributes"] = json_decode($row["attributes"], true);
|
||||||
|
}
|
||||||
|
return $rows;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'resource_details':
|
case 'resource_details':
|
||||||
$resourcedata = array();
|
$resourcedata = array();
|
||||||
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
|
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
|
||||||
@@ -4224,6 +4730,42 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'domain_templates':
|
||||||
|
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
|
'msg' => 'access_denied'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!is_array($_data['ids'])) {
|
||||||
|
$ids = array();
|
||||||
|
$ids[] = $_data['ids'];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$ids = $_data['ids'];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
foreach ($ids as $id) {
|
||||||
|
// delete template
|
||||||
|
$stmt = $pdo->prepare("DELETE FROM `templates`
|
||||||
|
WHERE id = :id AND type = :type AND NOT template = :template");
|
||||||
|
$stmt->execute(array(
|
||||||
|
":id" => $id,
|
||||||
|
":type" => "domain",
|
||||||
|
":template" => "Default"
|
||||||
|
));
|
||||||
|
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'success',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
|
'msg' => array('template_removed', htmlspecialchars($id))
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'alias':
|
case 'alias':
|
||||||
if (!is_array($_data['id'])) {
|
if (!is_array($_data['id'])) {
|
||||||
$ids = array();
|
$ids = array();
|
||||||
@@ -4518,6 +5060,42 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'mailbox_templates':
|
||||||
|
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
|
'msg' => 'access_denied'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!is_array($_data['ids'])) {
|
||||||
|
$ids = array();
|
||||||
|
$ids[] = $_data['ids'];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$ids = $_data['ids'];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
foreach ($ids as $id) {
|
||||||
|
// delete template
|
||||||
|
$stmt = $pdo->prepare("DELETE FROM `templates`
|
||||||
|
WHERE id = :id AND type = :type AND NOT template = :template");
|
||||||
|
$stmt->execute(array(
|
||||||
|
":id" => $id,
|
||||||
|
":type" => "mailbox",
|
||||||
|
":template" => "Default"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'success',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
|
'msg' => 'template_removed'
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
case 'resource':
|
case 'resource':
|
||||||
if (!is_array($_data['name'])) {
|
if (!is_array($_data['name'])) {
|
||||||
$names = array();
|
$names = array();
|
||||||
@@ -4594,15 +5172,6 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
if (!is_array($tags)) $tags = array();
|
if (!is_array($tags)) $tags = array();
|
||||||
|
|
||||||
|
|
||||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
|
||||||
$_SESSION['return'][] = array(
|
|
||||||
'type' => 'danger',
|
|
||||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
|
||||||
'msg' => 'access_denied'
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$wasModified = false;
|
$wasModified = false;
|
||||||
foreach ($domains as $domain) {
|
foreach ($domains as $domain) {
|
||||||
if (!is_valid_domain_name($domain)) {
|
if (!is_valid_domain_name($domain)) {
|
||||||
@@ -4613,6 +5182,14 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
|
'msg' => 'access_denied'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
foreach($tags as $tag){
|
foreach($tags as $tag){
|
||||||
// delete tag
|
// delete tag
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ function pushover($_action, $_data = null) {
|
|||||||
$active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
|
$active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
|
||||||
$evaluate_x_prio = (isset($_data['evaluate_x_prio'])) ? intval($_data['evaluate_x_prio']) : $is_now['evaluate_x_prio'];
|
$evaluate_x_prio = (isset($_data['evaluate_x_prio'])) ? intval($_data['evaluate_x_prio']) : $is_now['evaluate_x_prio'];
|
||||||
$only_x_prio = (isset($_data['only_x_prio'])) ? intval($_data['only_x_prio']) : $is_now['only_x_prio'];
|
$only_x_prio = (isset($_data['only_x_prio'])) ? intval($_data['only_x_prio']) : $is_now['only_x_prio'];
|
||||||
|
$sound = (isset($_data['sound'])) ? $_data['sound'] : $is_now['sound'];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
@@ -101,7 +102,8 @@ function pushover($_action, $_data = null) {
|
|||||||
$po_attributes = json_encode(
|
$po_attributes = json_encode(
|
||||||
array(
|
array(
|
||||||
'evaluate_x_prio' => strval(intval($evaluate_x_prio)),
|
'evaluate_x_prio' => strval(intval($evaluate_x_prio)),
|
||||||
'only_x_prio' => strval(intval($only_x_prio))
|
'only_x_prio' => strval(intval($only_x_prio)),
|
||||||
|
'sound' => strval($sound)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$stmt = $pdo->prepare("REPLACE INTO `pushover` (`username`, `key`, `attributes`, `senders_regex`, `senders`, `token`, `title`, `text`, `active`)
|
$stmt = $pdo->prepare("REPLACE INTO `pushover` (`username`, `key`, `attributes`, `senders_regex`, `senders`, `token`, `title`, `text`, `active`)
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ $globalVariables = [
|
|||||||
'dual_login' => @$_SESSION['dual-login'],
|
'dual_login' => @$_SESSION['dual-login'],
|
||||||
'ui_texts' => $UI_TEXTS,
|
'ui_texts' => $UI_TEXTS,
|
||||||
'css_path' => '/cache/'.basename($CSSPath),
|
'css_path' => '/cache/'.basename($CSSPath),
|
||||||
'theme' => strtolower(trim($DEFAULT_THEME)),
|
|
||||||
'logo' => customize('get', 'main_logo'),
|
'logo' => customize('get', 'main_logo'),
|
||||||
'available_languages' => $AVAILABLE_LANGUAGES,
|
'available_languages' => $AVAILABLE_LANGUAGES,
|
||||||
'lang' => $lang,
|
'lang' => $lang,
|
||||||
@@ -49,6 +48,7 @@ $globalVariables = [
|
|||||||
'app_links' => customize('get', 'app_links'),
|
'app_links' => customize('get', 'app_links'),
|
||||||
'is_root_uri' => (parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) == '/'),
|
'is_root_uri' => (parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) == '/'),
|
||||||
'uri' => $_SERVER['REQUEST_URI'],
|
'uri' => $_SERVER['REQUEST_URI'],
|
||||||
|
'last_login' => last_login('get', $_SESSION['mailcow_cc_username'], 7, 0)['ui']['time']
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($globalVariables as $globalVariableName => $globalVariableValue) {
|
foreach ($globalVariables as $globalVariableName => $globalVariableValue) {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ function init_db_schema() {
|
|||||||
try {
|
try {
|
||||||
global $pdo;
|
global $pdo;
|
||||||
|
|
||||||
$db_version = "25072022_2300";
|
$db_version = "23122022_1445";
|
||||||
|
|
||||||
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
|
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
|
||||||
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||||
@@ -225,6 +225,22 @@ function init_db_schema() {
|
|||||||
),
|
),
|
||||||
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
|
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
|
||||||
),
|
),
|
||||||
|
"templates" => array(
|
||||||
|
"cols" => array(
|
||||||
|
"id" => "INT NOT NULL AUTO_INCREMENT",
|
||||||
|
"template" => "VARCHAR(255) NOT NULL",
|
||||||
|
"type" => "VARCHAR(255) NOT NULL",
|
||||||
|
"attributes" => "JSON",
|
||||||
|
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
|
||||||
|
"modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP"
|
||||||
|
),
|
||||||
|
"keys" => array(
|
||||||
|
"primary" => array(
|
||||||
|
"" => array("id")
|
||||||
|
)
|
||||||
|
),
|
||||||
|
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
|
||||||
|
),
|
||||||
"domain" => array(
|
"domain" => array(
|
||||||
// Todo: Move some attributes to json
|
// Todo: Move some attributes to json
|
||||||
"cols" => array(
|
"cols" => array(
|
||||||
@@ -1264,6 +1280,7 @@ function init_db_schema() {
|
|||||||
$pdo->query("UPDATE `pushover` SET `attributes` = '{}' WHERE `attributes` = '' OR `attributes` IS NULL;");
|
$pdo->query("UPDATE `pushover` SET `attributes` = '{}' WHERE `attributes` = '' OR `attributes` IS NULL;");
|
||||||
$pdo->query("UPDATE `pushover` SET `attributes` = JSON_SET(`attributes`, '$.evaluate_x_prio', \"0\") WHERE JSON_VALUE(`attributes`, '$.evaluate_x_prio') IS NULL;");
|
$pdo->query("UPDATE `pushover` SET `attributes` = JSON_SET(`attributes`, '$.evaluate_x_prio', \"0\") WHERE JSON_VALUE(`attributes`, '$.evaluate_x_prio') IS NULL;");
|
||||||
$pdo->query("UPDATE `pushover` SET `attributes` = JSON_SET(`attributes`, '$.only_x_prio', \"0\") WHERE JSON_VALUE(`attributes`, '$.only_x_prio') IS NULL;");
|
$pdo->query("UPDATE `pushover` SET `attributes` = JSON_SET(`attributes`, '$.only_x_prio', \"0\") WHERE JSON_VALUE(`attributes`, '$.only_x_prio') IS NULL;");
|
||||||
|
$pdo->query("UPDATE `pushover` SET `attributes` = JSON_SET(`attributes`, '$.sound', \"pushover\") WHERE JSON_VALUE(`attributes`, '$.sound') IS NULL;");
|
||||||
// mailbox
|
// mailbox
|
||||||
$pdo->query("UPDATE `mailbox` SET `attributes` = '{}' WHERE `attributes` = '' OR `attributes` IS NULL;");
|
$pdo->query("UPDATE `mailbox` SET `attributes` = '{}' WHERE `attributes` = '' OR `attributes` IS NULL;");
|
||||||
$pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.passwd_update', \"0\") WHERE JSON_VALUE(`attributes`, '$.passwd_update') IS NULL;");
|
$pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.passwd_update', \"0\") WHERE JSON_VALUE(`attributes`, '$.passwd_update') IS NULL;");
|
||||||
@@ -1292,6 +1309,95 @@ function init_db_schema() {
|
|||||||
// Fix domain_admins
|
// Fix domain_admins
|
||||||
$pdo->query("DELETE FROM `domain_admins` WHERE `domain` = 'ALL';");
|
$pdo->query("DELETE FROM `domain_admins` WHERE `domain` = 'ALL';");
|
||||||
|
|
||||||
|
// add default templates
|
||||||
|
$default_domain_template = array(
|
||||||
|
"template" => "Default",
|
||||||
|
"type" => "domain",
|
||||||
|
"attributes" => array(
|
||||||
|
"tags" => array(),
|
||||||
|
"max_num_aliases_for_domain" => 400,
|
||||||
|
"max_num_mboxes_for_domain" => 10,
|
||||||
|
"def_quota_for_mbox" => 3072 * 1048576,
|
||||||
|
"max_quota_for_mbox" => 10240 * 1048576,
|
||||||
|
"max_quota_for_domain" => 10240 * 1048576,
|
||||||
|
"rl_frame" => "s",
|
||||||
|
"rl_value" => "",
|
||||||
|
"active" => 1,
|
||||||
|
"gal" => 1,
|
||||||
|
"backupmx" => 0,
|
||||||
|
"relay_all_recipients" => 0,
|
||||||
|
"relay_unknown_only" => 0,
|
||||||
|
"dkim_selector" => "dkim",
|
||||||
|
"key_size" => 2048,
|
||||||
|
"max_quota_for_domain" => 10240 * 1048576,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$default_mailbox_template = array(
|
||||||
|
"template" => "Default",
|
||||||
|
"type" => "mailbox",
|
||||||
|
"attributes" => array(
|
||||||
|
"tags" => array(),
|
||||||
|
"quota" => 0,
|
||||||
|
"quarantine_notification" => strval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['quarantine_notification']),
|
||||||
|
"quarantine_category" => strval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['quarantine_category']),
|
||||||
|
"rl_frame" => "s",
|
||||||
|
"rl_value" => "",
|
||||||
|
"force_pw_update" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['force_pw_update']),
|
||||||
|
"sogo_access" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['sogo_access']),
|
||||||
|
"active" => 1,
|
||||||
|
"tls_enforce_in" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['tls_enforce_in']),
|
||||||
|
"tls_enforce_out" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['tls_enforce_out']),
|
||||||
|
"imap_access" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['imap_access']),
|
||||||
|
"pop3_access" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['pop3_access']),
|
||||||
|
"smtp_access" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['smtp_access']),
|
||||||
|
"sieve_access" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['sieve_access']),
|
||||||
|
"acl_spam_alias" => 1,
|
||||||
|
"acl_tls_policy" => 1,
|
||||||
|
"acl_spam_score" => 1,
|
||||||
|
"acl_spam_policy" => 1,
|
||||||
|
"acl_delimiter_action" => 1,
|
||||||
|
"acl_syncjobs" => 0,
|
||||||
|
"acl_eas_reset" => 1,
|
||||||
|
"acl_sogo_profile_reset" => 0,
|
||||||
|
"acl_pushover" => 1,
|
||||||
|
"acl_quarantine" => 1,
|
||||||
|
"acl_quarantine_attachments" => 1,
|
||||||
|
"acl_quarantine_notification" => 1,
|
||||||
|
"acl_quarantine_category" => 1,
|
||||||
|
"acl_app_passwds" => 1,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$stmt = $pdo->prepare("SELECT id FROM `templates` WHERE `type` = :type AND `template` = :template");
|
||||||
|
$stmt->execute(array(
|
||||||
|
":type" => "domain",
|
||||||
|
":template" => $default_domain_template["template"]
|
||||||
|
));
|
||||||
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
if (empty($row)){
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO `templates` (`type`, `template`, `attributes`)
|
||||||
|
VALUES (:type, :template, :attributes)");
|
||||||
|
$stmt->execute(array(
|
||||||
|
":type" => "domain",
|
||||||
|
":template" => $default_domain_template["template"],
|
||||||
|
":attributes" => json_encode($default_domain_template["attributes"])
|
||||||
|
));
|
||||||
|
}
|
||||||
|
$stmt = $pdo->prepare("SELECT id FROM `templates` WHERE `type` = :type AND `template` = :template");
|
||||||
|
$stmt->execute(array(
|
||||||
|
":type" => "mailbox",
|
||||||
|
":template" => $default_mailbox_template["template"]
|
||||||
|
));
|
||||||
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
if (empty($row)){
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO `templates` (`type`, `template`, `attributes`)
|
||||||
|
VALUES (:type, :template, :attributes)");
|
||||||
|
$stmt->execute(array(
|
||||||
|
":type" => "mailbox",
|
||||||
|
":template" => $default_mailbox_template["template"],
|
||||||
|
":attributes" => json_encode($default_mailbox_template["attributes"])
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
if (php_sapi_name() == "cli") {
|
if (php_sapi_name() == "cli") {
|
||||||
echo "DB initialization completed" . PHP_EOL;
|
echo "DB initialization completed" . PHP_EOL;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Generated
+8
-8
@@ -1604,16 +1604,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "twig/twig",
|
"name": "twig/twig",
|
||||||
"version": "v3.3.8",
|
"version": "v3.4.3",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/twigphp/Twig.git",
|
"url": "https://github.com/twigphp/Twig.git",
|
||||||
"reference": "972d8604a92b7054828b539f2febb0211dd5945c"
|
"reference": "c38fd6b0b7f370c198db91ffd02e23b517426b58"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/972d8604a92b7054828b539f2febb0211dd5945c",
|
"url": "https://api.github.com/repos/twigphp/Twig/zipball/c38fd6b0b7f370c198db91ffd02e23b517426b58",
|
||||||
"reference": "972d8604a92b7054828b539f2febb0211dd5945c",
|
"reference": "c38fd6b0b7f370c198db91ffd02e23b517426b58",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -1628,7 +1628,7 @@
|
|||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-master": "3.3-dev"
|
"dev-master": "3.4-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@@ -1664,7 +1664,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/twigphp/Twig/issues",
|
"issues": "https://github.com/twigphp/Twig/issues",
|
||||||
"source": "https://github.com/twigphp/Twig/tree/v3.3.8"
|
"source": "https://github.com/twigphp/Twig/tree/v3.4.3"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -1676,7 +1676,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2022-02-04T06:59:48+00:00"
|
"time": "2022-09-28T08:42:51+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "yubico/u2flib-server",
|
"name": "yubico/u2flib-server",
|
||||||
@@ -1728,5 +1728,5 @@
|
|||||||
"prefer-lowest": false,
|
"prefer-lowest": false,
|
||||||
"platform": [],
|
"platform": [],
|
||||||
"platform-dev": [],
|
"platform-dev": [],
|
||||||
"plugin-api-version": "2.2.0"
|
"plugin-api-version": "2.3.0"
|
||||||
}
|
}
|
||||||
Vendored
+5
@@ -2,6 +2,11 @@
|
|||||||
|
|
||||||
// autoload.php @generated by Composer
|
// autoload.php @generated by Composer
|
||||||
|
|
||||||
|
if (PHP_VERSION_ID < 50600) {
|
||||||
|
echo 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
require_once __DIR__ . '/composer/autoload_real.php';
|
require_once __DIR__ . '/composer/autoload_real.php';
|
||||||
|
|
||||||
return ComposerAutoloaderInit873464e4bd965a3168f133248b1b218b::getLoader();
|
return ComposerAutoloaderInit873464e4bd965a3168f133248b1b218b::getLoader();
|
||||||
+9
-7
@@ -21,12 +21,14 @@ use Composer\Semver\VersionParser;
|
|||||||
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
|
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
|
||||||
*
|
*
|
||||||
* To require its presence, you can require `composer-runtime-api ^2.0`
|
* To require its presence, you can require `composer-runtime-api ^2.0`
|
||||||
|
*
|
||||||
|
* @final
|
||||||
*/
|
*/
|
||||||
class InstalledVersions
|
class InstalledVersions
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var mixed[]|null
|
* @var mixed[]|null
|
||||||
* @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}|array{}|null
|
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
|
||||||
*/
|
*/
|
||||||
private static $installed;
|
private static $installed;
|
||||||
|
|
||||||
@@ -37,7 +39,7 @@ class InstalledVersions
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array[]
|
* @var array[]
|
||||||
* @psalm-var array<string, array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
|
* @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||||
*/
|
*/
|
||||||
private static $installedByVendor = array();
|
private static $installedByVendor = array();
|
||||||
|
|
||||||
@@ -241,7 +243,7 @@ class InstalledVersions
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array
|
* @return array
|
||||||
* @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}
|
* @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
|
||||||
*/
|
*/
|
||||||
public static function getRootPackage()
|
public static function getRootPackage()
|
||||||
{
|
{
|
||||||
@@ -255,7 +257,7 @@ class InstalledVersions
|
|||||||
*
|
*
|
||||||
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
|
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
|
||||||
* @return array[]
|
* @return array[]
|
||||||
* @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}
|
* @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
|
||||||
*/
|
*/
|
||||||
public static function getRawData()
|
public static function getRawData()
|
||||||
{
|
{
|
||||||
@@ -278,7 +280,7 @@ class InstalledVersions
|
|||||||
* Returns the raw data of all installed.php which are currently loaded for custom implementations
|
* Returns the raw data of all installed.php which are currently loaded for custom implementations
|
||||||
*
|
*
|
||||||
* @return array[]
|
* @return array[]
|
||||||
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
|
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||||
*/
|
*/
|
||||||
public static function getAllRawData()
|
public static function getAllRawData()
|
||||||
{
|
{
|
||||||
@@ -301,7 +303,7 @@ class InstalledVersions
|
|||||||
* @param array[] $data A vendor/composer/installed.php data set
|
* @param array[] $data A vendor/composer/installed.php data set
|
||||||
* @return void
|
* @return void
|
||||||
*
|
*
|
||||||
* @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} $data
|
* @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
|
||||||
*/
|
*/
|
||||||
public static function reload($data)
|
public static function reload($data)
|
||||||
{
|
{
|
||||||
@@ -311,7 +313,7 @@ class InstalledVersions
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array[]
|
* @return array[]
|
||||||
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
|
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||||
*/
|
*/
|
||||||
private static function getInstalled()
|
private static function getInstalled()
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
// autoload_classmap.php @generated by Composer
|
// autoload_classmap.php @generated by Composer
|
||||||
|
|
||||||
$vendorDir = dirname(dirname(__FILE__));
|
$vendorDir = dirname(__DIR__);
|
||||||
$baseDir = dirname($vendorDir);
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
|
|||||||
+2
-2
@@ -2,15 +2,15 @@
|
|||||||
|
|
||||||
// autoload_files.php @generated by Composer
|
// autoload_files.php @generated by Composer
|
||||||
|
|
||||||
$vendorDir = dirname(dirname(__FILE__));
|
$vendorDir = dirname(__DIR__);
|
||||||
$baseDir = dirname($vendorDir);
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
|
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
|
||||||
'320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
|
|
||||||
'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
|
'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
|
||||||
'a1105708a18b76903365ca1c4aa61b02' => $vendorDir . '/symfony/translation/Resources/functions.php',
|
'a1105708a18b76903365ca1c4aa61b02' => $vendorDir . '/symfony/translation/Resources/functions.php',
|
||||||
'667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php',
|
'667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php',
|
||||||
|
'320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
|
||||||
'fe62ba7e10580d903cc46d808b5961a4' => $vendorDir . '/tightenco/collect/src/Collect/Support/helpers.php',
|
'fe62ba7e10580d903cc46d808b5961a4' => $vendorDir . '/tightenco/collect/src/Collect/Support/helpers.php',
|
||||||
'caf31cc6ec7cf2241cb6f12c226c3846' => $vendorDir . '/tightenco/collect/src/Collect/Support/alias.php',
|
'caf31cc6ec7cf2241cb6f12c226c3846' => $vendorDir . '/tightenco/collect/src/Collect/Support/alias.php',
|
||||||
'04c6c5c2f7095ccf6c481d3e53e1776f' => $vendorDir . '/mustangostang/spyc/Spyc.php',
|
'04c6c5c2f7095ccf6c481d3e53e1776f' => $vendorDir . '/mustangostang/spyc/Spyc.php',
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
// autoload_namespaces.php @generated by Composer
|
// autoload_namespaces.php @generated by Composer
|
||||||
|
|
||||||
$vendorDir = dirname(dirname(__FILE__));
|
$vendorDir = dirname(__DIR__);
|
||||||
$baseDir = dirname($vendorDir);
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
// autoload_psr4.php @generated by Composer
|
// autoload_psr4.php @generated by Composer
|
||||||
|
|
||||||
$vendorDir = dirname(dirname(__FILE__));
|
$vendorDir = dirname(__DIR__);
|
||||||
$baseDir = dirname($vendorDir);
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
|
|||||||
+4
-27
@@ -25,38 +25,15 @@ class ComposerAutoloaderInit873464e4bd965a3168f133248b1b218b
|
|||||||
require __DIR__ . '/platform_check.php';
|
require __DIR__ . '/platform_check.php';
|
||||||
|
|
||||||
spl_autoload_register(array('ComposerAutoloaderInit873464e4bd965a3168f133248b1b218b', 'loadClassLoader'), true, true);
|
spl_autoload_register(array('ComposerAutoloaderInit873464e4bd965a3168f133248b1b218b', 'loadClassLoader'), true, true);
|
||||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
|
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
|
||||||
spl_autoload_unregister(array('ComposerAutoloaderInit873464e4bd965a3168f133248b1b218b', 'loadClassLoader'));
|
spl_autoload_unregister(array('ComposerAutoloaderInit873464e4bd965a3168f133248b1b218b', 'loadClassLoader'));
|
||||||
|
|
||||||
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
require __DIR__ . '/autoload_static.php';
|
||||||
if ($useStaticLoader) {
|
call_user_func(\Composer\Autoload\ComposerStaticInit873464e4bd965a3168f133248b1b218b::getInitializer($loader));
|
||||||
require __DIR__ . '/autoload_static.php';
|
|
||||||
|
|
||||||
call_user_func(\Composer\Autoload\ComposerStaticInit873464e4bd965a3168f133248b1b218b::getInitializer($loader));
|
|
||||||
} else {
|
|
||||||
$map = require __DIR__ . '/autoload_namespaces.php';
|
|
||||||
foreach ($map as $namespace => $path) {
|
|
||||||
$loader->set($namespace, $path);
|
|
||||||
}
|
|
||||||
|
|
||||||
$map = require __DIR__ . '/autoload_psr4.php';
|
|
||||||
foreach ($map as $namespace => $path) {
|
|
||||||
$loader->setPsr4($namespace, $path);
|
|
||||||
}
|
|
||||||
|
|
||||||
$classMap = require __DIR__ . '/autoload_classmap.php';
|
|
||||||
if ($classMap) {
|
|
||||||
$loader->addClassMap($classMap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$loader->register(true);
|
$loader->register(true);
|
||||||
|
|
||||||
if ($useStaticLoader) {
|
$includeFiles = \Composer\Autoload\ComposerStaticInit873464e4bd965a3168f133248b1b218b::$files;
|
||||||
$includeFiles = Composer\Autoload\ComposerStaticInit873464e4bd965a3168f133248b1b218b::$files;
|
|
||||||
} else {
|
|
||||||
$includeFiles = require __DIR__ . '/autoload_files.php';
|
|
||||||
}
|
|
||||||
foreach ($includeFiles as $fileIdentifier => $file) {
|
foreach ($includeFiles as $fileIdentifier => $file) {
|
||||||
composerRequire873464e4bd965a3168f133248b1b218b($fileIdentifier, $file);
|
composerRequire873464e4bd965a3168f133248b1b218b($fileIdentifier, $file);
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -8,10 +8,10 @@ class ComposerStaticInit873464e4bd965a3168f133248b1b218b
|
|||||||
{
|
{
|
||||||
public static $files = array (
|
public static $files = array (
|
||||||
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
|
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
|
||||||
'320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
|
|
||||||
'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
|
'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
|
||||||
'a1105708a18b76903365ca1c4aa61b02' => __DIR__ . '/..' . '/symfony/translation/Resources/functions.php',
|
'a1105708a18b76903365ca1c4aa61b02' => __DIR__ . '/..' . '/symfony/translation/Resources/functions.php',
|
||||||
'667aeda72477189d0494fecd327c3641' => __DIR__ . '/..' . '/symfony/var-dumper/Resources/functions/dump.php',
|
'667aeda72477189d0494fecd327c3641' => __DIR__ . '/..' . '/symfony/var-dumper/Resources/functions/dump.php',
|
||||||
|
'320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
|
||||||
'fe62ba7e10580d903cc46d808b5961a4' => __DIR__ . '/..' . '/tightenco/collect/src/Collect/Support/helpers.php',
|
'fe62ba7e10580d903cc46d808b5961a4' => __DIR__ . '/..' . '/tightenco/collect/src/Collect/Support/helpers.php',
|
||||||
'caf31cc6ec7cf2241cb6f12c226c3846' => __DIR__ . '/..' . '/tightenco/collect/src/Collect/Support/alias.php',
|
'caf31cc6ec7cf2241cb6f12c226c3846' => __DIR__ . '/..' . '/tightenco/collect/src/Collect/Support/alias.php',
|
||||||
'04c6c5c2f7095ccf6c481d3e53e1776f' => __DIR__ . '/..' . '/mustangostang/spyc/Spyc.php',
|
'04c6c5c2f7095ccf6c481d3e53e1776f' => __DIR__ . '/..' . '/mustangostang/spyc/Spyc.php',
|
||||||
|
|||||||
+8
-8
@@ -1654,17 +1654,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "twig/twig",
|
"name": "twig/twig",
|
||||||
"version": "v3.3.8",
|
"version": "v3.4.3",
|
||||||
"version_normalized": "3.3.8.0",
|
"version_normalized": "3.4.3.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/twigphp/Twig.git",
|
"url": "https://github.com/twigphp/Twig.git",
|
||||||
"reference": "972d8604a92b7054828b539f2febb0211dd5945c"
|
"reference": "c38fd6b0b7f370c198db91ffd02e23b517426b58"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/972d8604a92b7054828b539f2febb0211dd5945c",
|
"url": "https://api.github.com/repos/twigphp/Twig/zipball/c38fd6b0b7f370c198db91ffd02e23b517426b58",
|
||||||
"reference": "972d8604a92b7054828b539f2febb0211dd5945c",
|
"reference": "c38fd6b0b7f370c198db91ffd02e23b517426b58",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -1676,11 +1676,11 @@
|
|||||||
"psr/container": "^1.0",
|
"psr/container": "^1.0",
|
||||||
"symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0"
|
"symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0"
|
||||||
},
|
},
|
||||||
"time": "2022-02-04T06:59:48+00:00",
|
"time": "2022-09-28T08:42:51+00:00",
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-master": "3.3-dev"
|
"dev-master": "3.4-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"installation-source": "dist",
|
"installation-source": "dist",
|
||||||
@@ -1717,7 +1717,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/twigphp/Twig/issues",
|
"issues": "https://github.com/twigphp/Twig/issues",
|
||||||
"source": "https://github.com/twigphp/Twig/tree/v3.3.8"
|
"source": "https://github.com/twigphp/Twig/tree/v3.4.3"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
|||||||
+34
-34
@@ -1,49 +1,49 @@
|
|||||||
<?php return array(
|
<?php return array(
|
||||||
'root' => array(
|
'root' => array(
|
||||||
'pretty_version' => '1.0.0+no-version-set',
|
'name' => '__root__',
|
||||||
'version' => '1.0.0.0',
|
'pretty_version' => 'dev-master',
|
||||||
|
'version' => 'dev-master',
|
||||||
|
'reference' => '8e0b1d8aee4af02311692cb031695cc2ac3850fd',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../../',
|
'install_path' => __DIR__ . '/../../',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'reference' => NULL,
|
|
||||||
'name' => '__root__',
|
|
||||||
'dev' => true,
|
'dev' => true,
|
||||||
),
|
),
|
||||||
'versions' => array(
|
'versions' => array(
|
||||||
'__root__' => array(
|
'__root__' => array(
|
||||||
'pretty_version' => '1.0.0+no-version-set',
|
'pretty_version' => 'dev-master',
|
||||||
'version' => '1.0.0.0',
|
'version' => 'dev-master',
|
||||||
|
'reference' => '8e0b1d8aee4af02311692cb031695cc2ac3850fd',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../../',
|
'install_path' => __DIR__ . '/../../',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'reference' => NULL,
|
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'bshaffer/oauth2-server-php' => array(
|
'bshaffer/oauth2-server-php' => array(
|
||||||
'pretty_version' => 'v1.11.1',
|
'pretty_version' => 'v1.11.1',
|
||||||
'version' => '1.11.1.0',
|
'version' => '1.11.1.0',
|
||||||
|
'reference' => '5a0c8000d4763b276919e2106f54eddda6bc50fa',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../bshaffer/oauth2-server-php',
|
'install_path' => __DIR__ . '/../bshaffer/oauth2-server-php',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'reference' => '5a0c8000d4763b276919e2106f54eddda6bc50fa',
|
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'ddeboer/imap' => array(
|
'ddeboer/imap' => array(
|
||||||
'pretty_version' => '1.13.1',
|
'pretty_version' => '1.13.1',
|
||||||
'version' => '1.13.1.0',
|
'version' => '1.13.1.0',
|
||||||
|
'reference' => '8b772d04b1deadb5df13782fb78c4b648f77496e',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../ddeboer/imap',
|
'install_path' => __DIR__ . '/../ddeboer/imap',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'reference' => '8b772d04b1deadb5df13782fb78c4b648f77496e',
|
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'directorytree/ldaprecord' => array(
|
'directorytree/ldaprecord' => array(
|
||||||
'pretty_version' => 'v2.10.1',
|
'pretty_version' => 'v2.10.1',
|
||||||
'version' => '2.10.1.0',
|
'version' => '2.10.1.0',
|
||||||
|
'reference' => 'bf512d9af7a7b0e2ed7a666ab29cefdd027bee88',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../directorytree/ldaprecord',
|
'install_path' => __DIR__ . '/../directorytree/ldaprecord',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'reference' => 'bf512d9af7a7b0e2ed7a666ab29cefdd027bee88',
|
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'exorus/php-mime-mail-parser' => array(
|
'exorus/php-mime-mail-parser' => array(
|
||||||
@@ -55,28 +55,28 @@
|
|||||||
'illuminate/contracts' => array(
|
'illuminate/contracts' => array(
|
||||||
'pretty_version' => 'v9.3.0',
|
'pretty_version' => 'v9.3.0',
|
||||||
'version' => '9.3.0.0',
|
'version' => '9.3.0.0',
|
||||||
|
'reference' => 'bf4b3c254c49d28157645d01e4883b5951b1e1d0',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../illuminate/contracts',
|
'install_path' => __DIR__ . '/../illuminate/contracts',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'reference' => 'bf4b3c254c49d28157645d01e4883b5951b1e1d0',
|
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'matthiasmullie/minify' => array(
|
'matthiasmullie/minify' => array(
|
||||||
'pretty_version' => '1.3.66',
|
'pretty_version' => '1.3.66',
|
||||||
'version' => '1.3.66.0',
|
'version' => '1.3.66.0',
|
||||||
|
'reference' => '45fd3b0f1dfa2c965857c6d4a470bea52adc31a6',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../matthiasmullie/minify',
|
'install_path' => __DIR__ . '/../matthiasmullie/minify',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'reference' => '45fd3b0f1dfa2c965857c6d4a470bea52adc31a6',
|
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'matthiasmullie/path-converter' => array(
|
'matthiasmullie/path-converter' => array(
|
||||||
'pretty_version' => '1.1.3',
|
'pretty_version' => '1.1.3',
|
||||||
'version' => '1.1.3.0',
|
'version' => '1.1.3.0',
|
||||||
|
'reference' => 'e7d13b2c7e2f2268e1424aaed02085518afa02d9',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../matthiasmullie/path-converter',
|
'install_path' => __DIR__ . '/../matthiasmullie/path-converter',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'reference' => 'e7d13b2c7e2f2268e1424aaed02085518afa02d9',
|
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'messaged/php-mime-mail-parser' => array(
|
'messaged/php-mime-mail-parser' => array(
|
||||||
@@ -88,136 +88,136 @@
|
|||||||
'mustangostang/spyc' => array(
|
'mustangostang/spyc' => array(
|
||||||
'pretty_version' => '0.6.3',
|
'pretty_version' => '0.6.3',
|
||||||
'version' => '0.6.3.0',
|
'version' => '0.6.3.0',
|
||||||
|
'reference' => '4627c838b16550b666d15aeae1e5289dd5b77da0',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../mustangostang/spyc',
|
'install_path' => __DIR__ . '/../mustangostang/spyc',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'reference' => '4627c838b16550b666d15aeae1e5289dd5b77da0',
|
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'nesbot/carbon' => array(
|
'nesbot/carbon' => array(
|
||||||
'pretty_version' => '2.57.0',
|
'pretty_version' => '2.57.0',
|
||||||
'version' => '2.57.0.0',
|
'version' => '2.57.0.0',
|
||||||
|
'reference' => '4a54375c21eea4811dbd1149fe6b246517554e78',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../nesbot/carbon',
|
'install_path' => __DIR__ . '/../nesbot/carbon',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'reference' => '4a54375c21eea4811dbd1149fe6b246517554e78',
|
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'paragonie/random_compat' => array(
|
'paragonie/random_compat' => array(
|
||||||
'pretty_version' => 'v9.99.100',
|
'pretty_version' => 'v9.99.100',
|
||||||
'version' => '9.99.100.0',
|
'version' => '9.99.100.0',
|
||||||
|
'reference' => '996434e5492cb4c3edcb9168db6fbb1359ef965a',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../paragonie/random_compat',
|
'install_path' => __DIR__ . '/../paragonie/random_compat',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'reference' => '996434e5492cb4c3edcb9168db6fbb1359ef965a',
|
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'php-mime-mail-parser/php-mime-mail-parser' => array(
|
'php-mime-mail-parser/php-mime-mail-parser' => array(
|
||||||
'pretty_version' => '7.0.0',
|
'pretty_version' => '7.0.0',
|
||||||
'version' => '7.0.0.0',
|
'version' => '7.0.0.0',
|
||||||
|
'reference' => '9d09a017f3f103fec8456211a4a538b80e0eca0d',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../php-mime-mail-parser/php-mime-mail-parser',
|
'install_path' => __DIR__ . '/../php-mime-mail-parser/php-mime-mail-parser',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'reference' => '9d09a017f3f103fec8456211a4a538b80e0eca0d',
|
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'phpmailer/phpmailer' => array(
|
'phpmailer/phpmailer' => array(
|
||||||
'pretty_version' => 'v6.6.0',
|
'pretty_version' => 'v6.6.0',
|
||||||
'version' => '6.6.0.0',
|
'version' => '6.6.0.0',
|
||||||
|
'reference' => 'e43bac82edc26ca04b36143a48bde1c051cfd5b1',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../phpmailer/phpmailer',
|
'install_path' => __DIR__ . '/../phpmailer/phpmailer',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'reference' => 'e43bac82edc26ca04b36143a48bde1c051cfd5b1',
|
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'psr/container' => array(
|
'psr/container' => array(
|
||||||
'pretty_version' => '2.0.2',
|
'pretty_version' => '2.0.2',
|
||||||
'version' => '2.0.2.0',
|
'version' => '2.0.2.0',
|
||||||
|
'reference' => 'c71ecc56dfe541dbd90c5360474fbc405f8d5963',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../psr/container',
|
'install_path' => __DIR__ . '/../psr/container',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'reference' => 'c71ecc56dfe541dbd90c5360474fbc405f8d5963',
|
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'psr/log' => array(
|
'psr/log' => array(
|
||||||
'pretty_version' => '3.0.0',
|
'pretty_version' => '3.0.0',
|
||||||
'version' => '3.0.0.0',
|
'version' => '3.0.0.0',
|
||||||
|
'reference' => 'fe5ea303b0887d5caefd3d431c3e61ad47037001',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../psr/log',
|
'install_path' => __DIR__ . '/../psr/log',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'reference' => 'fe5ea303b0887d5caefd3d431c3e61ad47037001',
|
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'psr/simple-cache' => array(
|
'psr/simple-cache' => array(
|
||||||
'pretty_version' => '2.0.0',
|
'pretty_version' => '2.0.0',
|
||||||
'version' => '2.0.0.0',
|
'version' => '2.0.0.0',
|
||||||
|
'reference' => '8707bf3cea6f710bf6ef05491234e3ab06f6432a',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../psr/simple-cache',
|
'install_path' => __DIR__ . '/../psr/simple-cache',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'reference' => '8707bf3cea6f710bf6ef05491234e3ab06f6432a',
|
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'robthree/twofactorauth' => array(
|
'robthree/twofactorauth' => array(
|
||||||
'pretty_version' => '1.8.1',
|
'pretty_version' => '1.8.1',
|
||||||
'version' => '1.8.1.0',
|
'version' => '1.8.1.0',
|
||||||
|
'reference' => '5afcb45282f1c75562a48d479ecd1732c9bdb11b',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../robthree/twofactorauth',
|
'install_path' => __DIR__ . '/../robthree/twofactorauth',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'reference' => '5afcb45282f1c75562a48d479ecd1732c9bdb11b',
|
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'soundasleep/html2text' => array(
|
'soundasleep/html2text' => array(
|
||||||
'pretty_version' => '0.5.0',
|
'pretty_version' => '0.5.0',
|
||||||
'version' => '0.5.0.0',
|
'version' => '0.5.0.0',
|
||||||
|
'reference' => 'cdb89f6ffa2c4cc78f8ed9ea6ee0594a9133ccad',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../soundasleep/html2text',
|
'install_path' => __DIR__ . '/../soundasleep/html2text',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'reference' => 'cdb89f6ffa2c4cc78f8ed9ea6ee0594a9133ccad',
|
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'symfony/polyfill-ctype' => array(
|
'symfony/polyfill-ctype' => array(
|
||||||
'pretty_version' => 'v1.24.0',
|
'pretty_version' => 'v1.24.0',
|
||||||
'version' => '1.24.0.0',
|
'version' => '1.24.0.0',
|
||||||
|
'reference' => '30885182c981ab175d4d034db0f6f469898070ab',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../symfony/polyfill-ctype',
|
'install_path' => __DIR__ . '/../symfony/polyfill-ctype',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'reference' => '30885182c981ab175d4d034db0f6f469898070ab',
|
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'symfony/polyfill-mbstring' => array(
|
'symfony/polyfill-mbstring' => array(
|
||||||
'pretty_version' => 'v1.24.0',
|
'pretty_version' => 'v1.24.0',
|
||||||
'version' => '1.24.0.0',
|
'version' => '1.24.0.0',
|
||||||
|
'reference' => '0abb51d2f102e00a4eefcf46ba7fec406d245825',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
|
'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'reference' => '0abb51d2f102e00a4eefcf46ba7fec406d245825',
|
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'symfony/polyfill-php80' => array(
|
'symfony/polyfill-php80' => array(
|
||||||
'pretty_version' => 'v1.24.0',
|
'pretty_version' => 'v1.24.0',
|
||||||
'version' => '1.24.0.0',
|
'version' => '1.24.0.0',
|
||||||
|
'reference' => '57b712b08eddb97c762a8caa32c84e037892d2e9',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../symfony/polyfill-php80',
|
'install_path' => __DIR__ . '/../symfony/polyfill-php80',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'reference' => '57b712b08eddb97c762a8caa32c84e037892d2e9',
|
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'symfony/translation' => array(
|
'symfony/translation' => array(
|
||||||
'pretty_version' => 'v6.0.5',
|
'pretty_version' => 'v6.0.5',
|
||||||
'version' => '6.0.5.0',
|
'version' => '6.0.5.0',
|
||||||
|
'reference' => 'e69501c71107cc3146b32aaa45f4edd0c3427875',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../symfony/translation',
|
'install_path' => __DIR__ . '/../symfony/translation',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'reference' => 'e69501c71107cc3146b32aaa45f4edd0c3427875',
|
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'symfony/translation-contracts' => array(
|
'symfony/translation-contracts' => array(
|
||||||
'pretty_version' => 'v3.0.0',
|
'pretty_version' => 'v3.0.0',
|
||||||
'version' => '3.0.0.0',
|
'version' => '3.0.0.0',
|
||||||
|
'reference' => '1b6ea5a7442af5a12dba3dbd6d71034b5b234e77',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../symfony/translation-contracts',
|
'install_path' => __DIR__ . '/../symfony/translation-contracts',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'reference' => '1b6ea5a7442af5a12dba3dbd6d71034b5b234e77',
|
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'symfony/translation-implementation' => array(
|
'symfony/translation-implementation' => array(
|
||||||
@@ -229,37 +229,37 @@
|
|||||||
'symfony/var-dumper' => array(
|
'symfony/var-dumper' => array(
|
||||||
'pretty_version' => 'v6.0.5',
|
'pretty_version' => 'v6.0.5',
|
||||||
'version' => '6.0.5.0',
|
'version' => '6.0.5.0',
|
||||||
|
'reference' => '60d6a756d5f485df5e6e40b337334848f79f61ce',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../symfony/var-dumper',
|
'install_path' => __DIR__ . '/../symfony/var-dumper',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'reference' => '60d6a756d5f485df5e6e40b337334848f79f61ce',
|
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'tightenco/collect' => array(
|
'tightenco/collect' => array(
|
||||||
'pretty_version' => 'v8.83.2',
|
'pretty_version' => 'v8.83.2',
|
||||||
'version' => '8.83.2.0',
|
'version' => '8.83.2.0',
|
||||||
|
'reference' => 'd9c66d586ec2d216d8a31283d73f8df1400cc722',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../tightenco/collect',
|
'install_path' => __DIR__ . '/../tightenco/collect',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'reference' => 'd9c66d586ec2d216d8a31283d73f8df1400cc722',
|
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'twig/twig' => array(
|
'twig/twig' => array(
|
||||||
'pretty_version' => 'v3.3.8',
|
'pretty_version' => 'v3.4.3',
|
||||||
'version' => '3.3.8.0',
|
'version' => '3.4.3.0',
|
||||||
|
'reference' => 'c38fd6b0b7f370c198db91ffd02e23b517426b58',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../twig/twig',
|
'install_path' => __DIR__ . '/../twig/twig',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'reference' => '972d8604a92b7054828b539f2febb0211dd5945c',
|
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'yubico/u2flib-server' => array(
|
'yubico/u2flib-server' => array(
|
||||||
'pretty_version' => '1.0.2',
|
'pretty_version' => '1.0.2',
|
||||||
'version' => '1.0.2.0',
|
'version' => '1.0.2.0',
|
||||||
|
'reference' => '55d813acf68212ad2cadecde07551600d6971939',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../yubico/u2flib-server',
|
'install_path' => __DIR__ . '/../yubico/u2flib-server',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'reference' => '55d813acf68212ad2cadecde07551600d6971939',
|
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/doc/** export-ignore
|
/doc/ export-ignore
|
||||||
/extra/** export-ignore
|
/extra/ export-ignore
|
||||||
/tests export-ignore
|
/tests/ export-ignore
|
||||||
/phpunit.xml.dist export-ignore
|
/phpunit.xml.dist export-ignore
|
||||||
+11
-37
@@ -9,6 +9,9 @@ on:
|
|||||||
env:
|
env:
|
||||||
SYMFONY_PHPUNIT_DISABLE_RESULT_CACHE: 1
|
SYMFONY_PHPUNIT_DISABLE_RESULT_CACHE: 1
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
tests:
|
tests:
|
||||||
name: "PHP ${{ matrix.php-version }}"
|
name: "PHP ${{ matrix.php-version }}"
|
||||||
@@ -25,36 +28,23 @@ jobs:
|
|||||||
- '7.4'
|
- '7.4'
|
||||||
- '8.0'
|
- '8.0'
|
||||||
- '8.1'
|
- '8.1'
|
||||||
composer-options: ['']
|
|
||||||
experimental: [false]
|
experimental: [false]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: "Checkout code"
|
- name: "Checkout code"
|
||||||
uses: actions/checkout@v2.3.3
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: "Install PHP with extensions"
|
- name: "Install PHP with extensions"
|
||||||
uses: shivammathur/setup-php@2.7.0
|
uses: shivammathur/setup-php@v2
|
||||||
with:
|
with:
|
||||||
coverage: "none"
|
coverage: "none"
|
||||||
php-version: ${{ matrix.php-version }}
|
php-version: ${{ matrix.php-version }}
|
||||||
ini-values: memory_limit=-1
|
ini-values: memory_limit=-1
|
||||||
tools: composer:v2
|
|
||||||
|
|
||||||
- name: "Add PHPUnit matcher"
|
- name: "Add PHPUnit matcher"
|
||||||
run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
|
run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
|
||||||
|
|
||||||
- name: "Set composer cache directory"
|
- run: composer install
|
||||||
id: composer-cache
|
|
||||||
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
|
|
||||||
|
|
||||||
- name: "Cache composer"
|
|
||||||
uses: actions/cache@v2.1.2
|
|
||||||
with:
|
|
||||||
path: ${{ steps.composer-cache.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-${{ matrix.php-version }}-composer-${{ hashFiles('composer.json') }}
|
|
||||||
restore-keys: ${{ runner.os }}-${{ matrix.php-version }}-composer-
|
|
||||||
|
|
||||||
- run: composer install ${{ matrix.composer-options }}
|
|
||||||
|
|
||||||
- name: "Install PHPUnit"
|
- name: "Install PHPUnit"
|
||||||
run: vendor/bin/simple-phpunit install
|
run: vendor/bin/simple-phpunit install
|
||||||
@@ -92,35 +82,22 @@ jobs:
|
|||||||
- 'extra/markdown-extra'
|
- 'extra/markdown-extra'
|
||||||
- 'extra/string-extra'
|
- 'extra/string-extra'
|
||||||
- 'extra/twig-extra-bundle'
|
- 'extra/twig-extra-bundle'
|
||||||
composer-options: ['']
|
|
||||||
experimental: [false]
|
experimental: [false]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: "Checkout code"
|
- name: "Checkout code"
|
||||||
uses: actions/checkout@v2.3.3
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: "Install PHP with extensions"
|
- name: "Install PHP with extensions"
|
||||||
uses: shivammathur/setup-php@2.7.0
|
uses: shivammathur/setup-php@v2
|
||||||
with:
|
with:
|
||||||
coverage: "none"
|
coverage: "none"
|
||||||
php-version: ${{ matrix.php-version }}
|
php-version: ${{ matrix.php-version }}
|
||||||
ini-values: memory_limit=-1
|
ini-values: memory_limit=-1
|
||||||
tools: composer:v2
|
|
||||||
|
|
||||||
- name: "Add PHPUnit matcher"
|
- name: "Add PHPUnit matcher"
|
||||||
run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
|
run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
|
||||||
|
|
||||||
- name: "Set composer cache directory"
|
|
||||||
id: composer-cache
|
|
||||||
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
|
|
||||||
|
|
||||||
- name: "Cache composer"
|
|
||||||
uses: actions/cache@v2.1.2
|
|
||||||
with:
|
|
||||||
path: ${{ steps.composer-cache.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-${{ matrix.php-version }}-${{ matrix.extension }}-${{ hashFiles('composer.json') }}
|
|
||||||
restore-keys: ${{ runner.os }}-${{ matrix.php-version }}-${{ matrix.extension }}-
|
|
||||||
|
|
||||||
- run: composer install
|
- run: composer install
|
||||||
|
|
||||||
- name: "Install PHPUnit"
|
- name: "Install PHPUnit"
|
||||||
@@ -129,10 +106,6 @@ jobs:
|
|||||||
- name: "PHPUnit version"
|
- name: "PHPUnit version"
|
||||||
run: vendor/bin/simple-phpunit --version
|
run: vendor/bin/simple-phpunit --version
|
||||||
|
|
||||||
- if: matrix.extension == 'extra/markdown-extra' && matrix.php-version == '8.0'
|
|
||||||
working-directory: ${{ matrix.extension}}
|
|
||||||
run: composer config platform.php 7.4.99
|
|
||||||
|
|
||||||
- name: "Composer install"
|
- name: "Composer install"
|
||||||
working-directory: ${{ matrix.extension}}
|
working-directory: ${{ matrix.extension}}
|
||||||
run: composer install
|
run: composer install
|
||||||
@@ -140,6 +113,7 @@ jobs:
|
|||||||
- name: "Run tests"
|
- name: "Run tests"
|
||||||
working-directory: ${{ matrix.extension}}
|
working-directory: ${{ matrix.extension}}
|
||||||
run: ../../vendor/bin/simple-phpunit
|
run: ../../vendor/bin/simple-phpunit
|
||||||
|
|
||||||
#
|
#
|
||||||
# Drupal does not support Twig 3 now!
|
# Drupal does not support Twig 3 now!
|
||||||
#
|
#
|
||||||
@@ -160,10 +134,10 @@ jobs:
|
|||||||
#
|
#
|
||||||
# steps:
|
# steps:
|
||||||
# - name: "Checkout code"
|
# - name: "Checkout code"
|
||||||
# uses: actions/checkout@v2.3.3
|
# uses: actions/checkout@v2
|
||||||
#
|
#
|
||||||
# - name: "Install PHP with extensions"
|
# - name: "Install PHP with extensions"
|
||||||
# uses: shivammathur/setup-php@2.7.0
|
# uses: shivammathur/setup-php@2
|
||||||
# with:
|
# with:
|
||||||
# coverage: "none"
|
# coverage: "none"
|
||||||
# extensions: "gd, pdo_sqlite"
|
# extensions: "gd, pdo_sqlite"
|
||||||
|
|||||||
Loaded 100 of 260 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user